diff --git a/src/engine.rs b/src/engine.rs index 4dc116ed..4a8424f4 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -501,35 +501,24 @@ impl> From for Target<'_> { pub struct GlobalRuntimeState { /// Stack of module names. // - // # Implementation Notes - // // We cannot use Cow here because `eval` may load a [module][Module] and // the module name will live beyond the AST of the eval script text. keys: StaticVec, - /// Stack of imported modules. + /// Stack of imported [modules][Module]. modules: StaticVec>, - /// Source of the current context. pub source: Option, /// 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>, - /// 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>>>, @@ -775,13 +764,18 @@ pub type FnResolutionCache = BTreeMap>>; /// 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, @@ -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()); } diff --git a/src/func/call.rs b/src/func/call.rs index 55e9e9e1..fd20e4ad 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -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) } }