Add complete_namespace to Module::eval_ast_as_new.

This commit is contained in:
Stephen Chung
2020-09-25 18:07:39 +08:00
parent 93f53fa417
commit 599fe846cb
7 changed files with 191 additions and 102 deletions

View File

@@ -3,7 +3,7 @@
use crate::any::{Dynamic, Variant};
use crate::calc_fn_hash;
use crate::engine::Engine;
use crate::fn_native::{CallableFunction as Func, FnCallArgs, IteratorFn, SendSync};
use crate::fn_native::{CallableFunction, FnCallArgs, IteratorFn, SendSync};
use crate::fn_register::by_value as cast_arg;
use crate::parser::{FnAccess, FnAccess::Public};
use crate::result::EvalAltResult;
@@ -41,6 +41,14 @@ use crate::stdlib::{
/// Return type of module-level Rust function.
pub type FuncReturn<T> = Result<T, Box<EvalAltResult>>;
pub type FuncInfo = (
String,
FnAccess,
usize,
Option<StaticVec<TypeId>>,
CallableFunction,
);
/// An imported module, which may contain variables, sub-modules,
/// external Rust functions, and script-defined functions.
///
@@ -57,18 +65,14 @@ pub struct Module {
all_variables: HashMap<u64, Dynamic, StraightHasherBuilder>,
/// External Rust functions.
functions: HashMap<
u64,
(String, FnAccess, usize, Option<StaticVec<TypeId>>, Func),
StraightHasherBuilder,
>,
functions: HashMap<u64, FuncInfo, StraightHasherBuilder>,
/// Iterator functions, keyed by the type producing the iterator.
type_iterators: HashMap<TypeId, IteratorFn>,
/// Flattened collection of all external Rust functions, native or scripted,
/// including those in sub-modules.
all_functions: HashMap<u64, Func, StraightHasherBuilder>,
all_functions: HashMap<u64, CallableFunction, StraightHasherBuilder>,
/// Is the module indexed?
indexed: bool,
@@ -381,7 +385,7 @@ impl Module {
name: impl Into<String>,
access: FnAccess,
arg_types: &[TypeId],
func: Func,
func: CallableFunction,
) -> u64 {
let name = name.into();
@@ -481,7 +485,12 @@ impl Module {
let f = move |engine: &Engine, lib: &Module, args: &mut FnCallArgs| {
func(engine, lib, args).map(Dynamic::from)
};
self.set_fn(name, Public, arg_types, Func::from_method(Box::new(f)))
self.set_fn(
name,
Public,
arg_types,
CallableFunction::from_method(Box::new(f)),
)
}
/// Set a raw function but with a signature that is a scripted function (meaning that the types
@@ -507,7 +516,7 @@ impl Module {
FnAccess::Public,
num_args,
None,
Func::from_pure(Box::new(f)),
CallableFunction::from_pure(Box::new(f)),
),
);
self.indexed = false;
@@ -534,7 +543,12 @@ impl Module {
) -> u64 {
let f = move |_: &Engine, _: &Module, _: &mut FnCallArgs| func().map(Dynamic::from);
let arg_types = [];
self.set_fn(name, Public, &arg_types, Func::from_pure(Box::new(f)))
self.set_fn(
name,
Public,
&arg_types,
CallableFunction::from_pure(Box::new(f)),
)
}
/// Set a Rust function taking one parameter into the module, returning a hash key.
@@ -559,7 +573,12 @@ impl Module {
func(cast_arg::<A>(&mut args[0])).map(Dynamic::from)
};
let arg_types = [TypeId::of::<A>()];
self.set_fn(name, Public, &arg_types, Func::from_pure(Box::new(f)))
self.set_fn(
name,
Public,
&arg_types,
CallableFunction::from_pure(Box::new(f)),
)
}
/// Set a Rust function taking one mutable parameter into the module, returning a hash key.
@@ -584,7 +603,12 @@ impl Module {
func(&mut args[0].write_lock::<A>().unwrap()).map(Dynamic::from)
};
let arg_types = [TypeId::of::<A>()];
self.set_fn(name, Public, &arg_types, Func::from_method(Box::new(f)))
self.set_fn(
name,
Public,
&arg_types,
CallableFunction::from_method(Box::new(f)),
)
}
/// Set a Rust getter function taking one mutable parameter, returning a hash key.
@@ -636,7 +660,12 @@ impl Module {
func(a, b).map(Dynamic::from)
};
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>()];
self.set_fn(name, Public, &arg_types, Func::from_pure(Box::new(f)))
self.set_fn(
name,
Public,
&arg_types,
CallableFunction::from_pure(Box::new(f)),
)
}
/// Set a Rust function taking two parameters (the first one mutable) into the module,
@@ -667,7 +696,12 @@ impl Module {
func(a, b).map(Dynamic::from)
};
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>()];
self.set_fn(name, Public, &arg_types, Func::from_method(Box::new(f)))
self.set_fn(
name,
Public,
&arg_types,
CallableFunction::from_method(Box::new(f)),
)
}
/// Set a Rust setter function taking two parameters (the first one mutable) into the module,
@@ -772,7 +806,12 @@ impl Module {
func(a, b, c).map(Dynamic::from)
};
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
self.set_fn(name, Public, &arg_types, Func::from_pure(Box::new(f)))
self.set_fn(
name,
Public,
&arg_types,
CallableFunction::from_pure(Box::new(f)),
)
}
/// Set a Rust function taking three parameters (the first one mutable) into the module,
@@ -809,7 +848,12 @@ impl Module {
func(a, b, c).map(Dynamic::from)
};
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
self.set_fn(name, Public, &arg_types, Func::from_method(Box::new(f)))
self.set_fn(
name,
Public,
&arg_types,
CallableFunction::from_method(Box::new(f)),
)
}
/// Set a Rust index setter taking three parameters (the first one mutable) into the module,
@@ -865,7 +909,7 @@ impl Module {
FN_IDX_SET,
Public,
&arg_types,
Func::from_method(Box::new(f)),
CallableFunction::from_method(Box::new(f)),
)
}
@@ -949,7 +993,12 @@ impl Module {
TypeId::of::<C>(),
TypeId::of::<D>(),
];
self.set_fn(name, Public, &arg_types, Func::from_pure(Box::new(f)))
self.set_fn(
name,
Public,
&arg_types,
CallableFunction::from_pure(Box::new(f)),
)
}
/// Set a Rust function taking four parameters (the first one mutable) into the module,
@@ -993,14 +1042,19 @@ impl Module {
TypeId::of::<C>(),
TypeId::of::<D>(),
];
self.set_fn(name, Public, &arg_types, Func::from_method(Box::new(f)))
self.set_fn(
name,
Public,
&arg_types,
CallableFunction::from_method(Box::new(f)),
)
}
/// Get a Rust function.
///
/// The `u64` hash is calculated by the function `crate::calc_fn_hash`.
/// It is also returned by the `set_fn_XXX` calls.
pub(crate) fn get_fn(&self, hash_fn: u64, public_only: bool) -> Option<&Func> {
pub(crate) fn get_fn(&self, hash_fn: u64, public_only: bool) -> Option<&CallableFunction> {
if hash_fn == 0 {
None
} else {
@@ -1019,7 +1073,7 @@ impl Module {
///
/// The `u64` hash is calculated by the function `crate::calc_fn_hash` and must match
/// the hash calculated by `index_all_sub_modules`.
pub(crate) fn get_qualified_fn(&self, hash_qualified_fn: u64) -> Option<&Func> {
pub(crate) fn get_qualified_fn(&self, hash_qualified_fn: u64) -> Option<&CallableFunction> {
self.all_functions.get(&hash_qualified_fn)
}
@@ -1084,7 +1138,9 @@ impl Module {
.iter()
.filter(|(_, (_, _, _, _, v))| match v {
#[cfg(not(feature = "no_function"))]
Func::Script(ref f) => _filter(f.access, f.name.as_str(), f.params.len()),
CallableFunction::Script(f) => {
_filter(f.access, f.name.as_str(), f.params.len())
}
_ => true,
})
.map(|(&k, v)| (k, v.clone())),
@@ -1106,7 +1162,7 @@ impl Module {
mut filter: impl FnMut(FnAccess, &str, usize) -> bool,
) -> &mut Self {
self.functions.retain(|_, (_, _, _, _, v)| match v {
Func::Script(ref f) => filter(f.access, f.name.as_str(), f.params.len()),
CallableFunction::Script(f) => filter(f.access, f.name.as_str(), f.params.len()),
_ => true,
});
@@ -1135,9 +1191,7 @@ impl Module {
}
/// Get an iterator to the functions in the module.
pub(crate) fn iter_fn(
&self,
) -> impl Iterator<Item = &(String, FnAccess, usize, Option<StaticVec<TypeId>>, Func)> {
pub(crate) fn iter_fn(&self) -> impl Iterator<Item = &FuncInfo> {
self.functions.values()
}
@@ -1156,13 +1210,21 @@ impl Module {
self.functions
.iter()
.for_each(|(_, (_, _, _, _, v))| match v {
Func::Script(ref f) => action(f.access, f.name.as_str(), f.params.len()),
CallableFunction::Script(f) => action(f.access, f.name.as_str(), f.params.len()),
_ => (),
});
}
/// Create a new `Module` by evaluating an `AST`.
///
/// ### `private_namespace` parameter
///
/// If `true`, the entire `AST` is encapsulated into each function as a private namespace,
/// allowing functions to cross-call each other.
///
/// If `false`, each function is registered independently and cannot cross-call
/// each other. Functions are searched in the global namespace.
///
/// # Examples
///
/// ```
@@ -1171,14 +1233,19 @@ impl Module {
///
/// let engine = Engine::new();
/// let ast = engine.compile("let answer = 42; export answer;")?;
/// let module = Module::eval_ast_as_new(Scope::new(), &ast, &engine)?;
/// let module = Module::eval_ast_as_new(Scope::new(), &ast, &engine, true)?;
/// assert!(module.contains_var("answer"));
/// assert_eq!(module.get_var_value::<i64>("answer").unwrap(), 42);
/// # Ok(())
/// # }
/// ```
#[cfg(not(feature = "no_module"))]
pub fn eval_ast_as_new(mut scope: Scope, ast: &AST, engine: &Engine) -> FuncReturn<Self> {
pub fn eval_ast_as_new(
mut scope: Scope,
ast: &AST,
private_namespace: bool,
engine: &Engine,
) -> FuncReturn<Self> {
let mut mods = Imports::new();
// Run the script
@@ -1201,7 +1268,32 @@ impl Module {
module.modules.insert(alias.to_string(), m);
});
module.merge(ast.lib());
#[cfg(not(feature = "no_function"))]
if private_namespace {
ast.iter_functions(|access, name, num_args| match access {
FnAccess::Private => (),
FnAccess::Public => {
let fn_name = name.to_string();
let ast_lib = ast.lib().clone();
module.set_raw_fn_as_scripted(
name,
num_args,
move |engine: &Engine, _, args: &mut [&mut Dynamic]| {
engine.call_fn_dynamic_raw(
&mut Scope::new(),
&ast_lib,
&fn_name,
&mut None,
args,
)
},
);
}
});
} else {
module.merge(ast.lib());
}
Ok(module)
}
@@ -1215,7 +1307,7 @@ impl Module {
module: &'a Module,
qualifiers: &mut Vec<&'a str>,
variables: &mut Vec<(u64, Dynamic)>,
functions: &mut Vec<(u64, Func)>,
functions: &mut Vec<(u64, CallableFunction)>,
) {
for (name, m) in &module.modules {
// Index all the sub-modules first.

View File

@@ -1,17 +1,10 @@
use crate::any::Dynamic;
use crate::engine::Engine;
use crate::module::{Module, ModuleResolver};
use crate::parser::{FnAccess, AST};
use crate::parser::AST;
use crate::result::EvalAltResult;
use crate::scope::Scope;
use crate::token::Position;
use crate::stdlib::{
boxed::Box,
collections::HashMap,
path::PathBuf,
string::{String, ToString},
};
use crate::stdlib::{boxed::Box, collections::HashMap, path::PathBuf, string::String};
#[cfg(not(feature = "sync"))]
use crate::stdlib::cell::RefCell;
@@ -149,61 +142,42 @@ impl ModuleResolver for FileModuleResolver {
file_path.push(path);
file_path.set_extension(&self.extension); // Force extension
let scope = Default::default();
let module;
// See if it is cached
let exists = {
let ast = {
#[cfg(not(feature = "sync"))]
let c = self.cache.borrow();
#[cfg(feature = "sync")]
let c = self.cache.read().unwrap();
c.contains_key(&file_path)
if let Some(ast) = c.get(&file_path) {
module = Module::eval_ast_as_new(scope, ast, true, engine).map_err(|err| {
Box::new(EvalAltResult::ErrorInModule(path.to_string(), err, pos))
})?;
None
} else {
// Load the file and compile it if not found
let ast = engine.compile_file(file_path.clone()).map_err(|err| {
Box::new(EvalAltResult::ErrorInModule(path.to_string(), err, pos))
})?;
module = Module::eval_ast_as_new(scope, &ast, true, engine).map_err(|err| {
Box::new(EvalAltResult::ErrorInModule(path.to_string(), err, pos))
})?;
Some(ast)
}
};
if !exists {
// Load the file and compile it if not found
let ast = engine
.compile_file(file_path.clone())
.map_err(|err| err.new_position(pos))?;
if let Some(ast) = ast {
// Put it into the cache
#[cfg(not(feature = "sync"))]
self.cache.borrow_mut().insert(file_path.clone(), ast);
self.cache.borrow_mut().insert(file_path, ast);
#[cfg(feature = "sync")]
self.cache.write().unwrap().insert(file_path.clone(), ast);
self.cache.write().unwrap().insert(file_path, ast);
}
#[cfg(not(feature = "sync"))]
let c = self.cache.borrow();
#[cfg(feature = "sync")]
let c = self.cache.read().unwrap();
let ast = c.get(&file_path).unwrap();
let mut _module = Module::eval_ast_as_new(Scope::new(), ast, engine)?;
#[cfg(not(feature = "no_function"))]
ast.iter_functions(|access, name, num_args| match access {
FnAccess::Private => (),
FnAccess::Public => {
let fn_name = name.to_string();
let ast_lib = ast.lib().clone();
_module.set_raw_fn_as_scripted(
name,
num_args,
move |engine: &Engine, _, args: &mut [&mut Dynamic]| {
engine.call_fn_dynamic_raw(
&mut Scope::new(),
&ast_lib,
&fn_name,
&mut None,
args,
)
},
);
}
});
Ok(_module)
Ok(module)
}
}

View File

@@ -148,31 +148,30 @@ impl ModuleResolver for GlobalFileModuleResolver {
file_path.set_extension(&self.extension); // Force extension
let scope = Default::default();
let module;
// See if it is cached
let (module, ast) = {
let ast = {
#[cfg(not(feature = "sync"))]
let c = self.cache.borrow();
#[cfg(feature = "sync")]
let c = self.cache.read().unwrap();
if let Some(ast) = c.get(&file_path) {
(
Module::eval_ast_as_new(scope, ast, engine)
.map_err(|err| err.new_position(pos))?,
None,
)
module = Module::eval_ast_as_new(scope, ast, false, engine).map_err(|err| {
Box::new(EvalAltResult::ErrorInModule(path.to_string(), err, pos))
})?;
None
} else {
// Load the file and compile it if not found
let ast = engine
.compile_file(file_path.clone())
.map_err(|err| err.new_position(pos))?;
let ast = engine.compile_file(file_path.clone()).map_err(|err| {
Box::new(EvalAltResult::ErrorInModule(path.to_string(), err, pos))
})?;
(
Module::eval_ast_as_new(scope, &ast, engine)
.map_err(|err| err.new_position(pos))?,
Some(ast),
)
module = Module::eval_ast_as_new(scope, &ast, false, engine).map_err(|err| {
Box::new(EvalAltResult::ErrorInModule(path.to_string(), err, pos))
})?;
Some(ast)
}
};