Implement namespaces chain.

This commit is contained in:
Stephen Chung
2020-10-20 10:54:32 +08:00
parent 643ecc86a3
commit 92ba7b42d5
11 changed files with 119 additions and 113 deletions

View File

@@ -10,7 +10,7 @@ use crate::error::ParseErrorType;
use crate::fn_native::{FnCallArgs, FnPtr};
use crate::module::{Module, ModuleRef};
use crate::optimize::OptimizationLevel;
use crate::parser::{Expr, ImmutableString, AST, INT};
use crate::parser::{Expr, ImmutableString, Stmt, INT};
use crate::result::EvalAltResult;
use crate::scope::Scope;
use crate::stdlib::ops::Deref;
@@ -180,7 +180,7 @@ impl Engine {
pub(crate) fn call_native_fn(
&self,
state: &mut State,
lib: &Module,
lib: &[&Module],
fn_name: &str,
hash_fn: u64,
args: &mut FnCallArgs,
@@ -345,7 +345,7 @@ impl Engine {
scope: &mut Scope,
mods: &mut Imports,
state: &mut State,
lib: &Module,
lib: &[&Module],
this_ptr: &mut Option<&mut Dynamic>,
fn_def: &ScriptFnDef,
args: &mut FnCallArgs,
@@ -382,17 +382,15 @@ impl Engine {
);
// 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 {
if lib.is_empty() {
// In the special case of the main script not defining any function
env_lib
} else {
lib_merged = lib.clone();
lib_merged.merge(env_lib);
&lib_merged
lib_merged = Default::default();
lib_merged.push(env_lib.as_ref());
if !lib.is_empty() {
lib_merged.extend(lib.iter().cloned());
}
lib_merged.as_ref()
} else {
lib
};
@@ -433,7 +431,7 @@ impl Engine {
#[inline]
pub(crate) fn has_override_by_name_and_arguments(
&self,
lib: &Module,
lib: &[&Module],
name: &str,
arg_types: impl AsRef<[TypeId]>,
pub_only: bool,
@@ -456,7 +454,7 @@ impl Engine {
#[inline(always)]
pub(crate) fn has_override(
&self,
lib: &Module,
lib: &[&Module],
hash_fn: u64,
hash_script: u64,
pub_only: bool,
@@ -464,8 +462,8 @@ impl Engine {
// NOTE: We skip script functions for global_module and packages, and native functions for lib
// First check script-defined functions
lib.contains_fn(hash_script, pub_only)
//|| lib.contains_fn(hash_fn, pub_only)
lib.iter().any(|&m| m.contains_fn(hash_script, pub_only))
//|| lib.iter().any(|&m| m.contains_fn(hash_fn, pub_only))
// Then check registered functions
//|| self.global_module.contains_fn(hash_script, pub_only)
|| self.global_module.contains_fn(hash_fn, pub_only)
@@ -485,7 +483,7 @@ impl Engine {
pub(crate) fn exec_fn_call(
&self,
state: &mut State,
lib: &Module,
lib: &[&Module],
fn_name: &str,
hash_script: u64,
args: &mut FnCallArgs,
@@ -543,13 +541,14 @@ impl Engine {
// Script-like function found
#[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.packages.contains_fn(hash_script, pub_only) =>
{
// Get function
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.packages.get_fn(hash_script, pub_only))
.unwrap();
@@ -557,8 +556,8 @@ impl Engine {
if func.is_script() {
let func = func.get_fn_def();
let scope = &mut Scope::new();
let mods = &mut Imports::new();
let scope: &mut Scope = &mut Default::default();
let mods = &mut Default::default();
// Move captured variables into scope
#[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'.
/// Position in `EvalAltResult` is `None` and must be set afterwards.
fn eval_script_expr(
@@ -641,7 +664,7 @@ impl Engine {
scope: &mut Scope,
mods: &mut Imports,
state: &mut State,
lib: &Module,
lib: &[&Module],
script: &str,
_level: usize,
) -> Result<Dynamic, Box<EvalAltResult>> {
@@ -658,8 +681,8 @@ impl Engine {
// Compile the script text
// No optimizations because we only run it once
let mut ast = self.compile_with_scope_and_optimization_level(
&Scope::new(),
let ast = self.compile_with_scope_and_optimization_level(
&Default::default(),
&[script],
OptimizationLevel::None,
)?;
@@ -669,11 +692,8 @@ impl Engine {
return Err(ParseErrorType::WrongFnDefinition.into());
}
let statements = mem::take(ast.statements_mut());
let ast = AST::new(statements, lib.clone());
// 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;
self.inc_operations(state)?;
@@ -687,7 +707,7 @@ impl Engine {
pub(crate) fn make_method_call(
&self,
state: &mut State,
lib: &Module,
lib: &[&Module],
name: &str,
hash_script: u64,
target: &mut Target,
@@ -839,7 +859,7 @@ impl Engine {
scope: &mut Scope,
mods: &mut Imports,
state: &mut State,
lib: &Module,
lib: &[&Module],
this_ptr: &mut Option<&mut Dynamic>,
name: &str,
args_expr: impl AsRef<[Expr]>,
@@ -984,7 +1004,7 @@ impl Engine {
return Ok(false.into());
} else {
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,
mods: &mut Imports,
state: &mut State,
lib: &Module,
lib: &[&Module],
this_ptr: &mut Option<&mut Dynamic>,
modules: &Option<Box<ModuleRef>>,
name: &str,
@@ -1186,8 +1206,8 @@ impl Engine {
let args = args.as_mut();
let fn_def = f.get_fn_def();
let new_scope = &mut Scope::new();
let mods = &mut Imports::new();
let new_scope = &mut Default::default();
let mods = &mut Default::default();
self.call_script_fn(new_scope, mods, state, lib, &mut None, fn_def, args, level)
}