Add rewind_scope to eval_stmt.

This commit is contained in:
Stephen Chung 2021-12-30 08:57:23 +08:00
parent 3488dbe74b
commit be4ae6e763
2 changed files with 28 additions and 38 deletions

View File

@ -501,35 +501,24 @@ impl<T: Into<Dynamic>> From<T> for Target<'_> {
pub struct GlobalRuntimeState {
/// Stack of module names.
//
// # Implementation Notes
//
// We cannot use Cow<str> here because `eval` may load a [module][Module] and
// the module name will live beyond the AST of the eval script text.
keys: StaticVec<Identifier>,
/// Stack of imported modules.
/// Stack of imported [modules][Module].
modules: StaticVec<Shared<Module>>,
/// Source of the current context.
pub source: Option<Identifier>,
/// Number of operations performed.
pub num_operations: u64,
/// Number of modules loaded.
pub num_modules_loaded: usize,
/// Function call hashes to index getters and setters.
///
/// Not available under `no_index` and `no_object`.
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
fn_hash_indexing: (u64, u64),
/// Embedded module resolver.
///
/// Not available under `no_module`.
/// Embedded [module][Module] resolver.
#[cfg(not(feature = "no_module"))]
pub embedded_module_resolver: Option<Shared<crate::module::resolvers::StaticModuleResolver>>,
/// Cache of globally-defined constants.
///
/// Not available under `no_module` and `no_function`.
#[cfg(not(feature = "no_module"))]
#[cfg(not(feature = "no_function"))]
constants: Option<Shared<crate::Locked<BTreeMap<Identifier, Dynamic>>>>,
@ -775,13 +764,18 @@ pub type FnResolutionCache = BTreeMap<u64, Option<Box<FnResolutionCacheEntry>>>;
/// Exported under the `internals` feature only.
#[derive(Debug, Clone)]
pub struct EvalState {
/// Force a [`Scope`] search by name.
///
/// Normally, access to variables are parsed with a relative offset into the [`Scope`] to avoid a lookup.
///
/// In some situation, e.g. after running an `eval` statement, or after a custom syntax statement,
/// subsequent offsets may become mis-aligned.
/// When that happens, this flag is turned on to force a [`Scope`] search by name.
///
/// When that happens, this flag is turned on.
pub always_search_scope: bool,
/// Level of the current scope. The global (root) level is zero, a new block (or function call)
/// is one level higher, and so on.
/// Level of the current scope.
///
/// The global (root) level is zero, a new block (or function call) is one level higher, and so on.
pub scope_level: usize,
/// Stack of function resolution caches.
fn_resolution_caches: StaticVec<FnResolutionCache>,
@ -798,12 +792,6 @@ impl EvalState {
fn_resolution_caches: StaticVec::new_const(),
}
}
/// Is the state currently at global (root) level?
#[inline(always)]
#[must_use]
pub const fn is_global(&self) -> bool {
self.scope_level == 0
}
/// Get the number of function resolution cache(s) in the stack.
#[inline(always)]
#[must_use]
@ -2465,7 +2453,16 @@ impl Engine {
let result = statements.iter().try_fold(Dynamic::UNIT, |_, stmt| {
let _mods_len = global.num_imported_modules();
let r = self.eval_stmt(scope, global, state, lib, this_ptr, stmt, level)?;
let r = self.eval_stmt(
scope,
global,
state,
lib,
this_ptr,
stmt,
restore_orig_state,
level,
)?;
#[cfg(not(feature = "no_module"))]
if matches!(stmt, Stmt::Import(_, _, _)) {
@ -2593,6 +2590,7 @@ impl Engine {
lib: &[&Module],
this_ptr: &mut Option<&mut Dynamic>,
stmt: &Stmt,
rewind_scope: bool,
level: usize,
) -> RhaiResult {
#[cfg(not(feature = "unchecked"))]
@ -3119,10 +3117,14 @@ impl Engine {
.eval_expr(scope, global, state, lib, this_ptr, expr, level)?
.flatten();
let (var_name, _alias): (Cow<'_, str>, _) = if state.is_global() {
let (var_name, _alias): (Cow<'_, str>, _) = if !rewind_scope {
#[cfg(not(feature = "no_function"))]
#[cfg(not(feature = "no_module"))]
if entry_type == AccessMode::ReadOnly && lib.iter().any(|&m| !m.is_empty()) {
if state.scope_level == 0
&& entry_type == AccessMode::ReadOnly
&& lib.iter().any(|&m| !m.is_empty())
{
// Add a global constant if at top level and there are functions
global.set_constant(name.clone(), value.clone());
}

View File

@ -1345,19 +1345,7 @@ impl Engine {
return Ok(Dynamic::UNIT);
}
// Backup the original state
let orig_scope_level = state.scope_level;
// Scope level is set to zero in order to retain all variables
state.scope_level = 0;
// Evaluate the AST
let result = self.eval_global_statements(scope, global, state, statements, lib, level);
// Restore original state
state.scope_level = orig_scope_level;
// Return result
result
self.eval_global_statements(scope, global, state, statements, lib, level)
}
}