Simplify debugger calls.

This commit is contained in:
Stephen Chung 2022-02-03 11:56:08 +08:00
parent 8322e62c18
commit 9fa6839380
6 changed files with 90 additions and 111 deletions

View File

@ -156,9 +156,7 @@ impl Engine {
if !_terminate_chaining => if !_terminate_chaining =>
{ {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
if self.debugger.is_some() {
self.run_debugger(scope, global, state, lib, this_ptr, _parent, level)?; self.run_debugger(scope, global, state, lib, this_ptr, _parent, level)?;
}
let mut idx_val_for_setter = idx_val.clone(); let mut idx_val_for_setter = idx_val.clone();
let idx_pos = x.lhs.position(); let idx_pos = x.lhs.position();
@ -206,9 +204,7 @@ impl Engine {
// xxx[rhs] op= new_val // xxx[rhs] op= new_val
_ if new_val.is_some() => { _ if new_val.is_some() => {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
if self.debugger.is_some() {
self.run_debugger(scope, global, state, lib, this_ptr, _parent, level)?; self.run_debugger(scope, global, state, lib, this_ptr, _parent, level)?;
}
let ((new_val, new_pos), (op_info, op_pos)) = new_val.expect("`Some`"); let ((new_val, new_pos), (op_info, op_pos)) = new_val.expect("`Some`");
let mut idx_val_for_setter = idx_val.clone(); let mut idx_val_for_setter = idx_val.clone();
@ -254,9 +250,7 @@ impl Engine {
// xxx[rhs] // xxx[rhs]
_ => { _ => {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
if self.debugger.is_some() {
self.run_debugger(scope, global, state, lib, this_ptr, _parent, level)?; self.run_debugger(scope, global, state, lib, this_ptr, _parent, level)?;
}
self.get_indexed_mut( self.get_indexed_mut(
global, state, lib, target, idx_val, pos, false, true, level, global, state, lib, target, idx_val, pos, false, true, level,
@ -275,13 +269,9 @@ impl Engine {
let call_args = &mut idx_val.into_fn_call_args(); let call_args = &mut idx_val.into_fn_call_args();
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
let reset_debugger = if self.debugger.is_some() { let reset_debugger = self.run_debugger_with_reset(
self.run_debugger_with_reset(
scope, global, state, lib, this_ptr, rhs, level, scope, global, state, lib, this_ptr, rhs, level,
)? )?;
} else {
None
};
let result = self.make_method_call( let result = self.make_method_call(
global, state, lib, name, *hashes, target, call_args, *pos, level, global, state, lib, name, *hashes, target, call_args, *pos, level,
@ -303,9 +293,7 @@ impl Engine {
// {xxx:map}.id op= ??? // {xxx:map}.id op= ???
Expr::Property(x, pos) if target.is::<crate::Map>() && new_val.is_some() => { Expr::Property(x, pos) if target.is::<crate::Map>() && new_val.is_some() => {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
if self.debugger.is_some() {
self.run_debugger(scope, global, state, lib, this_ptr, rhs, level)?; self.run_debugger(scope, global, state, lib, this_ptr, rhs, level)?;
}
let index = x.2.clone().into(); let index = x.2.clone().into();
let ((new_val, new_pos), (op_info, op_pos)) = new_val.expect("`Some`"); let ((new_val, new_pos), (op_info, op_pos)) = new_val.expect("`Some`");
@ -326,9 +314,7 @@ impl Engine {
// {xxx:map}.id // {xxx:map}.id
Expr::Property(x, pos) if target.is::<crate::Map>() => { Expr::Property(x, pos) if target.is::<crate::Map>() => {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
if self.debugger.is_some() {
self.run_debugger(scope, global, state, lib, this_ptr, rhs, level)?; self.run_debugger(scope, global, state, lib, this_ptr, rhs, level)?;
}
let index = x.2.clone().into(); let index = x.2.clone().into();
let val = self.get_indexed_mut( let val = self.get_indexed_mut(
@ -339,9 +325,7 @@ impl Engine {
// xxx.id op= ??? // xxx.id op= ???
Expr::Property(x, pos) if new_val.is_some() => { Expr::Property(x, pos) if new_val.is_some() => {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
if self.debugger.is_some() {
self.run_debugger(scope, global, state, lib, this_ptr, rhs, level)?; self.run_debugger(scope, global, state, lib, this_ptr, rhs, level)?;
}
let ((getter, hash_get), (setter, hash_set), name) = x.as_ref(); 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`"); let ((mut new_val, new_pos), (op_info, op_pos)) = new_val.expect("`Some`");
@ -421,9 +405,7 @@ impl Engine {
// xxx.id // xxx.id
Expr::Property(x, pos) => { Expr::Property(x, pos) => {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
if self.debugger.is_some() {
self.run_debugger(scope, global, state, lib, this_ptr, rhs, level)?; self.run_debugger(scope, global, state, lib, this_ptr, rhs, level)?;
}
let ((getter, hash_get), _, name) = x.as_ref(); let ((getter, hash_get), _, name) = x.as_ref();
let hash = crate::ast::FnCallHashes::from_native(*hash_get); let hash = crate::ast::FnCallHashes::from_native(*hash_get);
@ -463,11 +445,9 @@ impl Engine {
let val_target = &mut match x.lhs { let val_target = &mut match x.lhs {
Expr::Property(ref p, pos) => { Expr::Property(ref p, pos) => {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
if self.debugger.is_some() {
self.run_debugger( self.run_debugger(
scope, global, state, lib, this_ptr, _node, level, scope, global, state, lib, this_ptr, _node, level,
)?; )?;
}
let index = p.2.clone().into(); let index = p.2.clone().into();
self.get_indexed_mut( self.get_indexed_mut(
@ -480,13 +460,9 @@ impl Engine {
let call_args = &mut idx_val.into_fn_call_args(); let call_args = &mut idx_val.into_fn_call_args();
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
let reset_debugger = if self.debugger.is_some() { let reset_debugger = self.run_debugger_with_reset(
self.run_debugger_with_reset(
scope, global, state, lib, this_ptr, _node, level, scope, global, state, lib, this_ptr, _node, level,
)? )?;
} else {
None
};
let result = self.make_method_call( let result = self.make_method_call(
global, state, lib, name, *hashes, target, call_args, pos, global, state, lib, name, *hashes, target, call_args, pos,
@ -521,11 +497,9 @@ impl Engine {
// xxx.prop[expr] | xxx.prop.expr // xxx.prop[expr] | xxx.prop.expr
Expr::Property(ref p, pos) => { Expr::Property(ref p, pos) => {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
if self.debugger.is_some() {
self.run_debugger( self.run_debugger(
scope, global, state, lib, this_ptr, _node, level, scope, global, state, lib, this_ptr, _node, level,
)?; )?;
}
let ((getter, hash_get), (setter, hash_set), name) = p.as_ref(); let ((getter, hash_get), (setter, hash_set), name) = p.as_ref();
let rhs_chain = rhs.into(); let rhs_chain = rhs.into();
@ -626,13 +600,9 @@ impl Engine {
let args = &mut idx_val.into_fn_call_args(); let args = &mut idx_val.into_fn_call_args();
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
let reset_debugger = if self.debugger.is_some() { let reset_debugger = self.run_debugger_with_reset(
self.run_debugger_with_reset(
scope, global, state, lib, this_ptr, _node, level, scope, global, state, lib, this_ptr, _node, level,
)? )?;
} else {
None
};
let result = self.make_method_call( let result = self.make_method_call(
global, state, lib, name, *hashes, target, args, pos, level, global, state, lib, name, *hashes, target, args, pos, level,
@ -697,9 +667,7 @@ impl Engine {
// id.??? or id[???] // id.??? or id[???]
Expr::Variable(_, var_pos, x) => { Expr::Variable(_, var_pos, x) => {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
if self.debugger.is_some() {
self.run_debugger(scope, global, state, lib, this_ptr, lhs, level)?; self.run_debugger(scope, global, state, lib, this_ptr, lhs, level)?;
}
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
self.inc_operations(&mut global.num_operations, *var_pos)?; self.inc_operations(&mut global.num_operations, *var_pos)?;

View File

@ -4,9 +4,9 @@
use super::{EvalContext, EvalState, GlobalRuntimeState}; use super::{EvalContext, EvalState, GlobalRuntimeState};
use crate::ast::{ASTNode, Expr, Stmt}; use crate::ast::{ASTNode, Expr, Stmt};
use crate::{Dynamic, Engine, EvalAltResult, Identifier, Module, Position, RhaiResultOf, Scope}; use crate::{Dynamic, Engine, EvalAltResult, Identifier, Module, Position, RhaiResultOf, Scope};
use std::fmt;
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
use std::{fmt, mem};
/// Callback function to initialize the debugger. /// Callback function to initialize the debugger.
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
@ -319,13 +319,27 @@ impl Debugger {
pos, pos,
}); });
} }
/// Set the status of this [`Debugger`]. /// Change the current status to [`CONTINUE`][DebuggerStatus::CONTINUE] and return the previous status.
pub(crate) fn clear_status_if(
&mut self,
filter: impl Fn(&DebuggerStatus) -> bool,
) -> Option<DebuggerStatus> {
if filter(&self.status) {
Some(mem::replace(&mut self.status, DebuggerStatus::CONTINUE))
} else {
None
}
}
/// Override the status of this [`Debugger`] if it is [`Some`] the current status is
/// [`CONTINUE`][DebuggerStatus::CONTINUE].
#[inline(always)] #[inline(always)]
pub(crate) fn reset_status(&mut self, status: Option<DebuggerStatus>) { pub(crate) fn reset_status(&mut self, status: Option<DebuggerStatus>) {
if self.status == DebuggerStatus::CONTINUE {
if let Some(cmd) = status { if let Some(cmd) = status {
self.status = cmd; self.status = cmd;
} }
} }
}
/// Returns the first break-point triggered by a particular [`AST` Node][ASTNode]. /// Returns the first break-point triggered by a particular [`AST` Node][ASTNode].
#[must_use] #[must_use]
pub fn is_break_point(&self, src: &str, node: ASTNode) -> Option<usize> { pub fn is_break_point(&self, src: &str, node: ASTNode) -> Option<usize> {
@ -383,7 +397,7 @@ impl Debugger {
} }
impl Engine { impl Engine {
/// Run the debugger callback. /// Run the debugger callback if there is a debugging interface registered.
#[inline(always)] #[inline(always)]
pub(crate) fn run_debugger<'a>( pub(crate) fn run_debugger<'a>(
&self, &self,
@ -395,14 +409,40 @@ impl Engine {
node: impl Into<ASTNode<'a>>, node: impl Into<ASTNode<'a>>,
level: usize, level: usize,
) -> RhaiResultOf<()> { ) -> RhaiResultOf<()> {
if self.debugger.is_some() {
if let Some(cmd) = if let Some(cmd) =
self.run_debugger_with_reset(scope, global, state, lib, this_ptr, node, level)? self.run_debugger_with_reset_raw(scope, global, state, lib, this_ptr, node, level)?
{ {
global.debugger.status = cmd; global.debugger.status = cmd;
} }
}
Ok(()) Ok(())
} }
/// Run the debugger callback if there is a debugging interface registered.
///
/// Returns `Some` if the debugger needs to be reactivated at the end of the block, statement or
/// function call.
///
/// It is up to the [`Engine`] to reactivate the debugger.
#[inline(always)]
#[must_use]
pub(crate) fn run_debugger_with_reset<'a>(
&self,
scope: &mut Scope,
global: &mut GlobalRuntimeState,
state: &mut EvalState,
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, state, lib, this_ptr, node, level)
} else {
Ok(None)
}
}
/// Run the debugger callback. /// Run the debugger callback.
/// ///
/// Returns `Some` if the debugger needs to be reactivated at the end of the block, statement or /// Returns `Some` if the debugger needs to be reactivated at the end of the block, statement or
@ -411,7 +451,7 @@ impl Engine {
/// It is up to the [`Engine`] to reactivate the debugger. /// It is up to the [`Engine`] to reactivate the debugger.
#[inline] #[inline]
#[must_use] #[must_use]
pub(crate) fn run_debugger_with_reset<'a>( pub(crate) fn run_debugger_with_reset_raw<'a>(
&self, &self,
scope: &mut Scope, scope: &mut Scope,
global: &mut GlobalRuntimeState, global: &mut GlobalRuntimeState,
@ -513,7 +553,6 @@ impl Engine {
| ASTNode::Stmt(Stmt::Expr(Expr::FnCall(_, _))) => context.call_level() + 1, | ASTNode::Stmt(Stmt::Expr(Expr::FnCall(_, _))) => context.call_level() + 1,
_ => context.call_level(), _ => context.call_level(),
}; };
println!("Set FunctionExit to {}", level);
global.debugger.status = DebuggerStatus::FunctionExit(level); global.debugger.status = DebuggerStatus::FunctionExit(level);
Ok(None) Ok(None)
} }

View File

@ -266,11 +266,8 @@ impl Engine {
// binary operators are also function calls. // binary operators are also function calls.
if let Expr::FnCall(x, pos) = expr { if let Expr::FnCall(x, pos) = expr {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
let reset_debugger = if self.debugger.is_some() { let reset_debugger =
self.run_debugger_with_reset(scope, global, state, lib, this_ptr, expr, level)? self.run_debugger_with_reset(scope, global, state, lib, this_ptr, expr, level)?;
} else {
None
};
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
self.inc_operations(&mut global.num_operations, expr.position())?; self.inc_operations(&mut global.num_operations, expr.position())?;
@ -289,9 +286,7 @@ impl Engine {
// will cost more than the mis-predicted `match` branch. // will cost more than the mis-predicted `match` branch.
if let Expr::Variable(index, var_pos, x) = expr { if let Expr::Variable(index, var_pos, x) = expr {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
if self.debugger.is_some() {
self.run_debugger(scope, global, state, lib, this_ptr, expr, level)?; self.run_debugger(scope, global, state, lib, this_ptr, expr, level)?;
}
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
self.inc_operations(&mut global.num_operations, expr.position())?; self.inc_operations(&mut global.num_operations, expr.position())?;
@ -308,11 +303,8 @@ impl Engine {
} }
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
let reset_debugger = if self.debugger.is_some() { let reset_debugger =
self.run_debugger_with_reset(scope, global, state, lib, this_ptr, expr, level)? self.run_debugger_with_reset(scope, global, state, lib, this_ptr, expr, level)?;
} else {
None
};
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
self.inc_operations(&mut global.num_operations, expr.position())?; self.inc_operations(&mut global.num_operations, expr.position())?;

View File

@ -204,11 +204,8 @@ impl Engine {
level: usize, level: usize,
) -> RhaiResult { ) -> RhaiResult {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
let reset_debugger = if self.debugger.is_some() { let reset_debugger =
self.run_debugger_with_reset(scope, global, state, lib, this_ptr, stmt, level)? self.run_debugger_with_reset(scope, global, state, lib, this_ptr, stmt, level)?;
} else {
None
};
// Coded this way for better branch prediction. // Coded this way for better branch prediction.
// Popular branches are lifted out of the `match` statement into their own branches. // Popular branches are lifted out of the `match` statement into their own branches.

View File

@ -956,35 +956,24 @@ impl Engine {
Ok(( Ok((
if let Expr::Stack(slot, _) = arg_expr { if let Expr::Stack(slot, _) = arg_expr {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
if self.debugger.is_some() {
self.run_debugger(scope, global, state, lib, this_ptr, arg_expr, level)?; self.run_debugger(scope, global, state, lib, this_ptr, arg_expr, level)?;
}
constants[*slot].clone() constants[*slot].clone()
} else if let Some(value) = arg_expr.get_literal_value() { } else if let Some(value) = arg_expr.get_literal_value() {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
if self.debugger.is_some() {
self.run_debugger(scope, global, state, lib, this_ptr, arg_expr, level)?; self.run_debugger(scope, global, state, lib, this_ptr, arg_expr, level)?;
}
value value
} else { } else {
// Do not match function exit for arguments // Do not match function exit for arguments
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
let reset_debugger = match global.debugger.status { let reset_debugger = global.debugger.clear_status_if(|status| {
crate::eval::DebuggerStatus::FunctionExit(_) => { matches!(status, crate::eval::DebuggerStatus::FunctionExit(_))
Some(std::mem::take(&mut global.debugger.status)) });
}
_ => None,
};
let result = self.eval_expr(scope, global, state, lib, this_ptr, arg_expr, level); let result = self.eval_expr(scope, global, state, lib, this_ptr, arg_expr, level);
// Restore function exit if status is not active // Restore function exit status
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
if self.debugger.is_some()
&& global.debugger.status == crate::eval::DebuggerStatus::CONTINUE
{
global.debugger.reset_status(reset_debugger); global.debugger.reset_status(reset_debugger);
}
result? result?
}, },
@ -1229,9 +1218,7 @@ impl Engine {
let first_expr = first_arg.unwrap(); let first_expr = first_arg.unwrap();
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
if self.debugger.is_some() {
self.run_debugger(scope, global, state, lib, this_ptr, first_expr, level)?; self.run_debugger(scope, global, state, lib, this_ptr, first_expr, level)?;
}
// func(x, ...) -> x.func(...) // func(x, ...) -> x.func(...)
a_expr.iter().try_for_each(|expr| { a_expr.iter().try_for_each(|expr| {
@ -1315,10 +1302,7 @@ impl Engine {
// &mut first argument and avoid cloning the value // &mut first argument and avoid cloning the value
if !args_expr.is_empty() && args_expr[0].is_variable_access(true) { if !args_expr.is_empty() && args_expr[0].is_variable_access(true) {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
if self.debugger.is_some() { self.run_debugger(scope, global, state, lib, this_ptr, &args_expr[0], level)?;
let node = &args_expr[0];
self.run_debugger(scope, global, state, lib, this_ptr, node, level)?;
}
// func(x, ...) -> x.func(...) // func(x, ...) -> x.func(...)
arg_values.push(Dynamic::UNIT); arg_values.push(Dynamic::UNIT);

View File

@ -142,8 +142,7 @@ impl Engine {
}; };
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
if self.debugger.is_some() { {
println!("Level = {}", level);
let node = crate::ast::Stmt::Noop(fn_def.body.position()); let node = crate::ast::Stmt::Noop(fn_def.body.position());
self.run_debugger(scope, global, state, lib, this_ptr, &node, level)?; self.run_debugger(scope, global, state, lib, this_ptr, &node, level)?;
} }