Allow initialization of EvalState tag and separate debugger state into separate variable.

This commit is contained in:
Stephen Chung 2022-05-21 21:44:12 +08:00
parent 5435fdb8c8
commit 1abec0a8a8
10 changed files with 86 additions and 25 deletions

View File

@ -21,6 +21,8 @@ Enhancements
------------ ------------
* `EvalAltResult::IndexNotFound` is added to aid in raising errors for indexers. * `EvalAltResult::IndexNotFound` is added to aid in raising errors for indexers.
* `Engine::def_tag`, `Engine::def_tag_mut` and `Engine::set_tag` are added to manage a default value for the custom evaluation state, accessible via `EvalState::tag()` (which is the same as `NativeCallContext::tag()`).
* Originally, the debugger's custom state uses the same state as `EvalState::tag()` (which is the same as `NativeCallContext::tag()`). It is now split into its own variable accessible under `Debugger::state()`.
Version 1.7.0 Version 1.7.0

View File

@ -201,7 +201,7 @@ impl Engine {
scope: &Scope, scope: &Scope,
scripts: impl AsRef<[S]>, scripts: impl AsRef<[S]>,
) -> ParseResult<AST> { ) -> ParseResult<AST> {
self.compile_with_scope_and_optimization_level(scope, scripts, self.optimization_level) self.compile_with_scope_and_optimization_level(scope, scripts, self.optimization_level())
} }
/// Join a list of strings and compile into an [`AST`] using own scope at a specific optimization level. /// Join a list of strings and compile into an [`AST`] using own scope at a specific optimization level.
/// ///
@ -292,6 +292,6 @@ impl Engine {
let mut peekable = stream.peekable(); let mut peekable = stream.peekable();
let mut state = ParseState::new(self, scope, tokenizer_control); let mut state = ParseState::new(self, scope, tokenizer_control);
self.parse_global_expr(&mut peekable, &mut state, self.optimization_level) self.parse_global_expr(&mut peekable, &mut state, self.optimization_level())
} }
} }

View File

@ -67,7 +67,7 @@ impl Engine {
let ast = self.compile_with_scope_and_optimization_level( let ast = self.compile_with_scope_and_optimization_level(
scope, scope,
&[script], &[script],
self.optimization_level, self.optimization_level(),
)?; )?;
self.eval_ast_with_scope(scope, &ast) self.eval_ast_with_scope(scope, &ast)
} }

View File

@ -30,7 +30,7 @@ pub mod deprecated;
use crate::engine::Precedence; use crate::engine::Precedence;
use crate::tokenizer::Token; use crate::tokenizer::Token;
use crate::{Engine, Identifier}; use crate::{Dynamic, Engine, Identifier};
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
@ -195,4 +195,23 @@ impl Engine {
Ok(self) Ok(self)
} }
/// Get the default value of the custom state for each evaluation run.
#[inline(always)]
#[must_use]
pub fn default_tag(&self) -> &Dynamic {
&self.def_tag
}
/// Get a mutable reference to the default value of the custom state for each evaluation run.
#[inline(always)]
#[must_use]
pub fn default_tag_mut(&mut self) -> &mut Dynamic {
&mut self.def_tag
}
/// Set the default value of the custom state for each evaluation run.
#[inline(always)]
pub fn set_default_tag(&mut self, value: impl Into<Dynamic>) -> &mut Self {
self.def_tag = value.into();
self
}
} }

View File

@ -26,7 +26,11 @@ impl Engine {
self.lex_raw(&scripts, self.token_mapper.as_ref().map(Box::as_ref)); self.lex_raw(&scripts, self.token_mapper.as_ref().map(Box::as_ref));
let mut state = ParseState::new(self, scope, tokenizer_control); let mut state = ParseState::new(self, scope, tokenizer_control);
let ast = self.parse(&mut stream.peekable(), &mut state, self.optimization_level)?; let ast = self.parse(
&mut stream.peekable(),
&mut state,
self.optimization_level(),
)?;
self.run_ast_with_scope(scope, &ast) self.run_ast_with_scope(scope, &ast)
} }

View File

