Reverse EvalStateData.

This commit is contained in:
Stephen Chung 2021-12-28 12:19:20 +08:00
parent 280010c427
commit 5b667a69b7
4 changed files with 15 additions and 37 deletions

View File

@ -771,10 +771,10 @@ pub struct FnResolutionCacheEntry {
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
pub type FnResolutionCache = BTreeMap<u64, Option<Box<FnResolutionCacheEntry>>>; pub type FnResolutionCache = BTreeMap<u64, Option<Box<FnResolutionCacheEntry>>>;
/// _(internals)_ A type that holds all volatile evaluation states data. /// _(internals)_ A type that holds all the current states of the [`Engine`].
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default, Hash)] #[derive(Debug, Clone)]
pub struct EvalStateData { pub struct EvalState {
/// 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.
@ -783,24 +783,6 @@ pub struct EvalStateData {
/// Level of the current scope. The global (root) level is zero, a new block (or function call) /// Level of the current scope. The global (root) level is zero, a new block (or function call)
/// is one level higher, and so on. /// is one level higher, and so on.
pub scope_level: usize, pub scope_level: usize,
}
impl EvalStateData {
/// Create a new [`EvalStateData`].
pub const fn new() -> Self {
Self {
always_search_scope: false,
scope_level: 0,
}
}
}
/// _(internals)_ A type that holds all the current states of the [`Engine`].
/// Exported under the `internals` feature only.
#[derive(Debug, Clone)]
pub struct EvalState {
/// Volatile states data.
pub data: EvalStateData,
/// Stack of function resolution caches. /// Stack of function resolution caches.
fn_resolution_caches: StaticVec<FnResolutionCache>, fn_resolution_caches: StaticVec<FnResolutionCache>,
} }
@ -811,7 +793,8 @@ impl EvalState {
#[must_use] #[must_use]
pub const fn new() -> Self { pub const fn new() -> Self {
Self { Self {
data: EvalStateData::new(), always_search_scope: false,
scope_level: 0,
fn_resolution_caches: StaticVec::new_const(), fn_resolution_caches: StaticVec::new_const(),
} }
} }
@ -819,7 +802,7 @@ impl EvalState {
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub const fn is_global(&self) -> bool { pub const fn is_global(&self) -> bool {
self.data.scope_level == 0 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)]
@ -1159,7 +1142,7 @@ impl Engine {
let root = &namespace[0].name; let root = &namespace[0].name;
// Qualified - check if the root module is directly indexed // Qualified - check if the root module is directly indexed
let index = if state.data.always_search_scope { let index = if state.always_search_scope {
None None
} else { } else {
namespace.index() namespace.index()
@ -1284,7 +1267,7 @@ impl Engine {
Err(ERR::ErrorUnboundThis(*pos).into()) Err(ERR::ErrorUnboundThis(*pos).into())
} }
} }
_ if state.data.always_search_scope => (0, expr.position()), _ if state.always_search_scope => (0, expr.position()),
Expr::Variable(Some(i), pos, _) => (i.get() as usize, *pos), Expr::Variable(Some(i), pos, _) => (i.get() as usize, *pos),
Expr::Variable(None, pos, v) => (v.0.map(NonZeroUsize::get).unwrap_or(0), *pos), Expr::Variable(None, pos, v) => (v.0.map(NonZeroUsize::get).unwrap_or(0), *pos),
_ => unreachable!("Expr::Variable expected, but gets {:?}", expr), _ => unreachable!("Expr::Variable expected, but gets {:?}", expr),
@ -2471,13 +2454,13 @@ impl Engine {
return Ok(Dynamic::UNIT); return Ok(Dynamic::UNIT);
} }
let orig_always_search_scope = state.data.always_search_scope; let orig_always_search_scope = state.always_search_scope;
let orig_scope_len = scope.len(); let orig_scope_len = scope.len();
let orig_mods_len = global.num_imported_modules(); let orig_mods_len = global.num_imported_modules();
let orig_fn_resolution_caches_len = state.fn_resolution_caches_len(); let orig_fn_resolution_caches_len = state.fn_resolution_caches_len();
if rewind_scope { if rewind_scope {
state.data.scope_level += 1; state.scope_level += 1;
} }
let result = statements.iter().try_fold(Dynamic::UNIT, |_, stmt| { let result = statements.iter().try_fold(Dynamic::UNIT, |_, stmt| {
@ -2517,14 +2500,14 @@ impl Engine {
if rewind_scope { if rewind_scope {
scope.rewind(orig_scope_len); scope.rewind(orig_scope_len);
state.data.scope_level -= 1; state.scope_level -= 1;
} }
if restore_orig_state { if restore_orig_state {
global.truncate_modules(orig_mods_len); global.truncate_modules(orig_mods_len);
// The impact of new local variables goes away at the end of a block // The impact of new local variables goes away at the end of a block
// because any new variables introduced will go out of scope // because any new variables introduced will go out of scope
state.data.always_search_scope = orig_always_search_scope; state.always_search_scope = orig_always_search_scope;
} }
result result

View File

@ -1046,7 +1046,7 @@ impl Engine {
// IMPORTANT! If the eval defines new variables in the current scope, // IMPORTANT! If the eval defines new variables in the current scope,
// all variable offsets from this point on will be mis-aligned. // all variable offsets from this point on will be mis-aligned.
if scope.len() != orig_scope_len { if scope.len() != orig_scope_len {
state.data.always_search_scope = true; state.always_search_scope = true;
} }
return result.map_err(|err| { return result.map_err(|err| {

View File

@ -3,7 +3,7 @@
use super::call::FnCallArgs; use super::call::FnCallArgs;
use crate::ast::ScriptFnDef; use crate::ast::ScriptFnDef;
use crate::engine::{EvalState, EvalStateData, GlobalRuntimeState}; use crate::engine::{EvalState, GlobalRuntimeState};
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime; use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
use crate::{Dynamic, Engine, Module, Position, RhaiError, RhaiResult, Scope, StaticVec, ERR}; use crate::{Dynamic, Engine, Module, Position, RhaiError, RhaiResult, Scope, StaticVec, ERR};
use std::mem; use std::mem;
@ -91,8 +91,6 @@ impl Engine {
// Merge in encapsulated environment, if any // Merge in encapsulated environment, if any
let mut lib_merged = StaticVec::with_capacity(lib.len() + 1); let mut lib_merged = StaticVec::with_capacity(lib.len() + 1);
let orig_fn_resolution_caches_len = state.fn_resolution_caches_len(); let orig_fn_resolution_caches_len = state.fn_resolution_caches_len();
let orig_states_data = state.data;
state.data = EvalStateData::new();
let lib = if let Some(ref fn_lib) = fn_def.lib { let lib = if let Some(ref fn_lib) = fn_def.lib {
if fn_lib.is_empty() { if fn_lib.is_empty() {
@ -160,7 +158,6 @@ impl Engine {
global.truncate_modules(orig_mods_len); global.truncate_modules(orig_mods_len);
// Restore state // Restore state
state.data = orig_states_data;
state.rewind_fn_resolution_caches(orig_fn_resolution_caches_len); state.rewind_fn_resolution_caches(orig_fn_resolution_caches_len);
result result

View File

@ -241,9 +241,7 @@ pub use ast::{
pub use ast::FloatWrapper; pub use ast::FloatWrapper;
#[cfg(feature = "internals")] #[cfg(feature = "internals")]
pub use engine::{ pub use engine::{EvalState, FnResolutionCache, FnResolutionCacheEntry, GlobalRuntimeState};
EvalState, EvalStateData, FnResolutionCache, FnResolutionCacheEntry, GlobalRuntimeState,
};
#[cfg(feature = "internals")] #[cfg(feature = "internals")]
pub use module::Namespace; pub use module::Namespace;