Make module_resolver optional and remove NullModuleResolver.

This commit is contained in:
Stephen Chung 2020-05-06 16:09:44 +08:00
parent c9571d375a
commit 88fec57394
8 changed files with 200 additions and 207 deletions

View File

@ -20,7 +20,7 @@ categories = [ "no-std", "embedded", "parser-implementations" ]
num-traits = { version = "0.2.11", default-features = false }
[features]
#default = ["no_stdlib", "no_function", "no_index", "no_object", "no_float", "only_i32", "unchecked", "no_optimize", "sync"]
#default = ["no_stdlib", "no_function", "no_index", "no_object", "no_module", "no_float", "only_i32", "unchecked", "no_optimize", "sync"]
default = []
unchecked = [] # unchecked arithmetic
no_index = [] # no arrays and indexing

View File

@ -2118,13 +2118,16 @@ Built-in module resolvers are grouped under the `rhai::module_resolvers` module
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `FileModuleResolver` | The default module resolution service, not available under the [`no_std`] feature. Loads a script file (based off the current directory) with `.rhai` extension.<br/>The base directory can be changed via the `FileModuleResolver::new_with_path()` constructor function. |
| `StaticModuleResolver` | Loads modules that are statically added. This can be used when the [`no_std`] feature is turned on. |
| `NullModuleResolver` | The default module resolution service under the [`no_std`] feature. Always returns an `EvalAltResult::ErrorModuleNotFound` error. |
An [`Engine`]'s module resolver is set via a call to `set_module_resolver`:
```rust
// Use the 'NullModuleResolver'
engine.set_module_resolver(rhai::module_resolvers::NullModuleResolver::new());
// Use the 'StaticModuleResolver'
let resolver = rhai::module_resolvers::StaticModuleResolver::new();
engine.set_module_resolver(Some(resolver));
// Effectively disable 'import' statements by setting module resolver to 'None'
engine.set_module_resolver(None);
```
Script optimization

View File

@ -1,4 +1,4 @@
use rhai::{Dynamic, Engine, EvalAltResult, Map, Scope, AST, INT};
use rhai::{Dynamic, Engine, EvalAltResult, Scope, AST, INT};
#[cfg(not(feature = "no_optimize"))]
use rhai::OptimizationLevel;
@ -163,6 +163,7 @@ fn main() {
}
// Throw away all the statements, leaving only the functions
#[cfg(not(feature = "no_function"))]
main_ast.retain_functions();
}
}

View File

