Add rewind_scope to eval_stmt.
This commit is contained in:
parent
3488dbe74b
commit
be4ae6e763
@ -501,35 +501,24 @@ impl<T: Into<Dynamic>> From<T> for Target<'_> {
|
|||||||
pub struct GlobalRuntimeState {
|
pub struct GlobalRuntimeState {
|
||||||
/// Stack of module names.
|
/// Stack of module names.
|
||||||
//
|
//
|
||||||
// # Implementation Notes
|
|
||||||
//
|
|
||||||
// We cannot use Cow<str> here because `eval` may load a [module][Module] and
|
// 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.
|
// the module name will live beyond the AST of the eval script text.
|
||||||
keys: StaticVec<Identifier>,
|
keys: StaticVec<Identifier>,
|
||||||
/// Stack of imported modules.
|
/// Stack of imported [modules][Module].
|
||||||
modules: StaticVec<Shared<Module>>,
|
modules: StaticVec<Shared<Module>>,
|
||||||
|
|
||||||
/// Source of the current context.
|
/// Source of the current context.
|
||||||
pub source: Option<Identifier>,
|
pub source: Option<Identifier>,
|
||||||
/// Number of operations performed.
|
/// Number of operations performed.
|
||||||
pub num_operations: u64,
|
pub num_operations: u64,
|
||||||
/// Number of modules loaded.
|
/// Number of modules loaded.
|
||||||
pub num_modules_loaded: usize,
|
pub num_modules_loaded: usize,
|
||||||
|
|
||||||
/// Function call hashes to index getters and setters.
|
/// 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")))]
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
fn_hash_indexing: (u64, u64),
|
fn_hash_indexing: (u64, u64),
|
||||||
/// Embedded module resolver.
|
/// Embedded [module][Module] resolver.
|
||||||
///
|
|
||||||
/// Not available under `no_module`.
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub embedded_module_resolver: Option<Shared<crate::module::resolvers::StaticModuleResolver>>,
|
pub embedded_module_resolver: Option<Shared<crate::module::resolvers::StaticModuleResolver>>,
|
||||||
|
|
||||||
/// Cache of globally-defined constants.
|
/// Cache of globally-defined constants.
|
||||||
///
|
|
||||||
/// Not available under `no_module` and `no_function`.
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
constants: Option<Shared<crate::Locked<BTreeMap<Identifier, Dynamic>>>>,
|
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.
|
/// Exported under the `internals` feature only.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct EvalState {
|
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.
|
/// 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,
|
/// In some situation, e.g. after running an `eval` statement, or after a custom syntax statement,
|
||||||
/// subsequent offsets may become mis-aligned.
|
/// 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,
|
pub always_search_scope: bool,
|
||||||
/// Level of the current scope. The global (root) level is zero, a new block (or function call)
|
/// Level of the current scope.
|
||||||
/// is one level higher, and so on.
|
///
|
||||||
|
/// The global (root) level is zero, a new block (or function call) is one level higher, and so on.
|
||||||
pub scope_level: usize,
|
pub scope_level: usize,
|
||||||
/// Stack of function resolution caches.
|
/// Stack of function resolution caches.
|
||||||
fn_resolution_caches: StaticVec<FnResolutionCache>,
|
fn_resolution_caches: StaticVec<FnResolutionCache>,
|
||||||
@ -798,12 +792,6 @@ impl EvalState {
|
|||||||
fn_resolution_caches: StaticVec::new_const(),
|
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.
|
/// Get the number of function resolution cache(s) in the stack.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -2465,7 +2453,16 @@ impl Engine {
|
|||||||
let result = statements.iter().try_fold(Dynamic::UNIT, |_, stmt| {
|
let result = statements.iter().try_fold(Dynamic::UNIT, |_, stmt| {
|
||||||
let _mods_len = global.num_imported_modules();
|
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"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
if matches!(stmt, Stmt::Import(_, _, _)) {
|
if matches!(stmt, Stmt::Import(_, _, _)) {
|
||||||
@ -2593,6 +2590,7 @@ impl Engine {
|
|||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
this_ptr: &mut Option<&mut Dynamic>,
|
this_ptr: &mut Option<&mut Dynamic>,
|
||||||
stmt: &Stmt,
|
stmt: &Stmt,
|
||||||
|
rewind_scope: bool,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> RhaiResult {
|
) -> RhaiResult {
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
@ -3119,10 +3117,14 @@ impl Engine {
|
|||||||
.eval_expr(scope, global, state, lib, this_ptr, expr, level)?
|
.eval_expr(scope, global, state, lib, this_ptr, expr, level)?
|
||||||
.flatten();
|
.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_function"))]
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[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());
|
global.set_constant(name.clone(), value.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1345,19 +1345,7 @@ impl Engine {
|
|||||||
return Ok(Dynamic::UNIT);
|
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
|
// Evaluate the AST
|
||||||
let result = self.eval_global_statements(scope, global, state, statements, lib, level);
|
self.eval_global_statements(scope, global, state, statements, lib, level)
|
||||||
|
|
||||||
// Restore original state
|
|
||||||
state.scope_level = orig_scope_level;
|
|
||||||
|
|
||||||
// Return result
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user