@ -60,7 +60,12 @@ fn print_current_source(
lines: &[String], lines: &[String],
window: (usize, usize), window: (usize, usize),
) { ) {
let current_source = &mut *context.tag_mut().write_lock::<ImmutableString>().unwrap(); let current_source = &mut *context
.global_runtime_state_mut()
.debugger
.state_mut()
.write_lock::<ImmutableString>()
.unwrap();
let src = source.unwrap_or(""); let src = source.unwrap_or("");
if src != current_source { if src != current_source {
println!( println!(

View File

@ -132,8 +132,11 @@ pub struct Engine {
/// Language options. /// Language options.
pub(crate) options: LangOptions, pub(crate) options: LangOptions,
/// Default value for the custom state.
pub(crate) def_tag: Dynamic,
/// Script optimization level. /// Script optimization level.
pub optimization_level: OptimizationLevel, pub(crate) optimization_level: OptimizationLevel,
/// Max limits. /// Max limits.
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
@ -280,6 +283,8 @@ impl Engine {
options: LangOptions::new(), options: LangOptions::new(),
def_tag: Dynamic::UNIT,
#[cfg(not(feature = "no_optimize"))] #[cfg(not(feature = "no_optimize"))]
optimization_level: OptimizationLevel::Simple, optimization_level: OptimizationLevel::Simple,
#[cfg(feature = "no_optimize")] #[cfg(feature = "no_optimize")]

View File

@ -253,17 +253,20 @@ pub struct Debugger {
break_points: Vec<BreakPoint>, break_points: Vec<BreakPoint>,
/// The current function call stack. /// The current function call stack.
call_stack: Vec<CallStackFrame>, call_stack: Vec<CallStackFrame>,
/// The current state.
state: Dynamic,
} }
impl Debugger { impl Debugger {
/// Create a new [`Debugger`]. /// Create a new [`Debugger`].
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn new(status: DebuggerStatus) -> Self { pub fn new(status: DebuggerStatus, state: Dynamic) -> Self {
Self { Self {
status, status,
break_points: Vec::new(), break_points: Vec::new(),
call_stack: Vec::new(), call_stack: Vec::new(),
state,
} }
} }
/// Get the current call stack. /// Get the current call stack.
@ -374,6 +377,23 @@ impl Debugger {
pub fn break_points_mut(&mut self) -> &mut Vec<BreakPoint> { pub fn break_points_mut(&mut self) -> &mut Vec<BreakPoint> {
&mut self.break_points &mut self.break_points
} }
/// Get the custom state.
#[inline(always)]
#[must_use]
pub fn state(&self) -> &Dynamic {
&self.state
}
/// Get a mutable reference to the custom state.
#[inline(always)]
#[must_use]
pub fn state_mut(&mut self) -> &mut Dynamic {
&mut self.state
}
/// Set the custom state.
#[inline(always)]
pub fn set_state(&mut self, state: impl Into<Dynamic>) {
self.state = state.into();
}
} }
impl Engine { impl Engine {

View File

@ -78,8 +78,6 @@ impl GlobalRuntimeState<'_> {
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn new(engine: &Engine) -> Self { pub fn new(engine: &Engine) -> Self {
let _engine = engine;
Self { Self {
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
keys: crate::StaticVec::new_const(), keys: crate::StaticVec::new_const(),
@ -98,21 +96,21 @@ impl GlobalRuntimeState<'_> {
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
constants: None, constants: None,
#[cfg(not(feature = "debugging"))] tag: engine.default_tag().clone(),
tag: Dynamic::UNIT,
#[cfg(feature = "debugging")]
tag: if let Some((ref init, ..)) = engine.debugger {
init()
} else {
Dynamic::UNIT
},
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
debugger: crate::eval::Debugger::new(if engine.debugger.is_some() { debugger: crate::eval::Debugger::new(
crate::eval::DebuggerStatus::Init if engine.debugger.is_some() {
} else { crate::eval::DebuggerStatus::Init
crate::eval::DebuggerStatus::CONTINUE } else {
}), crate::eval::DebuggerStatus::CONTINUE
},
if let Some((ref init, ..)) = engine.debugger {
init()
} else {
Dynamic::UNIT
},
),
dummy: PhantomData::default(), dummy: PhantomData::default(),
} }

View File

@ -57,10 +57,18 @@ fn test_debugger_state() -> Result<(), Box<EvalAltResult>> {
}, },
|mut context, _, _, _, _| { |mut context, _, _, _, _| {
// Print debugger state - which is an object map // Print debugger state - which is an object map
println!("Current state = {}", context.tag()); println!(
"Current state = {}",
context.global_runtime_state_mut().debugger.state()
);
// Modify state // Modify state
let mut state = context.tag_mut().write_lock::<Map>().unwrap(); let mut state = context
.global_runtime_state_mut()
.debugger
.state_mut()
.write_lock::<Map>()
.unwrap();
let hello = state.get("hello").unwrap().as_int().unwrap(); let hello = state.get("hello").unwrap().as_int().unwrap();
state.insert("hello".into(), (hello + 1).into()); state.insert("hello".into(), (hello + 1).into());
state.insert("foo".into(), true.into()); state.insert("foo".into(), true.into());