Implement namespaces chain.
This commit is contained in:
parent
643ecc86a3
commit
92ba7b42d5
@ -121,7 +121,7 @@ where:
|
|||||||
* `context: &mut EvalContext` - mutable reference to the current evaluation _context_, exposing the following:
|
* `context: &mut EvalContext` - mutable reference to the current evaluation _context_, exposing the following:
|
||||||
* `context.scope: &mut Scope` - mutable reference to the current [`Scope`]; variables can be added to/removed from it.
|
* `context.scope: &mut Scope` - mutable reference to the current [`Scope`]; variables can be added to/removed from it.
|
||||||
* `context.engine(): &Engine` - reference to the current [`Engine`].
|
* `context.engine(): &Engine` - reference to the current [`Engine`].
|
||||||
* `context.namespace(): &Module` - reference to the current _global namespace_ (as a [module]) containing all script-defined functions.
|
* `context.namespaces(): &[&Module]` - reference to the chain of namespaces (as a slice of [modules]) containing all script-defined functions.
|
||||||
* `context.this_ptr(): Option<&Dynamic>` - reference to the current bound [`this`] pointer, if any.
|
* `context.this_ptr(): Option<&Dynamic>` - reference to the current bound [`this`] pointer, if any.
|
||||||
* `context.call_level(): usize` - the current nesting level of function calls.
|
* `context.call_level(): usize` - the current nesting level of function calls.
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ where:
|
|||||||
* `context: &EvalContext` - reference to the current evaluation _context_, which exposes the following fields:
|
* `context: &EvalContext` - reference to the current evaluation _context_, which exposes the following fields:
|
||||||
* `context.scope: &Scope` - reference to the current [`Scope`] containing all variables up to the current evaluation position.
|
* `context.scope: &Scope` - reference to the current [`Scope`] containing all variables up to the current evaluation position.
|
||||||
* `context.engine(): &Engine` - reference to the current [`Engine`].
|
* `context.engine(): &Engine` - reference to the current [`Engine`].
|
||||||
* `context.namespace(): &Module` - reference to the current _global namespace_ (as a [module]) containing all script-defined functions.
|
* `context.namespaces(): &[&Module]` - reference to the chain of namespaces (as a slice of [modules]) containing all script-defined functions.
|
||||||
* `context.this_ptr(): Option<&Dynamic>` - reference to the current bound [`this`] pointer, if any.
|
* `context.this_ptr(): Option<&Dynamic>` - reference to the current bound [`this`] pointer, if any.
|
||||||
* `context.call_level(): usize` - the current nesting level of function calls.
|
* `context.call_level(): usize` - the current nesting level of function calls.
|
||||||
|
|
||||||
|
@ -249,8 +249,8 @@ let fn_ptr = engine.eval_ast::<FnPtr>(&ast)?;
|
|||||||
ast.retain_functions(|_, _, _| true);
|
ast.retain_functions(|_, _, _| true);
|
||||||
|
|
||||||
// Create native call context via a tuple containing the Engine and the
|
// Create native call context via a tuple containing the Engine and the
|
||||||
// set of script-defined functions (within the AST)
|
// set of script-defined functions (within the AST) in form of a slice.
|
||||||
let context = (&engine, ast.as_ref()).into();
|
let context = (&engine, &[ast.as_ref()]).into();
|
||||||
|
|
||||||
// 'f' captures: the engine, the AST, and the closure
|
// 'f' captures: the engine, the AST, and the closure
|
||||||
let f = move |x: i64| fn_ptr.call_dynamic(context, None, [x.into()]);
|
let f = move |x: i64| fn_ptr.call_dynamic(context, None, [x.into()]);
|
||||||
|
@ -72,8 +72,7 @@ where:
|
|||||||
* `context.engine(): &Engine` - the current [`Engine`], with all configurations and settings.
|
* `context.engine(): &Engine` - the current [`Engine`], with all configurations and settings.
|
||||||
This is sometimes useful for calling a script-defined function within the same evaluation context
|
This is sometimes useful for calling a script-defined function within the same evaluation context
|
||||||
using [`Engine::call_fn`][`call_fn`], or calling a [function pointer].
|
using [`Engine::call_fn`][`call_fn`], or calling a [function pointer].
|
||||||
|
* `context.namespaces(): &[&Module]` - reference to the chain of namespaces (as a slice of [modules]) containing all script-defined functions.
|
||||||
* `context.namespace(): &Module` - the global namespace of script-defined functions, as a [`Module`].
|
|
||||||
|
|
||||||
* `args: &mut [&mut Dynamic]` - a slice containing `&mut` references to [`Dynamic`] values.
|
* `args: &mut [&mut Dynamic]` - a slice containing `&mut` references to [`Dynamic`] values.
|
||||||
The slice is guaranteed to contain enough arguments _of the correct types_.
|
The slice is guaranteed to contain enough arguments _of the correct types_.
|
||||||
|
68
src/api.rs
68
src/api.rs
@ -804,7 +804,7 @@ impl Engine {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn compile(&self, script: &str) -> Result<AST, ParseError> {
|
pub fn compile(&self, script: &str) -> Result<AST, ParseError> {
|
||||||
self.compile_with_scope(&Scope::new(), script)
|
self.compile_with_scope(&Default::default(), script)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compile a string into an `AST` using own scope, which can be used later for evaluation.
|
/// Compile a string into an `AST` using own scope, which can be used later for evaluation.
|
||||||
@ -965,7 +965,7 @@ impl Engine {
|
|||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn compile_file(&self, path: PathBuf) -> Result<AST, Box<EvalAltResult>> {
|
pub fn compile_file(&self, path: PathBuf) -> Result<AST, Box<EvalAltResult>> {
|
||||||
self.compile_file_with_scope(&Scope::new(), path)
|
self.compile_file_with_scope(&Default::default(), path)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compile a script file into an `AST` using own scope, which can be used later for evaluation.
|
/// Compile a script file into an `AST` using own scope, which can be used later for evaluation.
|
||||||
@ -1050,7 +1050,7 @@ impl Engine {
|
|||||||
/// ```
|
/// ```
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
pub fn parse_json(&self, json: &str, has_null: bool) -> Result<Map, Box<EvalAltResult>> {
|
pub fn parse_json(&self, json: &str, has_null: bool) -> Result<Map, Box<EvalAltResult>> {
|
||||||
let mut scope = Scope::new();
|
let mut scope = Default::default();
|
||||||
|
|
||||||
// Trims the JSON string and add a '#' in front
|
// Trims the JSON string and add a '#' in front
|
||||||
let json_text = json.trim_start();
|
let json_text = json.trim_start();
|
||||||
@ -1112,7 +1112,7 @@ impl Engine {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn compile_expression(&self, script: &str) -> Result<AST, ParseError> {
|
pub fn compile_expression(&self, script: &str) -> Result<AST, ParseError> {
|
||||||
self.compile_expression_with_scope(&Scope::new(), script)
|
self.compile_expression_with_scope(&Default::default(), script)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compile a string containing an expression into an `AST` using own scope,
|
/// Compile a string containing an expression into an `AST` using own scope,
|
||||||
@ -1236,7 +1236,7 @@ impl Engine {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn eval<T: Variant + Clone>(&self, script: &str) -> Result<T, Box<EvalAltResult>> {
|
pub fn eval<T: Variant + Clone>(&self, script: &str) -> Result<T, Box<EvalAltResult>> {
|
||||||
self.eval_with_scope(&mut Scope::new(), script)
|
self.eval_with_scope(&mut Default::default(), script)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate a string with own scope.
|
/// Evaluate a string with own scope.
|
||||||
@ -1294,7 +1294,7 @@ impl Engine {
|
|||||||
&self,
|
&self,
|
||||||
script: &str,
|
script: &str,
|
||||||
) -> Result<T, Box<EvalAltResult>> {
|
) -> Result<T, Box<EvalAltResult>> {
|
||||||
self.eval_expression_with_scope(&mut Scope::new(), script)
|
self.eval_expression_with_scope(&mut Default::default(), script)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate a string containing an expression with own scope.
|
/// Evaluate a string containing an expression with own scope.
|
||||||
@ -1350,7 +1350,7 @@ impl Engine {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn eval_ast<T: Variant + Clone>(&self, ast: &AST) -> Result<T, Box<EvalAltResult>> {
|
pub fn eval_ast<T: Variant + Clone>(&self, ast: &AST) -> Result<T, Box<EvalAltResult>> {
|
||||||
self.eval_ast_with_scope(&mut Scope::new(), ast)
|
self.eval_ast_with_scope(&mut Default::default(), ast)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate an `AST` with own scope.
|
/// Evaluate an `AST` with own scope.
|
||||||
@ -1388,7 +1388,7 @@ impl Engine {
|
|||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
ast: &AST,
|
ast: &AST,
|
||||||
) -> Result<T, Box<EvalAltResult>> {
|
) -> Result<T, Box<EvalAltResult>> {
|
||||||
let mut mods = Imports::new();
|
let mut mods = Default::default();
|
||||||
let (result, _) = self.eval_ast_with_scope_raw(scope, &mut mods, ast)?;
|
let (result, _) = self.eval_ast_with_scope_raw(scope, &mut mods, ast)?;
|
||||||
|
|
||||||
let typ = self.map_type_name(result.type_name());
|
let typ = self.map_type_name(result.type_name());
|
||||||
@ -1404,26 +1404,14 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate an `AST` with own scope.
|
/// Evaluate an `AST` with own scope.
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
pub(crate) fn eval_ast_with_scope_raw<'a>(
|
pub(crate) fn eval_ast_with_scope_raw<'a>(
|
||||||
&self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
mods: &mut Imports,
|
mods: &mut Imports,
|
||||||
ast: &'a AST,
|
ast: &'a AST,
|
||||||
) -> Result<(Dynamic, u64), Box<EvalAltResult>> {
|
) -> Result<(Dynamic, u64), Box<EvalAltResult>> {
|
||||||
let mut state = State::new();
|
self.eval_statements(scope, mods, ast.statements(), &[ast.lib()])
|
||||||
|
|
||||||
ast.statements()
|
|
||||||
.iter()
|
|
||||||
.try_fold(().into(), |_, stmt| {
|
|
||||||
self.eval_stmt(scope, mods, &mut state, ast.lib(), &mut None, stmt, 0)
|
|
||||||
})
|
|
||||||
.or_else(|err| match *err {
|
|
||||||
EvalAltResult::Return(out, _) => Ok(out),
|
|
||||||
EvalAltResult::LoopBreak(_, _) => unreachable!(),
|
|
||||||
_ => Err(err),
|
|
||||||
})
|
|
||||||
.map(|v| (v, state.operations))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate a file, but throw away the result and only return error (if any).
|
/// Evaluate a file, but throw away the result and only return error (if any).
|
||||||
@ -1452,7 +1440,7 @@ impl Engine {
|
|||||||
/// Useful for when you don't need the result, but still need to keep track of possible errors.
|
/// Useful for when you don't need the result, but still need to keep track of possible errors.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn consume(&self, script: &str) -> Result<(), Box<EvalAltResult>> {
|
pub fn consume(&self, script: &str) -> Result<(), Box<EvalAltResult>> {
|
||||||
self.consume_with_scope(&mut Scope::new(), script)
|
self.consume_with_scope(&mut Default::default(), script)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate a string with own scope, but throw away the result and only return error (if any).
|
/// Evaluate a string with own scope, but throw away the result and only return error (if any).
|
||||||
@ -1473,33 +1461,20 @@ impl Engine {
|
|||||||
/// Useful for when you don't need the result, but still need to keep track of possible errors.
|
/// Useful for when you don't need the result, but still need to keep track of possible errors.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn consume_ast(&self, ast: &AST) -> Result<(), Box<EvalAltResult>> {
|
pub fn consume_ast(&self, ast: &AST) -> Result<(), Box<EvalAltResult>> {
|
||||||
self.consume_ast_with_scope(&mut Scope::new(), ast)
|
self.consume_ast_with_scope(&mut Default::default(), ast)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate an `AST` with own scope, but throw away the result and only return error (if any).
|
/// Evaluate an `AST` with own scope, but throw away the result and only return error (if any).
|
||||||
/// Useful for when you don't need the result, but still need to keep track of possible errors.
|
/// Useful for when you don't need the result, but still need to keep track of possible errors.
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
pub fn consume_ast_with_scope(
|
pub fn consume_ast_with_scope(
|
||||||
&self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
ast: &AST,
|
ast: &AST,
|
||||||
) -> Result<(), Box<EvalAltResult>> {
|
) -> Result<(), Box<EvalAltResult>> {
|
||||||
let mut state = State::new();
|
|
||||||
let mut mods = Default::default();
|
let mut mods = Default::default();
|
||||||
|
self.eval_statements(scope, &mut mods, ast.statements(), &[ast.lib()])
|
||||||
ast.statements()
|
.map(|_| ())
|
||||||
.iter()
|
|
||||||
.try_fold(().into(), |_, stmt| {
|
|
||||||
self.eval_stmt(scope, &mut mods, &mut state, ast.lib(), &mut None, stmt, 0)
|
|
||||||
})
|
|
||||||
.map_or_else(
|
|
||||||
|err| match *err {
|
|
||||||
EvalAltResult::Return(_, _) => Ok(()),
|
|
||||||
EvalAltResult::LoopBreak(_, _) => unreachable!(),
|
|
||||||
_ => Err(err),
|
|
||||||
},
|
|
||||||
|_| Ok(()),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call a script function defined in an `AST` with multiple arguments.
|
/// Call a script function defined in an `AST` with multiple arguments.
|
||||||
@ -1651,14 +1626,23 @@ impl Engine {
|
|||||||
.ok_or_else(|| EvalAltResult::ErrorFunctionNotFound(name.into(), Position::none()))?;
|
.ok_or_else(|| EvalAltResult::ErrorFunctionNotFound(name.into(), Position::none()))?;
|
||||||
|
|
||||||
let mut state = State::new();
|
let mut state = State::new();
|
||||||
let mut mods = Imports::new();
|
let mut mods = Default::default();
|
||||||
|
|
||||||
// Check for data race.
|
// Check for data race.
|
||||||
if cfg!(not(feature = "no_closure")) {
|
if cfg!(not(feature = "no_closure")) {
|
||||||
ensure_no_data_race(name, args, false)?;
|
ensure_no_data_race(name, args, false)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.call_script_fn(scope, &mut mods, &mut state, lib, this_ptr, fn_def, args, 0)
|
self.call_script_fn(
|
||||||
|
scope,
|
||||||
|
&mut mods,
|
||||||
|
&mut state,
|
||||||
|
&[lib],
|
||||||
|
this_ptr,
|
||||||
|
fn_def,
|
||||||
|
args,
|
||||||
|
0,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Optimize the `AST` with constants defined in an external Scope.
|
/// Optimize the `AST` with constants defined in an external Scope.
|
||||||
|
@ -441,17 +441,17 @@ pub struct Limits {
|
|||||||
|
|
||||||
/// Context of a script evaluation process.
|
/// Context of a script evaluation process.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct EvalContext<'e, 'x, 'px: 'x, 'a, 's, 'm, 't, 'pt: 't> {
|
pub struct EvalContext<'e, 'x, 'px: 'x, 'a, 's, 'm, 'pm: 'm, 't, 'pt: 't> {
|
||||||
engine: &'e Engine,
|
engine: &'e Engine,
|
||||||
pub scope: &'x mut Scope<'px>,
|
pub scope: &'x mut Scope<'px>,
|
||||||
pub(crate) mods: &'a mut Imports,
|
pub(crate) mods: &'a mut Imports,
|
||||||
pub(crate) state: &'s mut State,
|
pub(crate) state: &'s mut State,
|
||||||
lib: &'m Module,
|
lib: &'m [&'pm Module],
|
||||||
pub(crate) this_ptr: &'t mut Option<&'pt mut Dynamic>,
|
pub(crate) this_ptr: &'t mut Option<&'pt mut Dynamic>,
|
||||||
level: usize,
|
level: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'e, 'x, 'px, 'a, 's, 'm, 't, 'pt> EvalContext<'e, 'x, 'px, 'a, 's, 'm, 't, 'pt> {
|
impl<'e, 'x, 'px, 'a, 's, 'm, 'pm, 't, 'pt> EvalContext<'e, 'x, 'px, 'a, 's, 'm, 'pm, 't, 'pt> {
|
||||||
/// The current `Engine`.
|
/// The current `Engine`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn engine(&self) -> &'e Engine {
|
pub fn engine(&self) -> &'e Engine {
|
||||||
@ -465,9 +465,9 @@ impl<'e, 'x, 'px, 'a, 's, 'm, 't, 'pt> EvalContext<'e, 'x, 'px, 'a, 's, 'm, 't,
|
|||||||
pub fn imports(&self) -> &'a Imports {
|
pub fn imports(&self) -> &'a Imports {
|
||||||
self.mods
|
self.mods
|
||||||
}
|
}
|
||||||
/// The global namespace containing definition of all script-defined functions.
|
/// The chain of namespaces containing definition of all script-defined functions.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn namespace(&self) -> &'m Module {
|
pub fn namespaces(&self) -> &'m [&'pm Module] {
|
||||||
self.lib
|
self.lib
|
||||||
}
|
}
|
||||||
/// The current bound `this` pointer, if any.
|
/// The current bound `this` pointer, if any.
|
||||||
@ -757,7 +757,7 @@ impl Engine {
|
|||||||
scope: &'s mut Scope,
|
scope: &'s mut Scope,
|
||||||
mods: &'s mut Imports,
|
mods: &'s mut Imports,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &Module,
|
lib: &[&Module],
|
||||||
this_ptr: &'s mut Option<&mut Dynamic>,
|
this_ptr: &'s mut Option<&mut Dynamic>,
|
||||||
expr: &'a Expr,
|
expr: &'a Expr,
|
||||||
) -> Result<(Target<'s>, &'a str, ScopeEntryType, Position), Box<EvalAltResult>> {
|
) -> Result<(Target<'s>, &'a str, ScopeEntryType, Position), Box<EvalAltResult>> {
|
||||||
@ -792,7 +792,7 @@ impl Engine {
|
|||||||
scope: &'s mut Scope,
|
scope: &'s mut Scope,
|
||||||
mods: &mut Imports,
|
mods: &mut Imports,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &Module,
|
lib: &[&Module],
|
||||||
this_ptr: &'s mut Option<&mut Dynamic>,
|
this_ptr: &'s mut Option<&mut Dynamic>,
|
||||||
expr: &'a Expr,
|
expr: &'a Expr,
|
||||||
) -> Result<(Target<'s>, &'a str, ScopeEntryType, Position), Box<EvalAltResult>> {
|
) -> Result<(Target<'s>, &'a str, ScopeEntryType, Position), Box<EvalAltResult>> {
|
||||||
@ -862,7 +862,7 @@ impl Engine {
|
|||||||
fn eval_dot_index_chain_helper(
|
fn eval_dot_index_chain_helper(
|
||||||
&self,
|
&self,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &Module,
|
lib: &[&Module],
|
||||||
this_ptr: &mut Option<&mut Dynamic>,
|
this_ptr: &mut Option<&mut Dynamic>,
|
||||||
target: &mut Target,
|
target: &mut Target,
|
||||||
rhs: &Expr,
|
rhs: &Expr,
|
||||||
@ -1155,7 +1155,7 @@ impl Engine {
|
|||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
mods: &mut Imports,
|
mods: &mut Imports,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &Module,
|
lib: &[&Module],
|
||||||
this_ptr: &mut Option<&mut Dynamic>,
|
this_ptr: &mut Option<&mut Dynamic>,
|
||||||
expr: &Expr,
|
expr: &Expr,
|
||||||
level: usize,
|
level: usize,
|
||||||
@ -1234,7 +1234,7 @@ impl Engine {
|
|||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
mods: &mut Imports,
|
mods: &mut Imports,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &Module,
|
lib: &[&Module],
|
||||||
this_ptr: &mut Option<&mut Dynamic>,
|
this_ptr: &mut Option<&mut Dynamic>,
|
||||||
expr: &Expr,
|
expr: &Expr,
|
||||||
chain_type: ChainType,
|
chain_type: ChainType,
|
||||||
@ -1305,7 +1305,7 @@ impl Engine {
|
|||||||
fn get_indexed_mut<'a>(
|
fn get_indexed_mut<'a>(
|
||||||
&self,
|
&self,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
_lib: &Module,
|
_lib: &[&Module],
|
||||||
target: &'a mut Target,
|
target: &'a mut Target,
|
||||||
idx: Dynamic,
|
idx: Dynamic,
|
||||||
idx_pos: Position,
|
idx_pos: Position,
|
||||||
@ -1414,7 +1414,7 @@ impl Engine {
|
|||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
mods: &mut Imports,
|
mods: &mut Imports,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &Module,
|
lib: &[&Module],
|
||||||
this_ptr: &mut Option<&mut Dynamic>,
|
this_ptr: &mut Option<&mut Dynamic>,
|
||||||
lhs: &Expr,
|
lhs: &Expr,
|
||||||
rhs: &Expr,
|
rhs: &Expr,
|
||||||
@ -1477,7 +1477,7 @@ impl Engine {
|
|||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
mods: &mut Imports,
|
mods: &mut Imports,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &Module,
|
lib: &[&Module],
|
||||||
this_ptr: &mut Option<&mut Dynamic>,
|
this_ptr: &mut Option<&mut Dynamic>,
|
||||||
expr: &Expr,
|
expr: &Expr,
|
||||||
level: usize,
|
level: usize,
|
||||||
@ -1786,7 +1786,7 @@ impl Engine {
|
|||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
mods: &mut Imports,
|
mods: &mut Imports,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &Module,
|
lib: &[&Module],
|
||||||
this_ptr: &mut Option<&mut Dynamic>,
|
this_ptr: &mut Option<&mut Dynamic>,
|
||||||
stmt: &Stmt,
|
stmt: &Stmt,
|
||||||
level: usize,
|
level: usize,
|
||||||
|
@ -10,7 +10,7 @@ use crate::error::ParseErrorType;
|
|||||||
use crate::fn_native::{FnCallArgs, FnPtr};
|
use crate::fn_native::{FnCallArgs, FnPtr};
|
||||||
use crate::module::{Module, ModuleRef};
|
use crate::module::{Module, ModuleRef};
|
||||||
use crate::optimize::OptimizationLevel;
|
use crate::optimize::OptimizationLevel;
|
||||||
use crate::parser::{Expr, ImmutableString, AST, INT};
|
use crate::parser::{Expr, ImmutableString, Stmt, INT};
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use crate::stdlib::ops::Deref;
|
use crate::stdlib::ops::Deref;
|
||||||
@ -180,7 +180,7 @@ impl Engine {
|
|||||||
pub(crate) fn call_native_fn(
|
pub(crate) fn call_native_fn(
|
||||||
&self,
|
&self,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &Module,
|
lib: &[&Module],
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
hash_fn: u64,
|
hash_fn: u64,
|
||||||
args: &mut FnCallArgs,
|
args: &mut FnCallArgs,
|
||||||
@ -345,7 +345,7 @@ impl Engine {
|
|||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
mods: &mut Imports,
|
mods: &mut Imports,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &Module,
|
lib: &[&Module],
|
||||||
this_ptr: &mut Option<&mut Dynamic>,
|
this_ptr: &mut Option<&mut Dynamic>,
|
||||||
fn_def: &ScriptFnDef,
|
fn_def: &ScriptFnDef,
|
||||||
args: &mut FnCallArgs,
|
args: &mut FnCallArgs,
|
||||||
@ -382,17 +382,15 @@ impl Engine {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Merge in encapsulated environment, if any
|
// Merge in encapsulated environment, if any
|
||||||
let mut lib_merged;
|
let mut lib_merged: StaticVec<_>;
|
||||||
|
|
||||||
let unified_lib = if let Some(ref env_lib) = fn_def.lib {
|
let unified_lib = if let Some(ref env_lib) = fn_def.lib {
|
||||||
if lib.is_empty() {
|
lib_merged = Default::default();
|
||||||
// In the special case of the main script not defining any function
|
lib_merged.push(env_lib.as_ref());
|
||||||
env_lib
|
if !lib.is_empty() {
|
||||||
} else {
|
lib_merged.extend(lib.iter().cloned());
|
||||||
lib_merged = lib.clone();
|
|
||||||
lib_merged.merge(env_lib);
|
|
||||||
&lib_merged
|
|
||||||
}
|
}
|
||||||
|
lib_merged.as_ref()
|
||||||
} else {
|
} else {
|
||||||
lib
|
lib
|
||||||
};
|
};
|
||||||
@ -433,7 +431,7 @@ impl Engine {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn has_override_by_name_and_arguments(
|
pub(crate) fn has_override_by_name_and_arguments(
|
||||||
&self,
|
&self,
|
||||||
lib: &Module,
|
lib: &[&Module],
|
||||||
name: &str,
|
name: &str,
|
||||||
arg_types: impl AsRef<[TypeId]>,
|
arg_types: impl AsRef<[TypeId]>,
|
||||||
pub_only: bool,
|
pub_only: bool,
|
||||||
@ -456,7 +454,7 @@ impl Engine {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn has_override(
|
pub(crate) fn has_override(
|
||||||
&self,
|
&self,
|
||||||
lib: &Module,
|
lib: &[&Module],
|
||||||
hash_fn: u64,
|
hash_fn: u64,
|
||||||
hash_script: u64,
|
hash_script: u64,
|
||||||
pub_only: bool,
|
pub_only: bool,
|
||||||
@ -464,8 +462,8 @@ impl Engine {
|
|||||||
// NOTE: We skip script functions for global_module and packages, and native functions for lib
|
// NOTE: We skip script functions for global_module and packages, and native functions for lib
|
||||||
|
|
||||||
// First check script-defined functions
|
// First check script-defined functions
|
||||||
lib.contains_fn(hash_script, pub_only)
|
lib.iter().any(|&m| m.contains_fn(hash_script, pub_only))
|
||||||
//|| lib.contains_fn(hash_fn, pub_only)
|
//|| lib.iter().any(|&m| m.contains_fn(hash_fn, pub_only))
|
||||||
// Then check registered functions
|
// Then check registered functions
|
||||||
//|| self.global_module.contains_fn(hash_script, pub_only)
|
//|| self.global_module.contains_fn(hash_script, pub_only)
|
||||||
|| self.global_module.contains_fn(hash_fn, pub_only)
|
|| self.global_module.contains_fn(hash_fn, pub_only)
|
||||||
@ -485,7 +483,7 @@ impl Engine {
|
|||||||
pub(crate) fn exec_fn_call(
|
pub(crate) fn exec_fn_call(
|
||||||
&self,
|
&self,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &Module,
|
lib: &[&Module],
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
hash_script: u64,
|
hash_script: u64,
|
||||||
args: &mut FnCallArgs,
|
args: &mut FnCallArgs,
|
||||||
@ -543,13 +541,14 @@ impl Engine {
|
|||||||
|
|
||||||
// Script-like function found
|
// Script-like function found
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
_ if lib.contains_fn(hash_script, pub_only)
|
_ if lib.iter().any(|&m| m.contains_fn(hash_script, pub_only))
|
||||||
//|| self.global_module.contains_fn(hash_script, pub_only)
|
//|| self.global_module.contains_fn(hash_script, pub_only)
|
||||||
|| self.packages.contains_fn(hash_script, pub_only) =>
|
|| self.packages.contains_fn(hash_script, pub_only) =>
|
||||||
{
|
{
|
||||||
// Get function
|
// Get function
|
||||||
let func = lib
|
let func = lib
|
||||||
.get_fn(hash_script, pub_only)
|
.iter()
|
||||||
|
.find_map(|&m| m.get_fn(hash_script, pub_only))
|
||||||
//.or_else(|| self.global_module.get_fn(hash_script, pub_only))
|
//.or_else(|| self.global_module.get_fn(hash_script, pub_only))
|
||||||
.or_else(|| self.packages.get_fn(hash_script, pub_only))
|
.or_else(|| self.packages.get_fn(hash_script, pub_only))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -557,8 +556,8 @@ impl Engine {
|
|||||||
if func.is_script() {
|
if func.is_script() {
|
||||||
let func = func.get_fn_def();
|
let func = func.get_fn_def();
|
||||||
|
|
||||||
let scope = &mut Scope::new();
|
let scope: &mut Scope = &mut Default::default();
|
||||||
let mods = &mut Imports::new();
|
let mods = &mut Default::default();
|
||||||
|
|
||||||
// Move captured variables into scope
|
// Move captured variables into scope
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
@ -634,6 +633,30 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Evaluate a list of statements.
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn eval_statements<'a>(
|
||||||
|
&self,
|
||||||
|
scope: &mut Scope,
|
||||||
|
mods: &mut Imports,
|
||||||
|
statements: impl IntoIterator<Item = &'a Stmt>,
|
||||||
|
lib: &[&Module],
|
||||||
|
) -> Result<(Dynamic, u64), Box<EvalAltResult>> {
|
||||||
|
let mut state = State::new();
|
||||||
|
|
||||||
|
statements
|
||||||
|
.into_iter()
|
||||||
|
.try_fold(().into(), |_, stmt| {
|
||||||
|
self.eval_stmt(scope, mods, &mut state, lib, &mut None, stmt, 0)
|
||||||
|
})
|
||||||
|
.or_else(|err| match *err {
|
||||||
|
EvalAltResult::Return(out, _) => Ok(out),
|
||||||
|
EvalAltResult::LoopBreak(_, _) => unreachable!(),
|
||||||
|
_ => Err(err),
|
||||||
|
})
|
||||||
|
.map(|v| (v, state.operations))
|
||||||
|
}
|
||||||
|
|
||||||
/// Evaluate a text string as a script - used primarily for 'eval'.
|
/// Evaluate a text string as a script - used primarily for 'eval'.
|
||||||
/// Position in `EvalAltResult` is `None` and must be set afterwards.
|
/// Position in `EvalAltResult` is `None` and must be set afterwards.
|
||||||
fn eval_script_expr(
|
fn eval_script_expr(
|
||||||
@ -641,7 +664,7 @@ impl Engine {
|
|||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
mods: &mut Imports,
|
mods: &mut Imports,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &Module,
|
lib: &[&Module],
|
||||||
script: &str,
|
script: &str,
|
||||||
_level: usize,
|
_level: usize,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
@ -658,8 +681,8 @@ impl Engine {
|
|||||||
|
|
||||||
// Compile the script text
|
// Compile the script text
|
||||||
// No optimizations because we only run it once
|
// No optimizations because we only run it once
|
||||||
let mut ast = self.compile_with_scope_and_optimization_level(
|
let ast = self.compile_with_scope_and_optimization_level(
|
||||||
&Scope::new(),
|
&Default::default(),
|
||||||
&[script],
|
&[script],
|
||||||
OptimizationLevel::None,
|
OptimizationLevel::None,
|
||||||
)?;
|
)?;
|
||||||
@ -669,11 +692,8 @@ impl Engine {
|
|||||||
return Err(ParseErrorType::WrongFnDefinition.into());
|
return Err(ParseErrorType::WrongFnDefinition.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let statements = mem::take(ast.statements_mut());
|
|
||||||
let ast = AST::new(statements, lib.clone());
|
|
||||||
|
|
||||||
// Evaluate the AST
|
// Evaluate the AST
|
||||||
let (result, operations) = self.eval_ast_with_scope_raw(scope, mods, &ast)?;
|
let (result, operations) = self.eval_statements(scope, mods, ast.statements(), lib)?;
|
||||||
|
|
||||||
state.operations += operations;
|
state.operations += operations;
|
||||||
self.inc_operations(state)?;
|
self.inc_operations(state)?;
|
||||||
@ -687,7 +707,7 @@ impl Engine {
|
|||||||
pub(crate) fn make_method_call(
|
pub(crate) fn make_method_call(
|
||||||
&self,
|
&self,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &Module,
|
lib: &[&Module],
|
||||||
name: &str,
|
name: &str,
|
||||||
hash_script: u64,
|
hash_script: u64,
|
||||||
target: &mut Target,
|
target: &mut Target,
|
||||||
@ -839,7 +859,7 @@ impl Engine {
|
|||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
mods: &mut Imports,
|
mods: &mut Imports,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &Module,
|
lib: &[&Module],
|
||||||
this_ptr: &mut Option<&mut Dynamic>,
|
this_ptr: &mut Option<&mut Dynamic>,
|
||||||
name: &str,
|
name: &str,
|
||||||
args_expr: impl AsRef<[Expr]>,
|
args_expr: impl AsRef<[Expr]>,
|
||||||
@ -984,7 +1004,7 @@ impl Engine {
|
|||||||
return Ok(false.into());
|
return Ok(false.into());
|
||||||
} else {
|
} else {
|
||||||
let hash = calc_fn_hash(empty(), fn_name, num_params as usize, empty());
|
let hash = calc_fn_hash(empty(), fn_name, num_params as usize, empty());
|
||||||
return Ok(lib.contains_fn(hash, false).into());
|
return Ok(lib.iter().any(|&m| m.contains_fn(hash, false)).into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1085,7 +1105,7 @@ impl Engine {
|
|||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
mods: &mut Imports,
|
mods: &mut Imports,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &Module,
|
lib: &[&Module],
|
||||||
this_ptr: &mut Option<&mut Dynamic>,
|
this_ptr: &mut Option<&mut Dynamic>,
|
||||||
modules: &Option<Box<ModuleRef>>,
|
modules: &Option<Box<ModuleRef>>,
|
||||||
name: &str,
|
name: &str,
|
||||||
@ -1186,8 +1206,8 @@ impl Engine {
|
|||||||
let args = args.as_mut();
|
let args = args.as_mut();
|
||||||
let fn_def = f.get_fn_def();
|
let fn_def = f.get_fn_def();
|
||||||
|
|
||||||
let new_scope = &mut Scope::new();
|
let new_scope = &mut Default::default();
|
||||||
let mods = &mut Imports::new();
|
let mods = &mut Default::default();
|
||||||
|
|
||||||
self.call_script_fn(new_scope, mods, state, lib, &mut None, fn_def, args, level)
|
self.call_script_fn(new_scope, mods, state, lib, &mut None, fn_def, args, level)
|
||||||
}
|
}
|
||||||
|
@ -50,29 +50,31 @@ pub type Locked<T> = RwLock<T>;
|
|||||||
|
|
||||||
/// Context of native Rust function call.
|
/// Context of native Rust function call.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct NativeCallContext<'e, 'm> {
|
pub struct NativeCallContext<'e, 'm, 'pm: 'm> {
|
||||||
engine: &'e Engine,
|
engine: &'e Engine,
|
||||||
lib: &'m Module,
|
lib: &'m [&'pm Module],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'e, 'm> From<(&'e Engine, &'m Module)> for NativeCallContext<'e, 'm> {
|
impl<'e, 'm, 'pm: 'm, M: AsRef<[&'pm Module]> + ?Sized> From<(&'e Engine, &'m M)>
|
||||||
fn from(value: (&'e Engine, &'m Module)) -> Self {
|
for NativeCallContext<'e, 'm, 'pm>
|
||||||
|
{
|
||||||
|
fn from(value: (&'e Engine, &'m M)) -> Self {
|
||||||
Self {
|
Self {
|
||||||
engine: value.0,
|
engine: value.0,
|
||||||
lib: value.1,
|
lib: value.1.as_ref(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'e, 'm> NativeCallContext<'e, 'm> {
|
impl<'e, 'm, 'pm> NativeCallContext<'e, 'm, 'pm> {
|
||||||
/// The current `Engine`.
|
/// The current `Engine`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn engine(&self) -> &'e Engine {
|
pub fn engine(&self) -> &'e Engine {
|
||||||
self.engine
|
self.engine
|
||||||
}
|
}
|
||||||
/// The global namespace containing definition of all script-defined functions.
|
/// The chain of namespaces containing definition of all script-defined functions.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn namespace(&self) -> &'m Module {
|
pub fn namespaces(&self) -> &'m [&'pm Module] {
|
||||||
self.lib
|
self.lib
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -184,7 +186,7 @@ impl FnPtr {
|
|||||||
.engine()
|
.engine()
|
||||||
.exec_fn_call(
|
.exec_fn_call(
|
||||||
&mut Default::default(),
|
&mut Default::default(),
|
||||||
context.namespace(),
|
context.namespaces(),
|
||||||
fn_name,
|
fn_name,
|
||||||
hash_script,
|
hash_script,
|
||||||
args.as_mut(),
|
args.as_mut(),
|
||||||
|
@ -70,7 +70,7 @@ struct State<'a> {
|
|||||||
/// An `Engine` instance for eager function evaluation.
|
/// An `Engine` instance for eager function evaluation.
|
||||||
engine: &'a Engine,
|
engine: &'a Engine,
|
||||||
/// Library of script-defined functions.
|
/// Library of script-defined functions.
|
||||||
lib: &'a Module,
|
lib: &'a [&'a Module],
|
||||||
/// Optimization level.
|
/// Optimization level.
|
||||||
optimization_level: OptimizationLevel,
|
optimization_level: OptimizationLevel,
|
||||||
}
|
}
|
||||||
@ -78,7 +78,7 @@ struct State<'a> {
|
|||||||
impl<'a> State<'a> {
|
impl<'a> State<'a> {
|
||||||
/// Create a new State.
|
/// Create a new State.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new(engine: &'a Engine, lib: &'a Module, level: OptimizationLevel) -> Self {
|
pub fn new(engine: &'a Engine, lib: &'a [&'a Module], level: OptimizationLevel) -> Self {
|
||||||
Self {
|
Self {
|
||||||
changed: false,
|
changed: false,
|
||||||
constants: vec![],
|
constants: vec![],
|
||||||
@ -615,7 +615,7 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
|
|||||||
|
|
||||||
// First search for script-defined functions (can override built-in)
|
// First search for script-defined functions (can override built-in)
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
let has_script_fn = state.lib.get_script_fn(name, args.len(), false).is_some();
|
let has_script_fn = state.lib.iter().any(|&m| m.get_script_fn(name, args.len(), false).is_some());
|
||||||
#[cfg(feature = "no_function")]
|
#[cfg(feature = "no_function")]
|
||||||
let has_script_fn = false;
|
let has_script_fn = false;
|
||||||
|
|
||||||
@ -686,7 +686,7 @@ fn optimize(
|
|||||||
statements: Vec<Stmt>,
|
statements: Vec<Stmt>,
|
||||||
engine: &Engine,
|
engine: &Engine,
|
||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
lib: &Module,
|
lib: &[&Module],
|
||||||
level: OptimizationLevel,
|
level: OptimizationLevel,
|
||||||
) -> Vec<Stmt> {
|
) -> Vec<Stmt> {
|
||||||
// If optimization level is None then skip optimizing
|
// If optimization level is None then skip optimizing
|
||||||
@ -837,7 +837,8 @@ pub fn optimize_into_ast(
|
|||||||
let pos = fn_def.body.position();
|
let pos = fn_def.body.position();
|
||||||
|
|
||||||
// Optimize the function body
|
// Optimize the function body
|
||||||
let mut body = optimize(vec![fn_def.body], engine, &Scope::new(), &lib2, level);
|
let mut body =
|
||||||
|
optimize(vec![fn_def.body], engine, &Scope::new(), &[&lib2], level);
|
||||||
|
|
||||||
// {} -> Noop
|
// {} -> Noop
|
||||||
fn_def.body = match body.pop().unwrap_or_else(|| Stmt::Noop(pos)) {
|
fn_def.body = match body.pop().unwrap_or_else(|| Stmt::Noop(pos)) {
|
||||||
@ -877,7 +878,7 @@ pub fn optimize_into_ast(
|
|||||||
match level {
|
match level {
|
||||||
OptimizationLevel::None => statements,
|
OptimizationLevel::None => statements,
|
||||||
OptimizationLevel::Simple | OptimizationLevel::Full => {
|
OptimizationLevel::Simple | OptimizationLevel::Full => {
|
||||||
optimize(statements, engine, &scope, &lib, level)
|
optimize(statements, engine, &scope, &[&lib], level)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
lib,
|
lib,
|
||||||
|
@ -53,7 +53,7 @@ impl Expression<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EvalContext<'_, '_, '_, '_, '_, '_, '_, '_> {
|
impl EvalContext<'_, '_, '_, '_, '_, '_, '_, '_, '_> {
|
||||||
/// Evaluate an expression tree.
|
/// Evaluate an expression tree.
|
||||||
///
|
///
|
||||||
/// ## WARNING - Low Level API
|
/// ## WARNING - Low Level API
|
||||||
@ -68,7 +68,7 @@ impl EvalContext<'_, '_, '_, '_, '_, '_, '_, '_> {
|
|||||||
self.scope,
|
self.scope,
|
||||||
self.mods,
|
self.mods,
|
||||||
self.state,
|
self.state,
|
||||||
self.namespace(),
|
self.namespaces(),
|
||||||
self.this_ptr,
|
self.this_ptr,
|
||||||
expr.expr(),
|
expr.expr(),
|
||||||
self.call_level(),
|
self.call_level(),
|
||||||
|
@ -270,7 +270,7 @@ fn test_closures_external() -> Result<(), Box<EvalAltResult>> {
|
|||||||
ast.retain_functions(|_, _, _| true);
|
ast.retain_functions(|_, _, _| true);
|
||||||
|
|
||||||
// Closure 'f' captures: the engine, the AST, and the curried function pointer
|
// Closure 'f' captures: the engine, the AST, and the curried function pointer
|
||||||
let f = move |x: INT| fn_ptr.call_dynamic((&engine, ast.as_ref()).into(), None, [x.into()]);
|
let f = move |x: INT| fn_ptr.call_dynamic((&engine, &[ast.as_ref()]).into(), None, [x.into()]);
|
||||||
|
|
||||||
assert_eq!(f(42)?.as_str(), Ok("hello42"));
|
assert_eq!(f(42)?.as_str(), Ok("hello42"));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user