@ -262,7 +262,7 @@ pub struct Engine {
pub(crate) type_iterators: HashMap<TypeId, Box<IteratorFn>>,
/// A module resolution service.
pub(crate) module_resolver: Box<dyn ModuleResolver>,
pub(crate) module_resolver: Option<Box<dyn ModuleResolver>>,
/// A hashmap mapping type names to pretty-print names.
pub(crate) type_names: HashMap<String, String>,
@ -300,9 +300,9 @@ impl Default for Engine {
#[cfg(not(feature = "no_module"))]
#[cfg(not(feature = "no_std"))]
module_resolver: Box::new(resolvers::FileModuleResolver::new()),
module_resolver: Some(Box::new(resolvers::FileModuleResolver::new())),
#[cfg(any(feature = "no_std", feature = "no_module"))]
module_resolver: Box::new(resolvers::NullModuleResolver::new()),
module_resolver: None,
type_names: Default::default(),
@ -438,13 +438,7 @@ impl Engine {
packages: Default::default(),
functions: HashMap::with_capacity(FUNCTIONS_COUNT / 2),
type_iterators: Default::default(),
#[cfg(not(feature = "no_module"))]
#[cfg(not(feature = "no_std"))]
module_resolver: Box::new(resolvers::FileModuleResolver::new()),
#[cfg(any(feature = "no_std", feature = "no_module"))]
module_resolver: Box::new(resolvers::NullModuleResolver::new()),
module_resolver: None,
type_names: Default::default(),
print: Box::new(|_| {}),
debug: Box::new(|_| {}),
@ -491,8 +485,8 @@ impl Engine {
///
/// Not available under the `no_module` feature.
#[cfg(not(feature = "no_module"))]
pub fn set_module_resolver(&mut self, resolver: impl ModuleResolver + 'static) {
self.module_resolver = Box::new(resolver);
pub fn set_module_resolver(&mut self, resolver: Option<impl ModuleResolver + 'static>) {
self.module_resolver = resolver.map(|f| Box::new(f) as Box<dyn ModuleResolver>);
}
/// Universal method for calling functions either registered with the `Engine` or written in Rhai.
@ -1264,8 +1258,7 @@ impl Engine {
let hash = calc_fn_hash(fn_name, args.iter().map(|a| a.type_id()));
match module.get_qualified_fn(fn_name, hash, modules, *pos) {
Ok(func) => func(&mut args, *pos)
.map_err(|err| EvalAltResult::set_position(err, *pos)),
Ok(func) => func(&mut args, *pos),
Err(_) if def_val.is_some() => Ok(def_val.as_deref().unwrap().clone()),
Err(err) => Err(err),
}
@ -1530,15 +1523,19 @@ impl Engine {
.eval_expr(scope, state, fn_lib, expr, level)?
.try_cast::<String>()
{
let module = self
.module_resolver
.resolve(self, &path)
.map_err(|err| EvalAltResult::set_position(err, expr.position()))?;
if let Some(resolver) = self.module_resolver.as_ref() {
let module = resolver.resolve(self, &path, expr.position())?;
// TODO - avoid copying module name in inner block?
let mod_name = name.as_ref().clone();
scope.push_module(mod_name, module);
Ok(Default::default())
// TODO - avoid copying module name in inner block?
let mod_name = name.as_ref().clone();
scope.push_module(mod_name, module);
Ok(Default::default())
} else {
Err(Box::new(EvalAltResult::ErrorModuleNotFound(
path,
expr.position(),
)))
}
} else {
Err(Box::new(EvalAltResult::ErrorImportExpr(expr.position())))
}

View File

@ -5,21 +5,35 @@ use crate::calc_fn_hash;
use crate::engine::{Engine, FnAny, FnCallArgs, FunctionsLib};
use crate::parser::FnDef;
use crate::result::EvalAltResult;
use crate::scope::{EntryType as ScopeEntryType, Scope};
use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope};
use crate::token::Position;
use crate::token::Token;
use crate::utils::StaticVec;
use crate::stdlib::{
any::TypeId, collections::HashMap, fmt, iter::empty, mem, rc::Rc, string::String, sync::Arc,
any::TypeId,
collections::HashMap,
fmt, mem,
ops::{Deref, DerefMut},
rc::Rc,
string::String,
sync::Arc,
};
/// A trait that encapsulates a module resolution service.
pub trait ModuleResolver {
/// Resolve a module based on a path string.
fn resolve(&self, engine: &Engine, path: &str) -> Result<Module, Box<EvalAltResult>>;
fn resolve(
&self,
engine: &Engine,
path: &str,
pos: Position,
) -> Result<Module, Box<EvalAltResult>>;
}
/// Return type of module-level Rust function.
type FuncReturn<T> = Result<T, Box<EvalAltResult>>;
/// An imported module, which may contain variables, sub-modules,
/// external Rust functions, and script-defined functions.
///
@ -158,7 +172,6 @@ impl Module {
#[cfg(not(feature = "sync"))]
self.functions.insert(hash, Rc::new(func));
#[cfg(feature = "sync")]
self.functions.insert(hash, Arc::new(func));
@ -171,14 +184,16 @@ impl Module {
pub fn set_fn_0<T: Into<Dynamic>>(
&mut self,
fn_name: &str,
#[cfg(not(feature = "sync"))] func: impl Fn() -> Result<T, Box<EvalAltResult>> + 'static,
#[cfg(feature = "sync")] func: impl Fn() -> Result<T, Box<EvalAltResult>>
+ Send
+ Sync
+ 'static,
#[cfg(not(feature = "sync"))] func: impl Fn() -> FuncReturn<T> + 'static,
#[cfg(feature = "sync")] func: impl Fn() -> FuncReturn<T> + Send + Sync + 'static,
) -> u64 {
let f = move |_: &mut FnCallArgs, _: Position| func().map(|v| v.into());
self.set_fn(fn_name, &[], Box::new(f))
let f = move |_: &mut FnCallArgs, pos| {
func()
.map(|v| v.into())
.map_err(|err| EvalAltResult::set_position(err, pos))
};
let arg_types = &[];
self.set_fn(fn_name, arg_types, Box::new(f))
}
/// Set a Rust function taking one parameter into the module, returning a hash key.
@ -187,16 +202,16 @@ impl Module {
pub fn set_fn_1<A: Variant + Clone, T: Into<Dynamic>>(
&mut self,
fn_name: &str,
#[cfg(not(feature = "sync"))] func: impl Fn(A) -> Result<T, Box<EvalAltResult>> + 'static,
#[cfg(feature = "sync")] func: impl Fn(A) -> Result<T, Box<EvalAltResult>>
+ Send
+ Sync
+ 'static,
#[cfg(not(feature = "sync"))] func: impl Fn(A) -> FuncReturn<T> + 'static,
#[cfg(feature = "sync")] func: impl Fn(A) -> FuncReturn<T> + Send + Sync + 'static,
) -> u64 {
let f = move |args: &mut FnCallArgs, _: Position| {
func(mem::take(args[0]).cast::<A>()).map(|v| v.into())
let f = move |args: &mut FnCallArgs, pos| {
func(mem::take(args[0]).cast::<A>())
.map(|v| v.into())
.map_err(|err| EvalAltResult::set_position(err, pos))
};
self.set_fn(fn_name, &[TypeId::of::<A>()], Box::new(f))
let arg_types = &[TypeId::of::<A>()];
self.set_fn(fn_name, arg_types, Box::new(f))
}
/// Set a Rust function taking one mutable parameter into the module, returning a hash key.
@ -205,16 +220,16 @@ impl Module {
pub fn set_fn_1_mut<A: Variant + Clone, T: Into<Dynamic>>(
&mut self,
fn_name: &str,
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A) -> Result<T, Box<EvalAltResult>> + 'static,
#[cfg(feature = "sync")] func: impl Fn(&mut A) -> Result<T, Box<EvalAltResult>>
+ Send
+ Sync
+ 'static,
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A) -> FuncReturn<T> + 'static,
#[cfg(feature = "sync")] func: impl Fn(&mut A) -> FuncReturn<T> + Send + Sync + 'static,
) -> u64 {
let f = move |args: &mut FnCallArgs, _: Position| {
func(args[0].downcast_mut::<A>().unwrap()).map(|v| v.into())
let f = move |args: &mut FnCallArgs, pos| {
func(args[0].downcast_mut::<A>().unwrap())
.map(|v| v.into())
.map_err(|err| EvalAltResult::set_position(err, pos))
};
self.set_fn(fn_name, &[TypeId::of::<A>()], Box::new(f))
let arg_types = &[TypeId::of::<A>()];
self.set_fn(fn_name, arg_types, Box::new(f))
}
/// Set a Rust function taking two parameters into the module, returning a hash key.
@ -223,23 +238,19 @@ impl Module {
pub fn set_fn_2<A: Variant + Clone, B: Variant + Clone, T: Into<Dynamic>>(
&mut self,
fn_name: &str,
#[cfg(not(feature = "sync"))] func: impl Fn(A, B) -> Result<T, Box<EvalAltResult>> + 'static,
#[cfg(feature = "sync")] func: impl Fn(A, B) -> Result<T, Box<EvalAltResult>>
+ Send
+ Sync
+ 'static,
#[cfg(not(feature = "sync"))] func: impl Fn(A, B) -> FuncReturn<T> + 'static,
#[cfg(feature = "sync")] func: impl Fn(A, B) -> FuncReturn<T> + Send + Sync + 'static,
) -> u64 {
let f = move |args: &mut FnCallArgs, _: Position| {
let f = move |args: &mut FnCallArgs, pos| {
let a = mem::take(args[0]).cast::<A>();
let b = mem::take(args[1]).cast::<B>();
func(a, b).map(|v| v.into())
func(a, b)
.map(|v| v.into())
.map_err(|err| EvalAltResult::set_position(err, pos))
};
self.set_fn(
fn_name,
&[TypeId::of::<A>(), TypeId::of::<B>()],
Box::new(f),
)
let arg_types = &[TypeId::of::<A>(), TypeId::of::<B>()];
self.set_fn(fn_name, arg_types, Box::new(f))
}
/// Set a Rust function taking two parameters (the first one mutable) into the module,
@ -249,24 +260,19 @@ impl Module {
pub fn set_fn_2_mut<A: Variant + Clone, B: Variant + Clone, T: Into<Dynamic>>(
&mut self,
fn_name: &str,
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A, B) -> Result<T, Box<EvalAltResult>>
+ 'static,
#[cfg(feature = "sync")] func: impl Fn(&mut A, B) -> Result<T, Box<EvalAltResult>>
+ Send
+ Sync
+ 'static,
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A, B) -> FuncReturn<T> + 'static,
#[cfg(feature = "sync")] func: impl Fn(&mut A, B) -> FuncReturn<T> + Send + Sync + 'static,
) -> u64 {
let f = move |args: &mut FnCallArgs, _: Position| {
let f = move |args: &mut FnCallArgs, pos| {
let b = mem::take(args[1]).cast::<B>();
let a = args[0].downcast_mut::<A>().unwrap();
func(a, b).map(|v| v.into())
func(a, b)
.map(|v| v.into())
.map_err(|err| EvalAltResult::set_position(err, pos))
};
self.set_fn(
fn_name,
&[TypeId::of::<A>(), TypeId::of::<B>()],
Box::new(f),
)
let arg_types = &[TypeId::of::<A>(), TypeId::of::<B>()];
self.set_fn(fn_name, arg_types, Box::new(f))
}
/// Set a Rust function taking three parameters into the module, returning a hash key.
@ -280,24 +286,20 @@ impl Module {
>(
&mut self,
fn_name: &str,
#[cfg(not(feature = "sync"))] func: impl Fn(A, B, C) -> Result<T, Box<EvalAltResult>> + 'static,
#[cfg(feature = "sync")] func: impl Fn(A, B, C) -> Result<T, Box<EvalAltResult>>
+ Send
+ Sync
+ 'static,
#[cfg(not(feature = "sync"))] func: impl Fn(A, B, C) -> FuncReturn<T> + 'static,
#[cfg(feature = "sync")] func: impl Fn(A, B, C) -> FuncReturn<T> + Send + Sync + 'static,
) -> u64 {
let f = move |args: &mut FnCallArgs, _: Position| {
let f = move |args: &mut FnCallArgs, pos| {
let a = mem::take(args[0]).cast::<A>();
let b = mem::take(args[1]).cast::<B>();
let c = mem::take(args[2]).cast::<C>();
func(a, b, c).map(|v| v.into())
func(a, b, c)
.map(|v| v.into())
.map_err(|err| EvalAltResult::set_position(err, pos))
};
self.set_fn(
fn_name,
&[TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()],
Box::new(f),
)
let arg_types = &[TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
self.set_fn(fn_name, arg_types, Box::new(f))
}
/// Set a Rust function taking three parameters (the first one mutable) into the module,
@ -312,25 +314,20 @@ impl Module {
>(
&mut self,
fn_name: &str,
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A, B, C) -> Result<T, Box<EvalAltResult>>
+ 'static,
#[cfg(feature = "sync")] func: impl Fn(&mut A, B, C) -> Result<T, Box<EvalAltResult>>
+ Send
+ Sync
+ 'static,
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A, B, C) -> FuncReturn<T> + 'static,
#[cfg(feature = "sync")] func: impl Fn(&mut A, B, C) -> FuncReturn<T> + Send + Sync + 'static,
) -> u64 {
let f = move |args: &mut FnCallArgs, _: Position| {
let f = move |args: &mut FnCallArgs, pos| {
let b = mem::take(args[1]).cast::<B>();
let c = mem::take(args[2]).cast::<C>();
let a = args[0].downcast_mut::<A>().unwrap();
func(a, b, c).map(|v| v.into())
func(a, b, c)
.map(|v| v.into())
.map_err(|err| EvalAltResult::set_position(err, pos))
};
self.set_fn(
fn_name,
&[TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()],
Box::new(f),
)
let arg_types = &[TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
self.set_fn(fn_name, arg_types, Box::new(f))
}
/// Get a Rust function.
@ -388,22 +385,40 @@ impl Module {
}
}
/// Re-export module resolvers.
pub mod resolvers {
use super::*;
pub use super::file::FileModuleResolver;
pub use super::stat::StaticModuleResolver;
}
#[cfg(not(feature = "no_std"))]
/// Script file-based module resolver.
#[cfg(not(feature = "no_std"))]
mod file {
use super::*;
use crate::stdlib::path::PathBuf;
/// A module resolution service that loads module script files (assumed `.rhai` extension).
#[cfg(not(feature = "no_std"))]
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct FileModuleResolver(PathBuf);
/// A module resolution service that loads module script files from the file system.
///
/// The `new_with_path` and `new_with_path_and_extension` constructor functions
/// allow specification of a base directory with module path used as a relative path offset
/// to the base directory. The script file is then forced to be in a specified extension
/// (default `.rhai`).
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Default)]
pub struct FileModuleResolver {
path: PathBuf,
extension: String,
}
#[cfg(not(feature = "no_std"))]
impl FileModuleResolver {
/// Create a new `FileModuleResolver` with a specific base path.
pub fn new_with_path(path: PathBuf) -> Self {
Self(path)
Self::new_with_path_and_extension(path, "rhai".to_string())
}
/// Create a new `FileModuleResolver` with a specific base path and file extension.
///
/// The default extension is `.rhai`.
pub fn new_with_path_and_extension(path: PathBuf, extension: String) -> Self {
Self { path, extension }
}
/// Create a new `FileModuleResolver` with the current directory as base path.
pub fn new() -> Self {
@ -411,54 +426,63 @@ pub mod resolvers {
}
}
#[cfg(not(feature = "no_std"))]
impl Default for FileModuleResolver {
fn default() -> Self {
Self::new_with_path(".".into())
}
}
#[cfg(not(feature = "no_std"))]
impl ModuleResolver for FileModuleResolver {
fn resolve(&self, engine: &Engine, path: &str) -> Result<Module, Box<EvalAltResult>> {
// Load the script file (attaching `.rhai`)
let mut file_path = self.0.clone();
fn resolve(
&self,
engine: &Engine,
path: &str,
pos: Position,
) -> Result<Module, Box<EvalAltResult>> {
// Construct the script file path
let mut file_path = self.path.clone();
file_path.push(path);
file_path.set_extension("rhai");
file_path.set_extension(&self.extension); // Force extension
// Compile it
let ast = engine.compile_file(file_path)?;
let ast = engine
.compile_file(file_path)
.map_err(|err| EvalAltResult::set_position(err, pos))?;
// Use new scope
let mut scope = Scope::new();
// Run the script
engine.eval_ast_with_scope_raw(&mut scope, &ast)?;
engine
.eval_ast_with_scope_raw(&mut scope, &ast)
.map_err(|err| EvalAltResult::set_position(err, pos))?;
// Create new module
let mut module = Module::new();
// Variables left in the scope become module variables
for entry in scope.into_iter() {
match entry.typ {
ScopeEntryType::Normal | ScopeEntryType::Constant => {
module
.variables
.insert(entry.name.into_owned(), entry.value);
scope.into_iter().for_each(
|ScopeEntry {
name, typ, value, ..
}| {
match typ {
// Variables left in the scope become module variables
ScopeEntryType::Normal | ScopeEntryType::Constant => {
module.variables.insert(name.into_owned(), value);
}
// Modules left in the scope become sub-modules
ScopeEntryType::Module => {
module
.modules
.insert(name.into_owned(), value.cast::<Module>());
}
}
ScopeEntryType::Module => {
module
.modules
.insert(entry.name.into_owned(), entry.value.cast::<Module>());
}
}
}
},
);
module.fn_lib = FunctionsLib::new().merge(ast.fn_lib());
module.fn_lib = module.fn_lib.merge(ast.fn_lib());
Ok(module)
}
}
}
/// Static module resolver.
mod stat {
use super::*;
/// A module resolution service that serves modules added into it.
#[derive(Debug, Clone, Default)]
@ -469,40 +493,33 @@ pub mod resolvers {
pub fn new() -> Self {
Default::default()
}
/// Add a named module.
pub fn add_module(&mut self, name: &str, module: Module) {
self.0.insert(name.to_string(), module);
}
impl Deref for StaticModuleResolver {
type Target = HashMap<String, Module>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for StaticModuleResolver {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl ModuleResolver for StaticModuleResolver {
fn resolve(&self, _: &Engine, path: &str) -> Result<Module, Box<EvalAltResult>> {
self.0.get(path).cloned().ok_or_else(|| {
Box::new(EvalAltResult::ErrorModuleNotFound(
path.to_string(),
Position::none(),
))
})
}
}
/// A module resolution service that always returns a not-found error.
#[derive(Debug, Clone, PartialEq, Eq, Copy, Default)]
pub struct NullModuleResolver;
impl NullModuleResolver {
/// Create a new `NullModuleResolver`.
pub fn new() -> Self {
Default::default()
}
}
impl ModuleResolver for NullModuleResolver {
fn resolve(&self, _: &Engine, path: &str) -> Result<Module, Box<EvalAltResult>> {
Err(Box::new(EvalAltResult::ErrorModuleNotFound(
path.to_string(),
Position::none(),
)))
fn resolve(
&self,
_: &Engine,
path: &str,
pos: Position,
) -> Result<Module, Box<EvalAltResult>> {
self.0
.get(path)
.cloned()
.ok_or_else(|| Box::new(EvalAltResult::ErrorModuleNotFound(path.to_string(), pos)))
}
}
}

View File

@ -67,13 +67,9 @@ impl AST {
/// Create a new `AST`.
pub fn new(statements: Vec<Stmt>, fn_lib: FunctionsLib) -> Self {
#[cfg(feature = "sync")]
{
Self(statements, Arc::new(fn_lib))
}
return Self(statements, Arc::new(fn_lib));
#[cfg(not(feature = "sync"))]
{
Self(statements, Rc::new(fn_lib))
}
return Self(statements, Rc::new(fn_lib));
}
/// Get the statements.
@ -148,13 +144,9 @@ impl AST {
};
#[cfg(feature = "sync")]
{
Self(ast, Arc::new(functions.merge(other.1.as_ref())))
}
return Self(ast, Arc::new(functions.merge(other.1.as_ref())));
#[cfg(not(feature = "sync"))]
{
Self(ast, Rc::new(functions.merge(other.1.as_ref())))
}
return Self(ast, Rc::new(functions.merge(other.1.as_ref())));
}
/// Clear all function definitions in the `AST`.
@ -1810,7 +1802,6 @@ fn parse_let<'a>(
}
/// Parse an import statement.
#[cfg(not(feature = "no_module"))]
fn parse_import<'a>(
input: &mut Peekable<TokenIterator<'a>>,
stack: &mut Stack,
@ -1941,7 +1932,6 @@ fn parse_stmt<'a>(
Token::LeftBrace => parse_block(input, stack, breakable, allow_stmt_expr),
// fn ...
#[cfg(not(feature = "no_function"))]
Token::Fn => Err(PERR::WrongFnDefinition.into_err(*pos)),
Token::If => parse_if(input, stack, breakable, allow_stmt_expr),
@ -2115,14 +2105,11 @@ fn parse_global_level<'a>(
while !input.peek().unwrap().0.is_eof() {
// Collect all the function definitions
#[cfg(not(feature = "no_function"))]
{
if let (Token::Fn, _) = input.peek().unwrap() {
let mut stack = Stack::new();
let f = parse_fn(input, &mut stack, true)?;
functions.insert(calc_fn_def(&f.name, f.params.len()), f);
continue;
}
if let (Token::Fn, _) = input.peek().unwrap() {
let mut stack = Stack::new();
let f = parse_fn(input, &mut stack, true)?;
functions.insert(calc_fn_def(&f.name, f.params.len()), f);
continue;
}
// Actual statement

View File

@ -153,11 +153,9 @@ pub enum Token {
RightShift,
SemiColon,
Colon,
#[cfg(not(feature = "no_module"))]
DoubleColon,
Comma,
Period,
#[cfg(not(feature = "no_object"))]
MapStart,
Equals,
True,
@ -182,7 +180,6 @@ pub enum Token {
XOr,
Ampersand,
And,
#[cfg(not(feature = "no_function"))]
Fn,
Continue,
Break,
@ -199,11 +196,8 @@ pub enum Token {
XOrAssign,
ModuloAssign,
PowerOfAssign,
#[cfg(not(feature = "no_module"))]
Import,
#[cfg(not(feature = "no_module"))]
Export,
#[cfg(not(feature = "no_module"))]
As,
LexError(Box<LexError>),
EOF,
@ -238,11 +232,9 @@ impl Token {
Divide => "/",
SemiColon => ";",
Colon => ":",
#[cfg(not(feature = "no_module"))]
DoubleColon => "::",
Comma => ",",
Period => ".",
#[cfg(not(feature = "no_object"))]
MapStart => "#{",
Equals => "=",
True => "true",
@ -266,7 +258,6 @@ impl Token {
Or => "||",
Ampersand => "&",
And => "&&",
#[cfg(not(feature = "no_function"))]
Fn => "fn",
Continue => "continue",
Break => "break",
@ -288,11 +279,8 @@ impl Token {
ModuloAssign => "%=",
PowerOf => "~",
PowerOfAssign => "~=",
#[cfg(not(feature = "no_module"))]
Import => "import",
#[cfg(not(feature = "no_module"))]
Export => "export",
#[cfg(not(feature = "no_module"))]
As => "as",
EOF => "{EOF}",
_ => panic!("operator should be match in outer scope"),

View File

@ -64,10 +64,10 @@ fn test_module_resolver() -> Result<(), Box<EvalAltResult>> {
let mut module = Module::new();
module.set_var("answer", 42 as INT);
resolver.add_module("hello", module);
resolver.insert("hello".to_string(), module);
let mut engine = Engine::new();
engine.set_module_resolver(resolver);
engine.set_module_resolver(Some(resolver));
assert_eq!(
engine.eval::<INT>(