No modules in scope.

This commit is contained in:
Stephen Chung 2020-06-28 15:49:24 +08:00
parent aac04a5e53
commit 527d41d0e3
4 changed files with 75 additions and 64 deletions

View File

@ -13,6 +13,7 @@ Breaking changes
* Functions defined in script now differentiates between using method-call style and normal function-call style. * Functions defined in script now differentiates between using method-call style and normal function-call style.
The method-call style will bind the object to the `this` parameter instead of consuming the first parameter. The method-call style will bind the object to the `this` parameter instead of consuming the first parameter.
* Imported modules are no longer stored in the `Scope`. `Scope::push_module` is removed. * Imported modules are no longer stored in the `Scope`. `Scope::push_module` is removed.
Therefore, cannot rely on module imports to persist across invocations using a `Scope`.
New features New features
------------ ------------

View File

@ -4,7 +4,7 @@ use crate::any::{Dynamic, Union, Variant};
use crate::calc_fn_hash; use crate::calc_fn_hash;
use crate::error::ParseErrorType; use crate::error::ParseErrorType;
use crate::fn_native::{CallableFunction, Callback, FnCallArgs, FnPtr}; use crate::fn_native::{CallableFunction, Callback, FnCallArgs, FnPtr};
use crate::module::{resolvers, Module, ModuleResolver}; use crate::module::{resolvers, Module, ModuleRef, ModuleResolver};
use crate::optimize::OptimizationLevel; use crate::optimize::OptimizationLevel;
use crate::packages::{Package, PackageLibrary, PackagesCollection, StandardPackage}; use crate::packages::{Package, PackageLibrary, PackagesCollection, StandardPackage};
use crate::parser::{Expr, FnAccess, ImmutableString, ReturnType, ScriptFnDef, Stmt, AST, INT}; use crate::parser::{Expr, FnAccess, ImmutableString, ReturnType, ScriptFnDef, Stmt, AST, INT};
@ -393,6 +393,39 @@ fn default_print(s: &str) {
println!("{}", s); println!("{}", s);
} }
/// Search for a module within an imports stack.
/// Position in `EvalAltResult` is None and must be set afterwards.
fn search_imports<'s>(
mods: &'s mut Imports,
state: &mut State,
modules: &Box<ModuleRef>,
) -> Result<&'s mut Module, Box<EvalAltResult>> {
let (root, root_pos) = modules.get(0);
// Qualified - check if the root module is directly indexed
let index = if state.always_search {
None
} else {
modules.index()
};
Ok(if let Some(index) = index {
let offset = mods.len() - index.get();
&mut mods.get_mut(offset).unwrap().1
} else {
mods.iter_mut()
.rev()
.find(|(n, _)| n == root)
.map(|(_, m)| m)
.ok_or_else(|| {
Box::new(EvalAltResult::ErrorModuleNotFound(
root.to_string(),
*root_pos,
))
})?
})
}
/// Search for a variable within the scope /// Search for a variable within the scope
fn search_scope<'s, 'a>( fn search_scope<'s, 'a>(
scope: &'s mut Scope, scope: &'s mut Scope,
@ -416,29 +449,16 @@ fn search_scope<'s, 'a>(
} }
// Check if it is qualified // Check if it is qualified
if let Some(modules) = modules.as_ref() { if let Some(modules) = modules {
// Qualified - check if the root module is directly indexed let module = search_imports(mods, state, modules)?;
let index = if state.always_search { let target = module
None .get_qualified_var_mut(*hash_var)
} else { .map_err(|err| match *err {
modules.index() EvalAltResult::ErrorVariableNotFound(_, _) => Box::new(
}; EvalAltResult::ErrorVariableNotFound(format!("{}{}", modules, name), *pos),
),
let module = if let Some(index) = index { _ => err.new_position(*pos),
let offset = mods.len() - index.get(); })?;
&mut mods.get_mut(offset).unwrap().1
} else {
// Find the root module in the scope
let (id, root_pos) = modules.get(0);
mods.iter_mut()
.rev()
.find(|(n, _)| n == id)
.map(|(_, m)| m)
.ok_or_else(|| Box::new(EvalAltResult::ErrorModuleNotFound(id.into(), *root_pos)))?
};
let target = module.get_qualified_var_mut(name, *hash_var, *pos)?;
// Module variables are constant // Module variables are constant
Ok((target, name, ScopeEntryType::Constant, *pos)) Ok((target, name, ScopeEntryType::Constant, *pos))
@ -1952,29 +1972,10 @@ impl Engine {
let mut args: StaticVec<_> = arg_values.iter_mut().collect(); let mut args: StaticVec<_> = arg_values.iter_mut().collect();
let (id, root_pos) = modules.get(0); // First module let module = search_imports(mods, state, modules)?;
let index = if state.always_search {
None
} else {
modules.index()
};
let module = if let Some(index) = index {
let offset = mods.len() - index.get();
&mut mods.get_mut(offset).unwrap().1
} else {
mods.iter_mut()
.rev()
.find(|(n, _)| n == id)
.map(|(_, m)| m)
.ok_or_else(|| {
Box::new(EvalAltResult::ErrorModuleNotFound(id.into(), *root_pos))
})?
};
// First search in script-defined functions (can override built-in) // First search in script-defined functions (can override built-in)
let func = match module.get_qualified_fn(name, *hash_script) { let func = match module.get_qualified_fn(*hash_script) {
Err(err) if matches!(*err, EvalAltResult::ErrorFunctionNotFound(_, _)) => { Err(err) if matches!(*err, EvalAltResult::ErrorFunctionNotFound(_, _)) => {
// Then search in Rust functions // Then search in Rust functions
self.inc_operations(state) self.inc_operations(state)
@ -1990,7 +1991,7 @@ impl Engine {
// 3) The final hash is the XOR of the two hashes. // 3) The final hash is the XOR of the two hashes.
let hash_qualified_fn = *hash_script ^ hash_fn_args; let hash_qualified_fn = *hash_script ^ hash_fn_args;
module.get_qualified_fn(name, hash_qualified_fn) module.get_qualified_fn(hash_qualified_fn)
} }
r => r, r => r,
}; };
@ -2009,13 +2010,18 @@ impl Engine {
Ok(f) => { Ok(f) => {
f.get_native_fn()(self, args.as_mut()).map_err(|err| err.new_position(*pos)) f.get_native_fn()(self, args.as_mut()).map_err(|err| err.new_position(*pos))
} }
Err(err) Err(err) => match *err {
if def_val.is_some() EvalAltResult::ErrorFunctionNotFound(_, _) if def_val.is_some() => {
&& matches!(*err, EvalAltResult::ErrorFunctionNotFound(_, _)) => Ok(def_val.clone().unwrap())
{ }
Ok(def_val.clone().unwrap()) EvalAltResult::ErrorFunctionNotFound(_, _) => {
} Err(Box::new(EvalAltResult::ErrorFunctionNotFound(
Err(err) => Err(err), format!("{}{}", modules, name),
*pos,
)))
}
_ => Err(err.new_position(*pos)),
},
} }
} }

View File

@ -218,17 +218,19 @@ impl Module {
} }
/// Get a mutable reference to a modules-qualified variable. /// Get a mutable reference to a modules-qualified variable.
/// Name and Position in `EvalAltResult` are None and must be set afterwards.
/// ///
/// The `u64` hash is calculated by the function `crate::calc_fn_hash`. /// The `u64` hash is calculated by the function `crate::calc_fn_hash`.
pub(crate) fn get_qualified_var_mut( pub(crate) fn get_qualified_var_mut(
&mut self, &mut self,
name: &str,
hash_var: u64, hash_var: u64,
pos: Position,
) -> Result<&mut Dynamic, Box<EvalAltResult>> { ) -> Result<&mut Dynamic, Box<EvalAltResult>> {
self.all_variables self.all_variables.get_mut(&hash_var).ok_or_else(|| {
.get_mut(&hash_var) Box::new(EvalAltResult::ErrorVariableNotFound(
.ok_or_else(|| Box::new(EvalAltResult::ErrorVariableNotFound(name.to_string(), pos))) String::new(),
Position::none(),
))
})
} }
/// Set a script-defined function into the module. /// Set a script-defined function into the module.
@ -839,17 +841,17 @@ impl Module {
} }
/// Get a modules-qualified function. /// Get a modules-qualified function.
/// Name and Position in `EvalAltResult` are None and must be set afterwards.
/// ///
/// The `u64` hash is calculated by the function `crate::calc_fn_hash` and must match /// The `u64` hash is calculated by the function `crate::calc_fn_hash` and must match
/// the hash calculated by `index_all_sub_modules`. /// the hash calculated by `index_all_sub_modules`.
pub(crate) fn get_qualified_fn( pub(crate) fn get_qualified_fn(
&mut self, &mut self,
name: &str,
hash_qualified_fn: u64, hash_qualified_fn: u64,
) -> Result<&CallableFunction, Box<EvalAltResult>> { ) -> Result<&CallableFunction, Box<EvalAltResult>> {
self.all_functions.get(&hash_qualified_fn).ok_or_else(|| { self.all_functions.get(&hash_qualified_fn).ok_or_else(|| {
Box::new(EvalAltResult::ErrorFunctionNotFound( Box::new(EvalAltResult::ErrorFunctionNotFound(
name.to_string(), String::new(),
Position::none(), Position::none(),
)) ))
}) })

View File

@ -2016,13 +2016,13 @@ fn parse_for(
ensure_not_statement_expr(input, "a boolean")?; ensure_not_statement_expr(input, "a boolean")?;
let expr = parse_expr(input, state, settings.level_up())?; let expr = parse_expr(input, state, settings.level_up())?;
let prev_len = state.stack.len(); let prev_stack_len = state.stack.len();
state.stack.push((name.clone(), ScopeEntryType::Normal)); state.stack.push((name.clone(), ScopeEntryType::Normal));
settings.is_breakable = true; settings.is_breakable = true;
let body = parse_block(input, state, settings.level_up())?; let body = parse_block(input, state, settings.level_up())?;
state.stack.truncate(prev_len); state.stack.truncate(prev_stack_len);
Ok(Stmt::For(Box::new((name, expr, body)))) Ok(Stmt::For(Box::new((name, expr, body))))
} }
@ -2209,7 +2209,8 @@ fn parse_block(
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
let mut statements = StaticVec::new(); let mut statements = StaticVec::new();
let prev_len = state.stack.len(); let prev_stack_len = state.stack.len();
let prev_mods_len = state.modules.len();
while !match_token(input, Token::RightBrace)? { while !match_token(input, Token::RightBrace)? {
// Parse statements inside the block // Parse statements inside the block
@ -2249,7 +2250,8 @@ fn parse_block(
} }
} }
state.stack.truncate(prev_len); state.stack.truncate(prev_stack_len);
state.modules.truncate(prev_mods_len);
Ok(Stmt::Block(Box::new((statements, settings.pos)))) Ok(Stmt::Block(Box::new((statements, settings.pos))))
} }