diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d0b8329..20169aff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ Enhancements ------------ * `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 diff --git a/src/api/compile.rs b/src/api/compile.rs index 2250b641..750972e9 100644 --- a/src/api/compile.rs +++ b/src/api/compile.rs @@ -201,7 +201,7 @@ impl Engine { scope: &Scope, scripts: impl AsRef<[S]>, ) -> ParseResult { - 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. /// @@ -292,6 +292,6 @@ impl Engine { let mut peekable = stream.peekable(); 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()) } } diff --git a/src/api/eval.rs b/src/api/eval.rs index aec12d99..65ef8c37 100644 --- a/src/api/eval.rs +++ b/src/api/eval.rs @@ -67,7 +67,7 @@ impl Engine { let ast = self.compile_with_scope_and_optimization_level( scope, &[script], - self.optimization_level, + self.optimization_level(), )?; self.eval_ast_with_scope(scope, &ast) } diff --git a/src/api/mod.rs b/src/api/mod.rs index 554f48d5..b8e7084e 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -30,7 +30,7 @@ pub mod deprecated; use crate::engine::Precedence; use crate::tokenizer::Token; -use crate::{Engine, Identifier}; +use crate::{Dynamic, Engine, Identifier}; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -195,4 +195,23 @@ impl Engine { 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) -> &mut Self { + self.def_tag = value.into(); + self + } } diff --git a/src/api/run.rs b/src/api/run.rs index 673fa19e..93a0a38b 100644 --- a/src/api/run.rs +++ b/src/api/run.rs @@ -26,7 +26,11 @@ impl Engine { self.lex_raw(&scripts, self.token_mapper.as_ref().map(Box::as_ref)); 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) } diff --git a/src/bin/rhai-dbg.rs b/src/bin/rhai-dbg.rs index db285f7a..93bc6b6d 100644 --- a/src/bin/rhai-dbg.rs +++ b/src/bin/rhai-dbg.rs @@ -60,7 +60,12 @@ fn print_current_source( lines: &[String], window: (usize, usize), ) { - let current_source = &mut *context.tag_mut().write_lock::().unwrap(); + let current_source = &mut *context + .global_runtime_state_mut() + .debugger + .state_mut() + .write_lock::() + .unwrap(); let src = source.unwrap_or(""); if src != current_source { println!( diff --git a/src/engine.rs b/src/engine.rs index 8a4e8841..2af23bac 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -132,8 +132,11 @@ pub struct Engine { /// Language options. pub(crate) options: LangOptions, + /// Default value for the custom state. + pub(crate) def_tag: Dynamic, + /// Script optimization level. - pub optimization_level: OptimizationLevel, + pub(crate) optimization_level: OptimizationLevel, /// Max limits. #[cfg(not(feature = "unchecked"))] @@ -280,6 +283,8 @@ impl Engine { options: LangOptions::new(), + def_tag: Dynamic::UNIT, + #[cfg(not(feature = "no_optimize"))] optimization_level: OptimizationLevel::Simple, #[cfg(feature = "no_optimize")] diff --git a/src/eval/debugger.rs b/src/eval/debugger.rs index a6344a85..11b52bf8 100644 --- a/src/eval/debugger.rs +++ b/src/eval/debugger.rs @@ -253,17 +253,20 @@ pub struct Debugger { break_points: Vec, /// The current function call stack. call_stack: Vec, + /// The current state. + state: Dynamic, } impl Debugger { /// Create a new [`Debugger`]. #[inline(always)] #[must_use] - pub fn new(status: DebuggerStatus) -> Self { + pub fn new(status: DebuggerStatus, state: Dynamic) -> Self { Self { status, break_points: Vec::new(), call_stack: Vec::new(), + state, } } /// Get the current call stack. @@ -374,6 +377,23 @@ impl Debugger { pub fn break_points_mut(&mut self) -> &mut Vec { &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) { + self.state = state.into(); + } } impl Engine { diff --git a/src/eval/global_state.rs b/src/eval/global_state.rs index bdcbb2ca..3c0a8c4a 100644 --- a/src/eval/global_state.rs +++ b/src/eval/global_state.rs @@ -78,8 +78,6 @@ impl GlobalRuntimeState<'_> { #[inline(always)] #[must_use] pub fn new(engine: &Engine) -> Self { - let _engine = engine; - Self { #[cfg(not(feature = "no_module"))] keys: crate::StaticVec::new_const(), @@ -98,21 +96,21 @@ impl GlobalRuntimeState<'_> { #[cfg(not(feature = "no_function"))] constants: None, - #[cfg(not(feature = "debugging"))] - tag: Dynamic::UNIT, - #[cfg(feature = "debugging")] - tag: if let Some((ref init, ..)) = engine.debugger { - init() - } else { - Dynamic::UNIT - }, + tag: engine.default_tag().clone(), #[cfg(feature = "debugging")] - debugger: crate::eval::Debugger::new(if engine.debugger.is_some() { - crate::eval::DebuggerStatus::Init - } else { - crate::eval::DebuggerStatus::CONTINUE - }), + debugger: crate::eval::Debugger::new( + if engine.debugger.is_some() { + crate::eval::DebuggerStatus::Init + } else { + crate::eval::DebuggerStatus::CONTINUE + }, + if let Some((ref init, ..)) = engine.debugger { + init() + } else { + Dynamic::UNIT + }, + ), dummy: PhantomData::default(), } diff --git a/tests/debugging.rs b/tests/debugging.rs index 8f5b8cf9..48f8d946 100644 --- a/tests/debugging.rs +++ b/tests/debugging.rs @@ -57,10 +57,18 @@ fn test_debugger_state() -> Result<(), Box> { }, |mut context, _, _, _, _| { // 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 - let mut state = context.tag_mut().write_lock::().unwrap(); + let mut state = context + .global_runtime_state_mut() + .debugger + .state_mut() + .write_lock::() + .unwrap(); let hello = state.get("hello").unwrap().as_int().unwrap(); state.insert("hello".into(), (hello + 1).into()); state.insert("foo".into(), true.into());