From 527d41d0e38e19497244bf096d589ff4db1973c6 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sun, 28 Jun 2020 15:49:24 +0800 Subject: [PATCH] No modules in scope. --- RELEASES.md | 1 + src/engine.rs | 112 ++++++++++++++++++++++++++------------------------ src/module.rs | 16 ++++---- src/parser.rs | 10 +++-- 4 files changed, 75 insertions(+), 64 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 68eb31e4..494db8b5 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -13,6 +13,7 @@ Breaking changes * 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. * 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 ------------ diff --git a/src/engine.rs b/src/engine.rs index 49c5650c..516f34fb 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -4,7 +4,7 @@ use crate::any::{Dynamic, Union, Variant}; use crate::calc_fn_hash; use crate::error::ParseErrorType; 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::packages::{Package, PackageLibrary, PackagesCollection, StandardPackage}; use crate::parser::{Expr, FnAccess, ImmutableString, ReturnType, ScriptFnDef, Stmt, AST, INT}; @@ -393,6 +393,39 @@ fn default_print(s: &str) { 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, +) -> Result<&'s mut Module, Box> { + 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 fn search_scope<'s, 'a>( scope: &'s mut Scope, @@ -416,29 +449,16 @@ fn search_scope<'s, 'a>( } // Check if it is qualified - if let Some(modules) = modules.as_ref() { - // Qualified - check if the root module is directly indexed - 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 { - // 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)?; + if let Some(modules) = modules { + let module = search_imports(mods, state, modules)?; + let target = module + .get_qualified_var_mut(*hash_var) + .map_err(|err| match *err { + EvalAltResult::ErrorVariableNotFound(_, _) => Box::new( + EvalAltResult::ErrorVariableNotFound(format!("{}{}", modules, name), *pos), + ), + _ => err.new_position(*pos), + })?; // Module variables are constant Ok((target, name, ScopeEntryType::Constant, *pos)) @@ -1952,29 +1972,10 @@ impl Engine { let mut args: StaticVec<_> = arg_values.iter_mut().collect(); - let (id, root_pos) = modules.get(0); // First module - - 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)) - })? - }; + let module = search_imports(mods, state, modules)?; // 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(_, _)) => { // Then search in Rust functions self.inc_operations(state) @@ -1990,7 +1991,7 @@ impl Engine { // 3) The final hash is the XOR of the two hashes. 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, }; @@ -2009,13 +2010,18 @@ impl Engine { Ok(f) => { f.get_native_fn()(self, args.as_mut()).map_err(|err| err.new_position(*pos)) } - Err(err) - if def_val.is_some() - && matches!(*err, EvalAltResult::ErrorFunctionNotFound(_, _)) => - { - Ok(def_val.clone().unwrap()) - } - Err(err) => Err(err), + Err(err) => match *err { + EvalAltResult::ErrorFunctionNotFound(_, _) if def_val.is_some() => { + Ok(def_val.clone().unwrap()) + } + EvalAltResult::ErrorFunctionNotFound(_, _) => { + Err(Box::new(EvalAltResult::ErrorFunctionNotFound( + format!("{}{}", modules, name), + *pos, + ))) + } + _ => Err(err.new_position(*pos)), + }, } } diff --git a/src/module.rs b/src/module.rs index 37d7c988..b6645d39 100644 --- a/src/module.rs +++ b/src/module.rs @@ -218,17 +218,19 @@ impl Module { } /// 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`. pub(crate) fn get_qualified_var_mut( &mut self, - name: &str, hash_var: u64, - pos: Position, ) -> Result<&mut Dynamic, Box> { - self.all_variables - .get_mut(&hash_var) - .ok_or_else(|| Box::new(EvalAltResult::ErrorVariableNotFound(name.to_string(), pos))) + self.all_variables.get_mut(&hash_var).ok_or_else(|| { + Box::new(EvalAltResult::ErrorVariableNotFound( + String::new(), + Position::none(), + )) + }) } /// Set a script-defined function into the module. @@ -839,17 +841,17 @@ impl Module { } /// 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 hash calculated by `index_all_sub_modules`. pub(crate) fn get_qualified_fn( &mut self, - name: &str, hash_qualified_fn: u64, ) -> Result<&CallableFunction, Box> { self.all_functions.get(&hash_qualified_fn).ok_or_else(|| { Box::new(EvalAltResult::ErrorFunctionNotFound( - name.to_string(), + String::new(), Position::none(), )) }) diff --git a/src/parser.rs b/src/parser.rs index 275f0c00..14c9d038 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2016,13 +2016,13 @@ fn parse_for( ensure_not_statement_expr(input, "a boolean")?; 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)); settings.is_breakable = true; 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)))) } @@ -2209,7 +2209,8 @@ fn parse_block( settings.ensure_level_within_max_limit(state.max_expr_depth)?; 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)? { // 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)))) }