diff --git a/src/api/call_fn.rs b/src/api/call_fn.rs index 02b062ab..5d584630 100644 --- a/src/api/call_fn.rs +++ b/src/api/call_fn.rs @@ -277,7 +277,7 @@ impl Engine { #[cfg(feature = "debugging")] if self.debugger.is_some() { - global.debugger.status = crate::eval::DebuggerStatus::Terminate; + global.debugger_mut().status = crate::eval::DebuggerStatus::Terminate; let node = &crate::ast::Stmt::Noop(Position::NONE); self.run_debugger(global, caches, scope, this_ptr, node)?; } diff --git a/src/api/eval.rs b/src/api/eval.rs index f3dd133f..5def7ccf 100644 --- a/src/api/eval.rs +++ b/src/api/eval.rs @@ -244,7 +244,7 @@ impl Engine { #[cfg(feature = "debugging")] if self.debugger.is_some() { - global.debugger.status = crate::eval::DebuggerStatus::Terminate; + global.debugger_mut().status = crate::eval::DebuggerStatus::Terminate; let mut this = Dynamic::NULL; let node = &crate::ast::Stmt::Noop(Position::NONE); diff --git a/src/api/run.rs b/src/api/run.rs index 65a95aae..ab854321 100644 --- a/src/api/run.rs +++ b/src/api/run.rs @@ -137,7 +137,7 @@ impl Engine { #[cfg(feature = "debugging")] if self.debugger.is_some() { - global.debugger.status = crate::eval::DebuggerStatus::Terminate; + global.debugger_mut().status = crate::eval::DebuggerStatus::Terminate; let mut this = crate::Dynamic::NULL; let node = &crate::ast::Stmt::Noop(crate::Position::NONE); self.run_debugger(global, caches, scope, &mut this, node)?; diff --git a/src/bin/rhai-dbg.rs b/src/bin/rhai-dbg.rs index 04284050..b47f7a6d 100644 --- a/src/bin/rhai-dbg.rs +++ b/src/bin/rhai-dbg.rs @@ -61,7 +61,7 @@ fn print_current_source( ) { let current_source = &mut *context .global_runtime_state_mut() - .debugger + .debugger_mut() .state_mut() .write_lock::() .unwrap(); @@ -241,7 +241,7 @@ fn debug_callback( DebuggerEvent::End => println!("\x1b[31m! Script end\x1b[39m"), DebuggerEvent::Step => (), DebuggerEvent::BreakPoint(n) => { - match context.global_runtime_state().debugger.break_points()[n] { + match context.global_runtime_state().debugger().break_points()[n] { #[cfg(not(feature = "no_position"))] BreakPoint::AtPosition { .. } => (), BreakPoint::AtFunctionName { ref name, .. } @@ -260,7 +260,7 @@ fn debug_callback( "! Return from function call '{}' => {:?}", context .global_runtime_state() - .debugger + .debugger() .call_stack() .last() .unwrap() @@ -273,7 +273,7 @@ fn debug_callback( "! Return from function call '{}' with error: {}", context .global_runtime_state() - .debugger + .debugger() .call_stack() .last() .unwrap() @@ -373,7 +373,7 @@ fn debug_callback( ["backtrace" | "bt"] => { for frame in context .global_runtime_state() - .debugger + .debugger() .call_stack() .iter() .rev() @@ -384,7 +384,7 @@ fn debug_callback( ["info" | "i", "break" | "b"] => Iterator::for_each( context .global_runtime_state() - .debugger + .debugger() .break_points() .iter() .enumerate(), @@ -402,13 +402,13 @@ fn debug_callback( if let Ok(n) = n.parse::() { let range = 1..=context .global_runtime_state_mut() - .debugger + .debugger() .break_points() .len(); if range.contains(&n) { context .global_runtime_state_mut() - .debugger + .debugger_mut() .break_points_mut() .get_mut(n - 1) .unwrap() @@ -425,13 +425,13 @@ fn debug_callback( if let Ok(n) = n.parse::() { let range = 1..=context .global_runtime_state_mut() - .debugger + .debugger() .break_points() .len(); if range.contains(&n) { context .global_runtime_state_mut() - .debugger + .debugger_mut() .break_points_mut() .get_mut(n - 1) .unwrap() @@ -448,13 +448,13 @@ fn debug_callback( if let Ok(n) = n.parse::() { let range = 1..=context .global_runtime_state_mut() - .debugger + .debugger() .break_points() .len(); if range.contains(&n) { context .global_runtime_state_mut() - .debugger + .debugger_mut() .break_points_mut() .remove(n - 1); println!("Break-point #{n} deleted.") @@ -468,7 +468,7 @@ fn debug_callback( ["delete" | "d"] => { context .global_runtime_state_mut() - .debugger + .debugger_mut() .break_points_mut() .clear(); println!("All break-points deleted."); @@ -483,7 +483,7 @@ fn debug_callback( println!("Break-point added for {bp}"); context .global_runtime_state_mut() - .debugger + .debugger_mut() .break_points_mut() .push(bp); } else { @@ -500,7 +500,7 @@ fn debug_callback( println!("Break-point added for {bp}"); context .global_runtime_state_mut() - .debugger + .debugger_mut() .break_points_mut() .push(bp); } @@ -523,7 +523,7 @@ fn debug_callback( println!("Break-point added {bp}"); context .global_runtime_state_mut() - .debugger + .debugger_mut() .break_points_mut() .push(bp); } else { @@ -539,7 +539,7 @@ fn debug_callback( println!("Break-point added for {bp}"); context .global_runtime_state_mut() - .debugger + .debugger_mut() .break_points_mut() .push(bp); } @@ -553,7 +553,7 @@ fn debug_callback( println!("Break-point added {bp}"); context .global_runtime_state_mut() - .debugger + .debugger_mut() .break_points_mut() .push(bp); } diff --git a/src/eval/chaining.rs b/src/eval/chaining.rs index 9ec5f7b0..3eab4d46 100644 --- a/src/eval/chaining.rs +++ b/src/eval/chaining.rs @@ -663,9 +663,10 @@ impl Engine { let reset = self.run_debugger_with_reset(global, caches, scope, this_ptr, rhs)?; #[cfg(feature = "debugging")] - let global = &mut *RestoreOnDrop::lock(global, move |g| { - g.debugger.reset_status(reset) - }); + let global = + &mut *RestoreOnDrop::lock_if(reset.is_some(), global, move |g| { + g.debugger_mut().reset_status(reset) + }); let crate::ast::FnCallExpr { name, hashes, args, .. @@ -832,9 +833,11 @@ impl Engine { global, caches, scope, this_ptr, _node, )?; #[cfg(feature = "debugging")] - let global = &mut *RestoreOnDrop::lock(global, move |g| { - g.debugger.reset_status(reset) - }); + let global = &mut *RestoreOnDrop::lock_if( + reset.is_some(), + global, + move |g| g.debugger_mut().reset_status(reset), + ); let crate::ast::FnCallExpr { name, hashes, args, .. @@ -956,9 +959,11 @@ impl Engine { global, caches, scope, this_ptr, _node, )?; #[cfg(feature = "debugging")] - let global = &mut *RestoreOnDrop::lock(global, move |g| { - g.debugger.reset_status(reset) - }); + let global = &mut *RestoreOnDrop::lock_if( + reset.is_some(), + global, + move |g| g.debugger_mut().reset_status(reset), + ); let crate::ast::FnCallExpr { name, hashes, args, .. diff --git a/src/eval/debugger.rs b/src/eval/debugger.rs index bcbb2c30..92f6bc0a 100644 --- a/src/eval/debugger.rs +++ b/src/eval/debugger.rs @@ -419,7 +419,7 @@ impl Engine { if let Some(cmd) = self.run_debugger_with_reset_raw(global, caches, scope, this_ptr, node)? { - global.debugger.status = cmd; + global.debugger_mut().status = cmd; } } @@ -469,24 +469,28 @@ impl Engine { _ => (), } - let event = match global.debugger.status { - DebuggerStatus::Init => Some(DebuggerEvent::Start), - DebuggerStatus::NEXT if node.is_stmt() => Some(DebuggerEvent::Step), - DebuggerStatus::INTO if node.is_expr() => Some(DebuggerEvent::Step), - DebuggerStatus::STEP => Some(DebuggerEvent::Step), - DebuggerStatus::Terminate => Some(DebuggerEvent::End), - _ => None, - }; + if let Some(ref dbg) = global.debugger { + let event = match dbg.status { + DebuggerStatus::Init => Some(DebuggerEvent::Start), + DebuggerStatus::NEXT if node.is_stmt() => Some(DebuggerEvent::Step), + DebuggerStatus::INTO if node.is_expr() => Some(DebuggerEvent::Step), + DebuggerStatus::STEP => Some(DebuggerEvent::Step), + DebuggerStatus::Terminate => Some(DebuggerEvent::End), + _ => None, + }; - let event = match event { - Some(e) => e, - None => match global.debugger.is_break_point(global.source(), node) { - Some(bp) => DebuggerEvent::BreakPoint(bp), - None => return Ok(None), - }, - }; + let event = match event { + Some(e) => e, + None => match dbg.is_break_point(global.source(), node) { + Some(bp) => DebuggerEvent::BreakPoint(bp), + None => return Ok(None), + }, + }; - self.run_debugger_raw(global, caches, scope, this_ptr, node, event) + self.run_debugger_raw(global, caches, scope, this_ptr, node, event) + } else { + Ok(None) + } } /// Run the debugger callback unconditionally. /// @@ -513,19 +517,19 @@ impl Engine { match command { DebuggerCommand::Continue => { - global.debugger.status = DebuggerStatus::CONTINUE; + global.debugger_mut().status = DebuggerStatus::CONTINUE; Ok(None) } DebuggerCommand::Next => { - global.debugger.status = DebuggerStatus::CONTINUE; + global.debugger_mut().status = DebuggerStatus::CONTINUE; Ok(Some(DebuggerStatus::NEXT)) } DebuggerCommand::StepOver => { - global.debugger.status = DebuggerStatus::CONTINUE; + global.debugger_mut().status = DebuggerStatus::CONTINUE; Ok(Some(DebuggerStatus::STEP)) } DebuggerCommand::StepInto => { - global.debugger.status = DebuggerStatus::STEP; + global.debugger_mut().status = DebuggerStatus::STEP; Ok(None) } DebuggerCommand::FunctionExit => { @@ -539,7 +543,7 @@ impl Engine { } _ => global.level, }; - global.debugger.status = DebuggerStatus::FunctionExit(level); + global.debugger_mut().status = DebuggerStatus::FunctionExit(level); Ok(None) } } diff --git a/src/eval/expr.rs b/src/eval/expr.rs index 7cf213fb..0ee555f4 100644 --- a/src/eval/expr.rs +++ b/src/eval/expr.rs @@ -227,9 +227,10 @@ impl Engine { #[cfg(feature = "debugging")] let reset = self.run_debugger_with_reset(global, caches, scope, this_ptr, expr)?; #[cfg(feature = "debugging")] - let global = &mut *crate::types::RestoreOnDrop::lock(global, move |g| { - g.debugger.reset_status(reset) - }); + let global = + &mut *crate::types::RestoreOnDrop::lock_if(reset.is_some(), global, move |g| { + g.debugger_mut().reset_status(reset) + }); self.track_operation(global, expr.position())?; @@ -260,9 +261,10 @@ impl Engine { #[cfg(feature = "debugging")] let reset = self.run_debugger_with_reset(global, caches, scope, this_ptr, expr)?; #[cfg(feature = "debugging")] - let global = &mut *crate::types::RestoreOnDrop::lock(global, move |g| { - g.debugger.reset_status(reset) - }); + let global = + &mut *crate::types::RestoreOnDrop::lock_if(reset.is_some(), global, move |g| { + g.debugger_mut().reset_status(reset) + }); self.track_operation(global, expr.position())?; diff --git a/src/eval/global_state.rs b/src/eval/global_state.rs index 4cd6de33..bc2ae8d0 100644 --- a/src/eval/global_state.rs +++ b/src/eval/global_state.rs @@ -25,10 +25,11 @@ pub type GlobalConstants = pub struct GlobalRuntimeState { /// Names of imported [modules][crate::Module]. #[cfg(not(feature = "no_module"))] - imports: crate::StaticVec, + imports: Option>>, /// Stack of imported [modules][crate::Module]. #[cfg(not(feature = "no_module"))] - modules: crate::StaticVec, + modules: Option>>, + /// The current stack of loaded [modules][crate::Module] containing script-defined functions. #[cfg(not(feature = "no_function"))] pub lib: crate::StaticVec, @@ -74,7 +75,7 @@ pub struct GlobalRuntimeState { pub tag: Dynamic, /// Debugging interface. #[cfg(feature = "debugging")] - pub debugger: super::Debugger, + pub(crate) debugger: Option, } impl GlobalRuntimeState { @@ -84,9 +85,9 @@ impl GlobalRuntimeState { pub fn new(engine: &Engine) -> Self { Self { #[cfg(not(feature = "no_module"))] - imports: crate::StaticVec::new_const(), + imports: None, #[cfg(not(feature = "no_module"))] - modules: crate::StaticVec::new_const(), + modules: None, #[cfg(not(feature = "no_function"))] lib: crate::StaticVec::new_const(), source: None, @@ -110,36 +111,28 @@ impl GlobalRuntimeState { 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 - }, - match engine.debugger { - Some((ref init, ..)) => init(engine), - None => Dynamic::UNIT, - }, - ), + debugger: engine.debugger.as_ref().map(|(init, ..)| { + crate::eval::Debugger::new(crate::eval::DebuggerStatus::Init, init(engine)) + }), } } /// Get the length of the stack of globally-imported [modules][crate::Module]. /// /// Not available under `no_module`. #[cfg(not(feature = "no_module"))] - #[inline(always)] + #[inline] #[must_use] pub fn num_imports(&self) -> usize { - self.modules.len() + self.modules.as_ref().map_or(0, |m| m.len()) } /// Get the globally-imported [module][crate::Module] at a particular index. /// /// Not available under `no_module`. #[cfg(not(feature = "no_module"))] - #[inline(always)] + #[inline] #[must_use] pub fn get_shared_import(&self, index: usize) -> Option { - self.modules.get(index).cloned() + self.modules.as_ref().and_then(|m| m.get(index).cloned()) } /// Get a mutable reference to the globally-imported [module][crate::Module] at a /// particular index. @@ -147,13 +140,13 @@ impl GlobalRuntimeState { /// Not available under `no_module`. #[cfg(not(feature = "no_module"))] #[allow(dead_code)] - #[inline(always)] + #[inline] #[must_use] pub(crate) fn get_shared_import_mut( &mut self, index: usize, ) -> Option<&mut crate::SharedModule> { - self.modules.get_mut(index) + self.modules.as_mut().and_then(|m| m.get_mut(index)) } /// Get the index of a globally-imported [module][crate::Module] by name. /// @@ -162,33 +155,44 @@ impl GlobalRuntimeState { #[inline] #[must_use] pub fn find_import(&self, name: &str) -> Option { - self.imports - .iter() - .rev() - .position(|key| key.as_str() == name) - .map(|i| self.imports.len() - 1 - i) + self.imports.as_ref().and_then(|imports| { + imports + .iter() + .rev() + .position(|key| key.as_str() == name) + .map(|i| imports.len() - 1 - i) + }) } /// Push an imported [module][crate::Module] onto the stack. /// /// Not available under `no_module`. #[cfg(not(feature = "no_module"))] - #[inline(always)] + #[inline] pub fn push_import( &mut self, name: impl Into, module: impl Into, ) { - self.imports.push(name.into()); - self.modules.push(module.into()); + if self.imports.is_none() { + self.imports = Some(crate::StaticVec::new_const().into()); + self.modules = Some(crate::StaticVec::new_const().into()); + } + self.imports.as_mut().unwrap().push(name.into()); + self.modules.as_mut().unwrap().push(module.into()); } /// Truncate the stack of globally-imported [modules][crate::Module] to a particular length. /// /// Not available under `no_module`. #[cfg(not(feature = "no_module"))] - #[inline(always)] + #[inline] pub fn truncate_imports(&mut self, size: usize) { - self.imports.truncate(size); - self.modules.truncate(size); + if size == 0 { + self.imports = None; + self.modules = None; + } else if self.imports.is_some() { + self.imports.as_mut().unwrap().truncate(size); + self.modules.as_mut().unwrap().truncate(size); + } } /// Get an iterator to the stack of globally-imported [modules][crate::Module] in reverse order. /// @@ -198,8 +202,9 @@ impl GlobalRuntimeState { pub fn iter_imports(&self) -> impl Iterator { self.imports .iter() - .zip(self.modules.iter()) + .flat_map(|x| x.iter()) .rev() + .zip(self.modules.iter().flat_map(|x| x.iter()).rev()) .map(|(name, module)| (name.as_str(), &**module)) } /// Get an iterator to the stack of globally-imported [modules][crate::Module] in reverse order. @@ -210,7 +215,11 @@ impl GlobalRuntimeState { pub(crate) fn iter_imports_raw( &self, ) -> impl Iterator { - self.imports.iter().zip(self.modules.iter()).rev() + self.imports + .iter() + .flat_map(|x| x.iter()) + .rev() + .zip(self.modules.iter().flat_map(|x| x.iter()).rev()) } /// Get an iterator to the stack of globally-imported [modules][crate::Module] in forward order. /// @@ -220,18 +229,21 @@ impl GlobalRuntimeState { pub fn scan_imports_raw( &self, ) -> impl Iterator { - self.imports.iter().zip(self.modules.iter()) + self.imports + .iter() + .flat_map(|x| x.iter()) + .zip(self.modules.iter().flat_map(|x| x.iter())) } /// Can the particular function with [`Dynamic`] parameter(s) exist in the stack of /// globally-imported [modules][crate::Module]? /// /// Not available under `no_module`. #[cfg(not(feature = "no_module"))] - #[inline(always)] + #[inline] pub(crate) fn may_contain_dynamic_fn(&self, hash_script: u64) -> bool { - self.modules - .iter() - .any(|m| m.may_contain_dynamic_fn(hash_script)) + self.modules.as_ref().map_or(false, |m| { + m.iter().any(|m| m.may_contain_dynamic_fn(hash_script)) + }) } /// Does the specified function hash key exist in the stack of globally-imported /// [modules][crate::Module]? @@ -242,7 +254,9 @@ impl GlobalRuntimeState { #[inline] #[must_use] pub fn contains_qualified_fn(&self, hash: u64) -> bool { - self.modules.iter().any(|m| m.contains_qualified_fn(hash)) + self.modules + .as_ref() + .map_or(false, |m| m.iter().any(|m| m.contains_qualified_fn(hash))) } /// Get the specified function via its hash key from the stack of globally-imported /// [modules][crate::Module]. @@ -255,10 +269,11 @@ impl GlobalRuntimeState { &self, hash: u64, ) -> Option<(&crate::func::CallableFunction, Option<&ImmutableString>)> { - self.modules - .iter() - .rev() - .find_map(|m| m.get_qualified_fn(hash).map(|f| (f, m.id_raw()))) + self.modules.as_ref().and_then(|m| { + m.iter() + .rev() + .find_map(|m| m.get_qualified_fn(hash).map(|f| (f, m.id_raw()))) + }) } /// Does the specified [`TypeId`][std::any::TypeId] iterator exist in the stack of /// globally-imported [modules][crate::Module]? @@ -269,7 +284,9 @@ impl GlobalRuntimeState { #[inline] #[must_use] pub fn contains_iter(&self, id: std::any::TypeId) -> bool { - self.modules.iter().any(|m| m.contains_qualified_iter(id)) + self.modules + .as_ref() + .map_or(false, |m| m.iter().any(|m| m.contains_qualified_iter(id))) } /// Get the specified [`TypeId`][std::any::TypeId] iterator from the stack of globally-imported /// [modules][crate::Module]. @@ -280,9 +297,8 @@ impl GlobalRuntimeState { #[must_use] pub fn get_iter(&self, id: std::any::TypeId) -> Option<&crate::func::IteratorFn> { self.modules - .iter() - .rev() - .find_map(|m| m.get_qualified_iter(id)) + .as_ref() + .and_then(|m| m.iter().rev().find_map(|m| m.get_qualified_iter(id))) } /// Get the current source. #[inline(always)] @@ -311,15 +327,42 @@ impl GlobalRuntimeState { pub(crate) fn hash_idx_set(&mut self) -> u64 { self.fn_hash_indexing.1 } + + /// Return a reference to the debugging interface. + /// + /// # Panics + /// + /// Panics if the debugging interface is not set. + #[cfg(feature = "debugging")] + pub fn debugger(&self) -> &super::Debugger { + self.debugger.as_ref().unwrap() + } + /// Return a mutable reference to the debugging interface. + /// + /// # Panics + /// + /// Panics if the debugging interface is not set. + #[cfg(feature = "debugging")] + pub fn debugger_mut(&mut self) -> &mut super::Debugger { + self.debugger.as_mut().unwrap() + } } #[cfg(not(feature = "no_module"))] impl, M: Into> Extend<(K, M)> for GlobalRuntimeState { #[inline] fn extend>(&mut self, iter: T) { + if self.imports.is_none() { + self.imports = Some(crate::StaticVec::new_const().into()); + self.modules = Some(crate::StaticVec::new_const().into()); + } + + let imports = self.imports.as_mut().unwrap(); + let modules = self.modules.as_mut().unwrap(); + for (k, m) in iter { - self.imports.push(k.into()); - self.modules.push(m.into()); + imports.push(k.into()); + modules.push(m.into()); } } } diff --git a/src/eval/stmt.rs b/src/eval/stmt.rs index dca988dc..d0ddbfcc 100644 --- a/src/eval/stmt.rs +++ b/src/eval/stmt.rs @@ -194,7 +194,9 @@ impl Engine { #[cfg(feature = "debugging")] let reset = self.run_debugger_with_reset(global, caches, scope, this_ptr, stmt)?; #[cfg(feature = "debugging")] - let global = &mut *RestoreOnDrop::lock(global, move |g| g.debugger.reset_status(reset)); + let global = &mut *RestoreOnDrop::lock_if(reset.is_some(), global, move |g| { + g.debugger_mut().reset_status(reset) + }); // Coded this way for better branch prediction. // Popular branches are lifted out of the `match` statement into their own branches. diff --git a/src/func/call.rs b/src/func/call.rs index 932f4f3f..532c0892 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -364,7 +364,10 @@ impl Engine { // Push a new call stack frame #[cfg(feature = "debugging")] - let orig_call_stack_len = global.debugger.call_stack().len(); + let orig_call_stack_len = global + .debugger + .as_ref() + .map_or(0, |dbg| dbg.call_stack().len()); let backup = &mut ArgBackup::new(); @@ -381,10 +384,12 @@ impl Engine { #[cfg(feature = "debugging")] if self.debugger.is_some() { - global.debugger.push_call_stack_frame( + let source = source.clone().or_else(|| global.source.clone()); + + global.debugger_mut().push_call_stack_frame( self.get_interned_string(name), args.iter().map(|v| (*v).clone()).collect(), - source.clone().or_else(|| global.source.clone()), + source, pos, ); } @@ -410,10 +415,10 @@ impl Engine { }; #[cfg(feature = "debugging")] - { + if self.debugger.is_some() { use crate::eval::{DebuggerEvent, DebuggerStatus}; - let trigger = match global.debugger.status { + let trigger = match global.debugger().status { DebuggerStatus::FunctionExit(n) => n >= global.level, DebuggerStatus::Next(.., true) => true, _ => false, @@ -436,7 +441,7 @@ impl Engine { } // Pop the call stack - global.debugger.rewind_call_stack(orig_call_stack_len); + global.debugger_mut().rewind_call_stack(orig_call_stack_len); } let result = _result?; @@ -714,11 +719,15 @@ impl Engine { // Do not match function exit for arguments #[cfg(feature = "debugging")] - let reset = global.debugger.clear_status_if(|status| { - matches!(status, crate::eval::DebuggerStatus::FunctionExit(..)) + let reset = global.debugger.as_mut().and_then(|dbg| { + dbg.clear_status_if(|status| { + matches!(status, crate::eval::DebuggerStatus::FunctionExit(..)) + }) }); #[cfg(feature = "debugging")] - let global = &mut *RestoreOnDrop::lock(global, move |g| g.debugger.reset_status(reset)); + let global = &mut *RestoreOnDrop::lock_if(reset.is_some(), global, move |g| { + g.debugger_mut().reset_status(reset) + }); self.eval_expr(global, caches, scope, this_ptr, arg_expr) .map(|r| (r, arg_expr.start_position())) diff --git a/src/func/script.rs b/src/func/script.rs index 55ba1361..efdc69de 100644 --- a/src/func/script.rs +++ b/src/func/script.rs @@ -83,7 +83,10 @@ impl Engine { let orig_imports_len = global.num_imports(); #[cfg(feature = "debugging")] - let orig_call_stack_len = global.debugger.call_stack().len(); + let orig_call_stack_len = global + .debugger + .as_ref() + .map_or(0, |dbg| dbg.call_stack().len()); // Put arguments into scope as variables scope.extend(fn_def.params.iter().cloned().zip(args.iter_mut().map(|v| { @@ -94,10 +97,12 @@ impl Engine { // Push a new call stack frame #[cfg(feature = "debugging")] if self.debugger.is_some() { - global.debugger.push_call_stack_frame( + let source = global.source.clone(); + + global.debugger_mut().push_call_stack_frame( fn_def.name.clone(), scope.iter().skip(orig_scope_len).map(|(.., v)| v).collect(), - global.source.clone(), + source, pos, ); } @@ -126,7 +131,7 @@ impl Engine { }; #[cfg(feature = "debugging")] - { + if self.debugger.is_some() { let node = crate::ast::Stmt::Noop(fn_def.body.position()); self.run_debugger(global, caches, scope, this_ptr, &node)?; } @@ -156,12 +161,13 @@ impl Engine { }); #[cfg(feature = "debugging")] - { - let trigger = match global.debugger.status { + if self.debugger.is_some() { + let trigger = match global.debugger_mut().status { crate::eval::DebuggerStatus::FunctionExit(n) => n >= global.level, crate::eval::DebuggerStatus::Next(.., true) => true, _ => false, }; + if trigger { let node = crate::ast::Stmt::Noop(fn_def.body.end_position().or_else(pos)); let node = (&node).into(); @@ -176,7 +182,11 @@ impl Engine { } // Pop the call stack - global.debugger.rewind_call_stack(orig_call_stack_len); + global + .debugger + .as_mut() + .unwrap() + .rewind_call_stack(orig_call_stack_len); } // Remove all local variables and imported modules diff --git a/src/packages/debugging.rs b/src/packages/debugging.rs index 1256102a..c6b2a87e 100644 --- a/src/packages/debugging.rs +++ b/src/packages/debugging.rs @@ -36,49 +36,55 @@ mod debugging_functions { pub fn back_trace(ctx: NativeCallContext) -> Array { use crate::debugger::CallStackFrame; - ctx.global_runtime_state() - .debugger - .call_stack() - .iter() - .rev() - .filter(|CallStackFrame { fn_name, args, .. }| { - fn_name.as_str() != "back_trace" || !args.is_empty() - }) - .map( - |frame @ CallStackFrame { - fn_name: _fn_name, - args: _args, - source: _source, - pos: _pos, - }| { - let display = frame.to_string(); + if let Some(ref debugger) = ctx.global_runtime_state().debugger { + debugger + .call_stack() + .iter() + .rev() + .filter(|CallStackFrame { fn_name, args, .. }| { + fn_name.as_str() != "back_trace" || !args.is_empty() + }) + .map( + |frame @ CallStackFrame { + fn_name: _fn_name, + args: _args, + source: _source, + pos: _pos, + }| { + let display = frame.to_string(); - #[cfg(not(feature = "no_object"))] - { - use crate::INT; + #[cfg(not(feature = "no_object"))] + { + use crate::INT; - let mut map = Map::new(); - map.insert("display".into(), display.into()); - map.insert("fn_name".into(), _fn_name.into()); - if !_args.is_empty() { - map.insert("args".into(), Dynamic::from_array(_args.clone().to_vec())); + let mut map = Map::new(); + map.insert("display".into(), display.into()); + map.insert("fn_name".into(), _fn_name.into()); + if !_args.is_empty() { + map.insert( + "args".into(), + Dynamic::from_array(_args.clone().to_vec()), + ); + } + if let Some(source) = _source { + map.insert("source".into(), source.into()); + } + if !_pos.is_none() { + map.insert("line".into(), (_pos.line().unwrap() as INT).into()); + map.insert( + "position".into(), + (_pos.position().unwrap_or(0) as INT).into(), + ); + } + Dynamic::from_map(map) } - if let Some(source) = _source { - map.insert("source".into(), source.into()); - } - if !_pos.is_none() { - map.insert("line".into(), (_pos.line().unwrap() as INT).into()); - map.insert( - "position".into(), - (_pos.position().unwrap_or(0) as INT).into(), - ); - } - Dynamic::from_map(map) - } - #[cfg(feature = "no_object")] - display.into() - }, - ) - .collect() + #[cfg(feature = "no_object")] + display.into() + }, + ) + .collect() + } else { + Array::new() + } } } diff --git a/src/packages/string_more.rs b/src/packages/string_more.rs index 5670e421..400ea159 100644 --- a/src/packages/string_more.rs +++ b/src/packages/string_more.rs @@ -1,8 +1,8 @@ use crate::module::ModuleFlags; use crate::plugin::*; use crate::{ - def_package, Dynamic, ExclusiveRange, ImmutableString, InclusiveRange, RhaiResultOf, - SmartString, StaticVec, INT, MAX_USIZE_INT, ERR, Position + def_package, Dynamic, ExclusiveRange, ImmutableString, InclusiveRange, Position, RhaiResultOf, + SmartString, StaticVec, ERR, INT, MAX_USIZE_INT, }; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -1224,11 +1224,9 @@ mod string_functions { // Check if string will be over max size limit if _ctx.engine().max_string_size() > 0 && len > _ctx.engine().max_string_size() { - return Err(ERR::ErrorDataTooLarge( - "Length of string".to_string(), - Position::NONE, - ) - .into()); + return Err( + ERR::ErrorDataTooLarge("Length of string".to_string(), Position::NONE).into(), + ); } let orig_len = string.chars().count(); @@ -1242,11 +1240,9 @@ mod string_functions { if _ctx.engine().max_string_size() > 0 && string.len() > _ctx.engine().max_string_size() { - return Err(ERR::ErrorDataTooLarge( - "Length of string".to_string(), - Position::NONE, - ) - .into()); + return Err( + ERR::ErrorDataTooLarge("Length of string".to_string(), Position::NONE).into(), + ); } } @@ -1284,11 +1280,9 @@ mod string_functions { // Check if string will be over max size limit if _ctx.engine().max_string_size() > 0 && len > _ctx.engine().max_string_size() { - return Err(ERR::ErrorDataTooLarge( - "Length of string".to_string(), - Position::NONE, - ) - .into()); + return Err( + ERR::ErrorDataTooLarge("Length of string".to_string(), Position::NONE).into(), + ); } let mut str_len = string.chars().count(); @@ -1309,11 +1303,9 @@ mod string_functions { if _ctx.engine().max_string_size() > 0 && string.len() > _ctx.engine().max_string_size() { - return Err(ERR::ErrorDataTooLarge( - "Length of string".to_string(), - Position::NONE, - ) - .into()); + return Err( + ERR::ErrorDataTooLarge("Length of string".to_string(), Position::NONE).into(), + ); } } diff --git a/tests/debugging.rs b/tests/debugging.rs index a35d41fc..762ed9d2 100644 --- a/tests/debugging.rs +++ b/tests/debugging.rs @@ -59,13 +59,13 @@ fn test_debugger_state() -> Result<(), Box> { // Print debugger state - which is an object map println!( "Current state = {}", - context.global_runtime_state_mut().debugger.state() + context.global_runtime_state_mut().debugger().state() ); // Modify state let mut state = context .global_runtime_state_mut() - .debugger + .debugger_mut() .state_mut() .write_lock::() .unwrap();