Make caches optional for EvalContext.

This commit is contained in:
Stephen Chung 2022-04-16 23:32:14 +08:00
parent 855cb76246
commit daf73d5341
10 changed files with 61 additions and 67 deletions

View File

@ -1,6 +1,7 @@
//! Module implementing custom syntax for [`Engine`].
use crate::ast::Expr;
use crate::eval::Caches;
use crate::func::native::SendSync;
use crate::parser::ParseResult;
use crate::tokenizer::{is_valid_identifier, Token};
@ -130,7 +131,7 @@ impl Deref for Expression<'_> {
}
}
impl EvalContext<'_, '_, '_, '_, '_, '_, '_, '_, '_> {
impl EvalContext<'_, '_, '_, '_, '_, '_, '_, '_> {
/// Evaluate an [expression tree][Expression].
///
/// # WARNING - Low Level API
@ -138,10 +139,18 @@ impl EvalContext<'_, '_, '_, '_, '_, '_, '_, '_, '_> {
/// This function is very low level. It evaluates an expression from an [`AST`][crate::AST].
#[inline(always)]
pub fn eval_expression_tree(&mut self, expr: &Expression) -> RhaiResult {
let mut caches;
self.engine.eval_expr(
self.scope,
self.global,
self.caches,
match self.caches.as_mut() {
Some(c) => c,
None => {
caches = Caches::new();
&mut caches
}
},
self.lib,
self.this_ptr,
expr,

View File

@ -155,7 +155,7 @@ impl Engine {
if !_parent_options.contains(ASTFlags::BREAK) =>
{
#[cfg(feature = "debugging")]
self.run_debugger(scope, global, caches, lib, this_ptr, _parent, level)?;
self.run_debugger(scope, global, lib, this_ptr, _parent, level)?;
let mut idx_val_for_setter = idx_val.clone();
let idx_pos = x.lhs.start_position();
@ -198,7 +198,7 @@ impl Engine {
// xxx[rhs] op= new_val
_ if new_val.is_some() => {
#[cfg(feature = "debugging")]
self.run_debugger(scope, global, caches, lib, this_ptr, _parent, level)?;
self.run_debugger(scope, global, lib, this_ptr, _parent, level)?;
let ((new_val, new_pos), (op_info, op_pos)) = new_val.expect("`Some`");
let mut idx_val2 = idx_val.clone();
@ -260,7 +260,7 @@ impl Engine {
// xxx[rhs]
_ => {
#[cfg(feature = "debugging")]
self.run_debugger(scope, global, caches, lib, this_ptr, _parent, level)?;
self.run_debugger(scope, global, lib, this_ptr, _parent, level)?;
self.get_indexed_mut(
global, caches, lib, target, idx_val, pos, false, true, level,
@ -279,9 +279,8 @@ impl Engine {
let call_args = &mut idx_val.into_fn_call_args();
#[cfg(feature = "debugging")]
let reset_debugger = self.run_debugger_with_reset(
scope, global, caches, lib, this_ptr, rhs, level,
)?;
let reset_debugger =
self.run_debugger_with_reset(scope, global, lib, this_ptr, rhs, level)?;
let result = self.make_method_call(
global, caches, lib, name, *hashes, target, call_args, *pos, level,
@ -303,7 +302,7 @@ impl Engine {
// {xxx:map}.id op= ???
Expr::Property(x, pos) if target.is::<crate::Map>() && new_val.is_some() => {
#[cfg(feature = "debugging")]
self.run_debugger(scope, global, caches, lib, this_ptr, rhs, level)?;
self.run_debugger(scope, global, lib, this_ptr, rhs, level)?;
let index = x.2.clone().into();
let ((new_val, new_pos), (op_info, op_pos)) = new_val.expect("`Some`");
@ -324,7 +323,7 @@ impl Engine {
// {xxx:map}.id
Expr::Property(x, pos) if target.is::<crate::Map>() => {
#[cfg(feature = "debugging")]
self.run_debugger(scope, global, caches, lib, this_ptr, rhs, level)?;
self.run_debugger(scope, global, lib, this_ptr, rhs, level)?;
let index = x.2.clone().into();
let val = self.get_indexed_mut(
@ -335,7 +334,7 @@ impl Engine {
// xxx.id op= ???
Expr::Property(x, pos) if new_val.is_some() => {
#[cfg(feature = "debugging")]
self.run_debugger(scope, global, caches, lib, this_ptr, rhs, level)?;
self.run_debugger(scope, global, lib, this_ptr, rhs, level)?;
let ((getter, hash_get), (setter, hash_set), name) = x.as_ref();
let ((mut new_val, new_pos), (op_info, op_pos)) = new_val.expect("`Some`");
@ -404,7 +403,7 @@ impl Engine {
// xxx.id
Expr::Property(x, pos) => {
#[cfg(feature = "debugging")]
self.run_debugger(scope, global, caches, lib, this_ptr, rhs, level)?;
self.run_debugger(scope, global, lib, this_ptr, rhs, level)?;
let ((getter, hash_get), _, name) = x.as_ref();
let hash = crate::ast::FnCallHashes::from_native(*hash_get);
@ -442,9 +441,7 @@ impl Engine {
let val_target = &mut match x.lhs {
Expr::Property(ref p, pos) => {
#[cfg(feature = "debugging")]
self.run_debugger(
scope, global, caches, lib, this_ptr, _node, level,
)?;
self.run_debugger(scope, global, lib, this_ptr, _node, level)?;
let index = p.2.clone().into();
self.get_indexed_mut(
@ -458,7 +455,7 @@ impl Engine {
#[cfg(feature = "debugging")]
let reset_debugger = self.run_debugger_with_reset(
scope, global, caches, lib, this_ptr, _node, level,
scope, global, lib, this_ptr, _node, level,
)?;
let result = self.make_method_call(
@ -494,9 +491,7 @@ impl Engine {
// xxx.prop[expr] | xxx.prop.expr
Expr::Property(ref p, pos) => {
#[cfg(feature = "debugging")]
self.run_debugger(
scope, global, caches, lib, this_ptr, _node, level,
)?;
self.run_debugger(scope, global, lib, this_ptr, _node, level)?;
let ((getter, hash_get), (setter, hash_set), name) = p.as_ref();
let rhs_chain = rhs.into();
@ -581,7 +576,7 @@ impl Engine {
#[cfg(feature = "debugging")]
let reset_debugger = self.run_debugger_with_reset(
scope, global, caches, lib, this_ptr, _node, level,
scope, global, lib, this_ptr, _node, level,
)?;
let result = self.make_method_call(
@ -647,13 +642,13 @@ impl Engine {
// id.??? or id[???]
Expr::Variable(x, .., var_pos) => {
#[cfg(feature = "debugging")]
self.run_debugger(scope, global, caches, lib, this_ptr, lhs, level)?;
self.run_debugger(scope, global, lib, this_ptr, lhs, level)?;
#[cfg(not(feature = "unchecked"))]
self.inc_operations(&mut global.num_operations, *var_pos)?;
let (mut target, ..) =
self.search_namespace(scope, global, caches, lib, this_ptr, lhs, level)?;
self.search_namespace(scope, global, lib, this_ptr, lhs, level)?;
let obj_ptr = &mut target;
let root = (x.3.as_str(), *var_pos);

View File

@ -1,7 +1,7 @@
//! Module defining the debugging interface.
#![cfg(feature = "debugging")]
use super::{Caches, EvalContext, GlobalRuntimeState};
use super::{EvalContext, GlobalRuntimeState};
use crate::ast::{ASTNode, Expr, Stmt};
use crate::{Dynamic, Engine, EvalAltResult, Identifier, Module, Position, RhaiResultOf, Scope};
#[cfg(feature = "no_std")]
@ -406,7 +406,6 @@ impl Engine {
&self,
scope: &mut Scope,
global: &mut GlobalRuntimeState,
caches: &mut Caches,
lib: &[&Module],
this_ptr: &mut Option<&mut Dynamic>,
node: impl Into<ASTNode<'a>>,
@ -414,7 +413,7 @@ impl Engine {
) -> RhaiResultOf<()> {
if self.debugger.is_some() {
if let Some(cmd) =
self.run_debugger_with_reset_raw(scope, global, caches, lib, this_ptr, node, level)?
self.run_debugger_with_reset_raw(scope, global, lib, this_ptr, node, level)?
{
global.debugger.status = cmd;
}
@ -434,14 +433,13 @@ impl Engine {
&self,
scope: &mut Scope,
global: &mut GlobalRuntimeState,
caches: &mut Caches,
lib: &[&Module],
this_ptr: &mut Option<&mut Dynamic>,
node: impl Into<ASTNode<'a>>,
level: usize,
) -> RhaiResultOf<Option<DebuggerStatus>> {
if self.debugger.is_some() {
self.run_debugger_with_reset_raw(scope, global, caches, lib, this_ptr, node, level)
self.run_debugger_with_reset_raw(scope, global, lib, this_ptr, node, level)
} else {
Ok(None)
}
@ -458,7 +456,6 @@ impl Engine {
&self,
scope: &mut Scope,
global: &mut GlobalRuntimeState,
caches: &mut Caches,
lib: &[&Module],
this_ptr: &mut Option<&mut Dynamic>,
node: impl Into<ASTNode<'a>>,
@ -490,7 +487,7 @@ impl Engine {
}
};
self.run_debugger_raw(scope, global, caches, lib, this_ptr, node, event, level)
self.run_debugger_raw(scope, global, lib, this_ptr, node, event, level)
}
/// Run the debugger callback unconditionally.
///
@ -504,7 +501,6 @@ impl Engine {
&self,
scope: &mut Scope,
global: &mut GlobalRuntimeState,
caches: &mut Caches,
lib: &[&Module],
this_ptr: &mut Option<&mut Dynamic>,
node: ASTNode<'a>,
@ -522,7 +518,7 @@ impl Engine {
engine: self,
scope,
global,
caches,
caches: None,
lib,
this_ptr,
level,

View File

@ -7,24 +7,24 @@ use std::prelude::v1::*;
/// Context of a script evaluation process.
#[derive(Debug)]
pub struct EvalContext<'a, 'x, 'px, 'm, 'pm, 'c, 'b, 't, 'pt> {
pub struct EvalContext<'a, 's, 'ps, 'm, 'pm, 'c, 't, 'pt> {
/// The current [`Engine`].
pub(crate) engine: &'a Engine,
/// The current [`Scope`].
pub(crate) scope: &'x mut Scope<'px>,
pub(crate) scope: &'s mut Scope<'ps>,
/// The current [`GlobalRuntimeState`].
pub(crate) global: &'m mut GlobalRuntimeState<'pm>,
/// The current [caches][Caches].
pub(crate) caches: &'c mut Caches,
/// The current [caches][Caches], if available.
pub(crate) caches: Option<&'c mut Caches>,
/// The current stack of imported [modules][Module].
pub(crate) lib: &'b [&'b Module],
pub(crate) lib: &'a [&'a Module],
/// The current bound `this` pointer, if any.
pub(crate) this_ptr: &'t mut Option<&'pt mut Dynamic>,
/// The current nesting level of function calls.
pub(crate) level: usize,
}
impl<'x, 'px, 'm, 'pm, 'pt> EvalContext<'_, 'x, 'px, 'm, 'pm, '_, '_, '_, 'pt> {
impl<'s, 'ps, 'm, 'pm, 'pt> EvalContext<'_, 's, 'ps, 'm, 'pm, '_, '_, 'pt> {
/// The current [`Engine`].
#[inline(always)]
#[must_use]
@ -44,13 +44,13 @@ impl<'x, 'px, 'm, 'pm, 'pt> EvalContext<'_, 'x, 'px, 'm, 'pm, '_, '_, '_, 'pt> {
/// The current [`Scope`].
#[inline(always)]
#[must_use]
pub const fn scope(&self) -> &Scope<'px> {
pub const fn scope(&self) -> &Scope<'ps> {
self.scope
}
/// Get a mutable reference to the current [`Scope`].
#[inline(always)]
#[must_use]
pub fn scope_mut(&mut self) -> &mut &'x mut Scope<'px> {
pub fn scope_mut(&mut self) -> &mut &'s mut Scope<'ps> {
&mut self.scope
}
/// Get an iterator over the current set of modules imported via `import` statements,

View File

@ -47,7 +47,6 @@ impl Engine {
&self,
scope: &'s mut Scope,
global: &mut GlobalRuntimeState,
caches: &mut Caches,
lib: &[&Module],
this_ptr: &'s mut Option<&mut Dynamic>,
expr: &Expr,
@ -55,13 +54,13 @@ impl Engine {
) -> RhaiResultOf<(Target<'s>, Position)> {
match expr {
Expr::Variable(_, Some(_), _) => {
self.search_scope_only(scope, global, caches, lib, this_ptr, expr, level)
self.search_scope_only(scope, global, lib, this_ptr, expr, level)
}
Expr::Variable(v, None, _var_pos) => match v.as_ref() {
// Normal variable access
#[cfg(not(feature = "no_module"))]
(_, ns, ..) if ns.is_empty() => {
self.search_scope_only(scope, global, caches, lib, this_ptr, expr, level)
self.search_scope_only(scope, global, lib, this_ptr, expr, level)
}
#[cfg(feature = "no_module")]
(_, (), ..) => {
@ -130,7 +129,6 @@ impl Engine {
&self,
scope: &'s mut Scope,
global: &mut GlobalRuntimeState,
caches: &mut Caches,
lib: &[&Module],
this_ptr: &'s mut Option<&mut Dynamic>,
expr: &Expr,
@ -159,7 +157,7 @@ impl Engine {
engine: self,
scope,
global,
caches,
caches: None,
lib,
this_ptr,
level,
@ -269,7 +267,7 @@ impl Engine {
if let Expr::FnCall(x, ..) = expr {
#[cfg(feature = "debugging")]
let reset_debugger =
self.run_debugger_with_reset(scope, global, caches, lib, this_ptr, expr, level)?;
self.run_debugger_with_reset(scope, global, lib, this_ptr, expr, level)?;
#[cfg(not(feature = "unchecked"))]
self.inc_operations(&mut global.num_operations, expr.position())?;
@ -288,7 +286,7 @@ impl Engine {
// will cost more than the mis-predicted `match` branch.
if let Expr::Variable(x, index, var_pos) = expr {
#[cfg(feature = "debugging")]
self.run_debugger(scope, global, caches, lib, this_ptr, expr, level)?;
self.run_debugger(scope, global, lib, this_ptr, expr, level)?;
#[cfg(not(feature = "unchecked"))]
self.inc_operations(&mut global.num_operations, expr.position())?;
@ -299,14 +297,14 @@ impl Engine {
.cloned()
.ok_or_else(|| ERR::ErrorUnboundThis(*var_pos).into())
} else {
self.search_namespace(scope, global, caches, lib, this_ptr, expr, level)
self.search_namespace(scope, global, lib, this_ptr, expr, level)
.map(|(val, ..)| val.take_or_clone())
};
}
#[cfg(feature = "debugging")]
let reset_debugger =
self.run_debugger_with_reset(scope, global, caches, lib, this_ptr, expr, level)?;
self.run_debugger_with_reset(scope, global, lib, this_ptr, expr, level)?;
#[cfg(not(feature = "unchecked"))]
self.inc_operations(&mut global.num_operations, expr.position())?;
@ -490,7 +488,7 @@ impl Engine {
engine: self,
scope,
global,
caches,
caches: Some(caches),
lib,
this_ptr,
level,

View File

@ -63,7 +63,7 @@ pub struct GlobalRuntimeState<'a> {
/// Interior mutability is needed because it is shared in order to aid in cloning.
#[cfg(not(feature = "no_module"))]
#[cfg(not(feature = "no_function"))]
pub(crate) constants: Option<GlobalConstants>,
pub constants: Option<GlobalConstants>,
/// Debugging interface.
#[cfg(feature = "debugging")]
pub debugger: super::Debugger,

View File

@ -206,7 +206,7 @@ impl Engine {
) -> RhaiResult {
#[cfg(feature = "debugging")]
let reset_debugger =
self.run_debugger_with_reset(scope, global, caches, lib, this_ptr, stmt, level)?;
self.run_debugger_with_reset(scope, global, lib, this_ptr, stmt, level)?;
// Coded this way for better branch prediction.
// Popular branches are lifted out of the `match` statement into their own branches.
@ -241,7 +241,7 @@ impl Engine {
if let Ok(rhs_val) = rhs_result {
let search_result =
self.search_namespace(scope, global, caches, lib, this_ptr, lhs, level);
self.search_namespace(scope, global, lib, this_ptr, lhs, level);
if let Ok(search_val) = search_result {
let (mut lhs_ptr, pos) = search_val;
@ -843,7 +843,7 @@ impl Engine {
engine: self,
scope,
global,
caches,
caches: None,
lib,
this_ptr,
level,

View File

@ -419,9 +419,7 @@ impl Engine {
Ok(ref r) => crate::eval::DebuggerEvent::FunctionExitWithValue(r),
Err(ref err) => crate::eval::DebuggerEvent::FunctionExitWithError(err),
};
match self
.run_debugger_raw(scope, global, caches, lib, &mut None, node, event, level)
{
match self.run_debugger_raw(scope, global, lib, &mut None, node, event, level) {
Ok(_) => (),
Err(err) => _result = Err(err),
}
@ -905,7 +903,7 @@ impl Engine {
if self.debugger.is_some() {
if let Some(value) = arg_expr.get_literal_value() {
#[cfg(feature = "debugging")]
self.run_debugger(scope, global, caches, lib, this_ptr, arg_expr, level)?;
self.run_debugger(scope, global, lib, this_ptr, arg_expr, level)?;
return Ok((value, arg_expr.start_position()));
}
}
@ -1152,7 +1150,7 @@ impl Engine {
let first_expr = first_arg.unwrap();
#[cfg(feature = "debugging")]
self.run_debugger(scope, global, caches, lib, this_ptr, first_expr, level)?;
self.run_debugger(scope, global, lib, this_ptr, first_expr, level)?;
// func(x, ...) -> x.func(...)
a_expr.iter().try_for_each(|expr| {
@ -1161,7 +1159,7 @@ impl Engine {
})?;
let (mut target, _pos) =
self.search_namespace(scope, global, caches, lib, this_ptr, first_expr, level)?;
self.search_namespace(scope, global, lib, this_ptr, first_expr, level)?;
if target.as_ref().is_read_only() {
target = target.into_owned();
@ -1233,7 +1231,7 @@ impl Engine {
// and avoid cloning the value
if !args_expr.is_empty() && args_expr[0].is_variable_access(true) {
#[cfg(feature = "debugging")]
self.run_debugger(scope, global, caches, lib, this_ptr, &args_expr[0], level)?;
self.run_debugger(scope, global, lib, this_ptr, &args_expr[0], level)?;
// func(x, ...) -> x.func(...)
arg_values.push(Dynamic::UNIT);
@ -1246,7 +1244,7 @@ impl Engine {
// Get target reference to first argument
let first_arg = &args_expr[0];
let (target, _pos) =
self.search_scope_only(scope, global, caches, lib, this_ptr, first_arg, level)?;
self.search_scope_only(scope, global, lib, this_ptr, first_arg, level)?;
#[cfg(not(feature = "unchecked"))]
self.inc_operations(&mut global.num_operations, _pos)?;

View File

@ -142,7 +142,7 @@ impl Engine {
#[cfg(feature = "debugging")]
{
let node = crate::ast::Stmt::Noop(fn_def.body.position());
self.run_debugger(scope, global, caches, lib, this_ptr, &node, level)?;
self.run_debugger(scope, global, lib, this_ptr, &node, level)?;
}
// Evaluate the function
@ -193,9 +193,7 @@ impl Engine {
Ok(ref r) => crate::eval::DebuggerEvent::FunctionExitWithValue(r),
Err(ref err) => crate::eval::DebuggerEvent::FunctionExitWithError(err),
};
match self
.run_debugger_raw(scope, global, caches, lib, this_ptr, node, event, level)
{
match self.run_debugger_raw(scope, global, lib, this_ptr, node, event, level) {
Ok(_) => (),
Err(err) => _result = Err(err),
}

View File

@ -8,7 +8,7 @@ use crate::ast::{
OpAssignment, ScriptFnDef, Stmt, StmtBlock, StmtBlockContainer, SwitchCases, TryCatchBlock,
};
use crate::engine::{Precedence, KEYWORD_THIS, OP_CONTAINS};
use crate::eval::{Caches, GlobalRuntimeState};
use crate::eval::GlobalRuntimeState;
use crate::func::hashing::get_hasher;
use crate::tokenizer::{
is_keyword_function, is_valid_function_name, is_valid_identifier, Token, TokenStream,
@ -2686,7 +2686,7 @@ impl Engine {
engine: self,
scope: &mut state.stack,
global: &mut GlobalRuntimeState::new(self),
caches: &mut Caches::new(),
caches: None,
lib: &[],
this_ptr: &mut None,
level,