rhai/src/eval/debugger.rs

554 lines
18 KiB
Rust
Raw Normal View History

2022-01-24 17:04:40 +08:00
//! Module defining the debugging interface.
#![cfg(feature = "debugging")]
2022-11-04 21:47:09 +08:00
use super::{Caches, EvalContext, GlobalRuntimeState};
2022-01-24 17:04:40 +08:00
use crate::ast::{ASTNode, Expr, Stmt};
2022-11-10 11:49:10 +08:00
use crate::{Dynamic, Engine, EvalAltResult, ImmutableString, Position, RhaiResultOf, Scope};
2022-01-24 17:04:40 +08:00
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
2022-04-13 10:35:10 +08:00
use std::{fmt, iter::repeat, mem};
2022-01-24 17:04:40 +08:00
2022-01-28 18:59:18 +08:00
/// Callback function to initialize the debugger.
#[cfg(not(feature = "sync"))]
2022-08-20 15:04:17 +08:00
pub type OnDebuggingInit = dyn Fn(&Engine) -> Dynamic;
2022-01-28 18:59:18 +08:00
/// Callback function to initialize the debugger.
#[cfg(feature = "sync")]
2022-08-20 15:04:17 +08:00
pub type OnDebuggingInit = dyn Fn(&Engine) -> Dynamic + Send + Sync;
2022-01-28 18:59:18 +08:00
/// Callback function for debugging.
2022-01-24 17:04:40 +08:00
#[cfg(not(feature = "sync"))]
pub type OnDebuggerCallback = dyn Fn(
2022-05-02 00:03:45 +08:00
EvalContext,
DebuggerEvent,
ASTNode,
Option<&str>,
Position,
) -> RhaiResultOf<DebuggerCommand>;
2022-01-28 18:59:18 +08:00
/// Callback function for debugging.
2022-01-24 17:04:40 +08:00
#[cfg(feature = "sync")]
2022-05-02 00:03:45 +08:00
pub type OnDebuggerCallback = dyn Fn(EvalContext, DebuggerEvent, ASTNode, Option<&str>, Position) -> RhaiResultOf<DebuggerCommand>
2022-01-27 23:55:32 +08:00
+ Send
+ Sync;
2022-01-24 17:04:40 +08:00
/// A command for the debugger on the next iteration.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
2022-04-26 16:36:24 +08:00
#[non_exhaustive]
2022-01-24 17:04:40 +08:00
pub enum DebuggerCommand {
2022-06-05 18:17:44 +08:00
/// Continue normal execution.
2022-01-24 17:04:40 +08:00
Continue,
2022-06-05 18:17:44 +08:00
/// Step into the next expression, diving into functions.
2022-01-24 17:04:40 +08:00
StepInto,
2022-06-05 18:17:44 +08:00
/// Run to the next expression or statement, stepping over functions.
2022-01-24 17:04:40 +08:00
StepOver,
2022-06-05 18:17:44 +08:00
/// Run to the next statement, skipping over functions.
Next,
2022-06-05 18:17:44 +08:00
/// Run to the end of the current function call.
FunctionExit,
}
impl Default for DebuggerCommand {
#[inline(always)]
2022-09-28 12:06:22 +08:00
#[must_use]
fn default() -> Self {
Self::Continue
}
}
/// The debugger status.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
2022-04-26 16:36:24 +08:00
#[non_exhaustive]
pub enum DebuggerStatus {
2022-04-26 16:36:24 +08:00
// Script evaluation starts.
Init,
// Stop at the next statement or expression.
Next(bool, bool),
// Run to the end of the current level of function call.
FunctionExit(usize),
2022-04-26 16:36:24 +08:00
// Script evaluation ends.
Terminate,
}
impl DebuggerStatus {
pub const CONTINUE: Self = Self::Next(false, false);
pub const STEP: Self = Self::Next(true, true);
pub const NEXT: Self = Self::Next(true, false);
2022-04-26 16:36:24 +08:00
pub const INTO: Self = Self::Next(false, true);
}
/// A event that triggers the debugger.
#[derive(Debug, Clone, Copy)]
2022-04-26 16:36:24 +08:00
#[non_exhaustive]
pub enum DebuggerEvent<'a> {
2022-06-05 18:17:44 +08:00
/// Script evaluation starts.
2022-04-26 16:36:24 +08:00
Start,
2022-06-05 18:17:44 +08:00
/// Break on next step.
Step,
2022-06-05 18:17:44 +08:00
/// Break on break-point.
BreakPoint(usize),
2022-06-05 18:17:44 +08:00
/// Return from a function with a value.
FunctionExitWithValue(&'a Dynamic),
2022-06-05 18:17:44 +08:00
/// Return from a function with a value.
FunctionExitWithError(&'a EvalAltResult),
2022-06-05 18:17:44 +08:00
/// Script evaluation ends.
2022-04-26 16:36:24 +08:00
End,
2022-01-24 17:04:40 +08:00
}
/// A break-point for debugging.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
2022-04-26 16:36:24 +08:00
#[non_exhaustive]
2022-01-24 17:04:40 +08:00
pub enum BreakPoint {
/// Break at a particular position under a particular source.
2022-01-25 23:59:35 +08:00
///
2022-01-24 17:04:40 +08:00
/// Not available under `no_position`.
#[cfg(not(feature = "no_position"))]
2022-01-25 17:29:34 +08:00
AtPosition {
2022-06-05 18:17:44 +08:00
/// Source (empty if not available) of the break-point.
2022-10-29 14:59:20 +08:00
source: Option<ImmutableString>,
2022-06-05 18:17:44 +08:00
/// [Position] of the break-point.
2022-01-25 17:29:34 +08:00
pos: Position,
2022-06-05 18:17:44 +08:00
/// Is the break-point enabled?
2022-01-25 17:29:34 +08:00
enabled: bool,
},
2022-01-24 17:04:40 +08:00
/// Break at a particular function call.
2022-06-05 18:17:44 +08:00
AtFunctionName {
/// Function name.
2022-10-29 14:59:20 +08:00
name: ImmutableString,
2022-06-05 18:17:44 +08:00
/// Is the break-point enabled?
enabled: bool,
},
2022-01-24 17:04:40 +08:00
/// Break at a particular function call with a particular number of arguments.
2022-01-25 17:29:34 +08:00
AtFunctionCall {
2022-06-05 18:17:44 +08:00
/// Function name.
2022-10-29 14:59:20 +08:00
name: ImmutableString,
2022-06-05 18:17:44 +08:00
/// Number of arguments.
2022-01-25 17:29:34 +08:00
args: usize,
2022-06-05 18:17:44 +08:00
/// Is the break-point enabled?
2022-01-25 17:29:34 +08:00
enabled: bool,
},
2022-01-25 18:21:05 +08:00
/// Break at a particular property .
2022-01-25 23:59:35 +08:00
///
/// Not available under `no_object`.
#[cfg(not(feature = "no_object"))]
2022-06-05 18:17:44 +08:00
AtProperty {
/// Property name.
2022-10-29 14:59:20 +08:00
name: ImmutableString,
2022-06-05 18:17:44 +08:00
/// Is the break-point enabled?
enabled: bool,
},
2022-01-24 17:04:40 +08:00
}
impl fmt::Display for BreakPoint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
2022-01-25 23:59:35 +08:00
#[cfg(not(feature = "no_position"))]
2022-01-25 17:29:34 +08:00
Self::AtPosition {
source,
pos,
enabled,
} => {
2022-10-29 14:59:20 +08:00
if let Some(ref source) = source {
write!(f, "{source} ")?;
2022-01-25 17:29:34 +08:00
}
write!(f, "@ {pos:?}")?;
2022-01-25 17:29:34 +08:00
if !*enabled {
f.write_str(" (disabled)")?;
}
Ok(())
}
Self::AtFunctionName { name, enabled } => {
write!(f, "{name} (...)")?;
2022-01-25 17:29:34 +08:00
if !*enabled {
f.write_str(" (disabled)")?;
2022-01-24 17:04:40 +08:00
}
2022-01-25 17:29:34 +08:00
Ok(())
2022-01-24 17:04:40 +08:00
}
2022-01-25 12:24:30 +08:00
Self::AtFunctionCall {
name,
2022-01-25 12:24:30 +08:00
args,
2022-01-25 17:29:34 +08:00
enabled,
} => {
write!(
f,
"{name} ({})",
2022-04-13 10:35:10 +08:00
repeat("_").take(*args).collect::<Vec<_>>().join(", ")
2022-01-25 17:29:34 +08:00
)?;
if !*enabled {
f.write_str(" (disabled)")?;
}
Ok(())
}
2022-01-25 23:59:35 +08:00
#[cfg(not(feature = "no_object"))]
Self::AtProperty { name, enabled } => {
write!(f, ".{name}")?;
2022-01-25 18:21:05 +08:00
if !*enabled {
f.write_str(" (disabled)")?;
}
Ok(())
}
2022-01-25 17:29:34 +08:00
}
}
}
impl BreakPoint {
/// Is this [`BreakPoint`] enabled?
#[inline(always)]
2022-07-27 18:04:59 +08:00
#[must_use]
2022-11-23 13:24:14 +08:00
pub const fn is_enabled(&self) -> bool {
2022-01-25 17:29:34 +08:00
match self {
#[cfg(not(feature = "no_position"))]
Self::AtPosition { enabled, .. } => *enabled,
2022-01-25 23:59:35 +08:00
Self::AtFunctionName { enabled, .. } | Self::AtFunctionCall { enabled, .. } => *enabled,
#[cfg(not(feature = "no_object"))]
Self::AtProperty { enabled, .. } => *enabled,
2022-01-25 17:29:34 +08:00
}
}
/// Enable/disable this [`BreakPoint`].
#[inline(always)]
pub fn enable(&mut self, value: bool) {
match self {
#[cfg(not(feature = "no_position"))]
Self::AtPosition { enabled, .. } => *enabled = value,
2022-01-25 23:59:35 +08:00
Self::AtFunctionName { enabled, .. } | Self::AtFunctionCall { enabled, .. } => {
*enabled = value
}
#[cfg(not(feature = "no_object"))]
Self::AtProperty { enabled, .. } => *enabled = value,
2022-01-24 17:04:40 +08:00
}
}
}
2022-01-25 12:24:30 +08:00
/// A function call.
2022-01-24 17:04:40 +08:00
#[derive(Debug, Clone, Hash)]
pub struct CallStackFrame {
2022-01-25 23:59:35 +08:00
/// Function name.
2022-10-29 14:59:20 +08:00
pub fn_name: ImmutableString,
2022-01-25 23:59:35 +08:00
/// Copies of function call arguments, if any.
2022-01-25 14:32:07 +08:00
pub args: crate::StaticVec<Dynamic>,
2022-10-29 14:12:18 +08:00
/// Source of the function.
pub source: Option<ImmutableString>,
2022-01-25 23:59:35 +08:00
/// [Position][`Position`] of the function call.
2022-01-24 17:04:40 +08:00
pub pos: Position,
}
impl fmt::Display for CallStackFrame {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut fp = f.debug_tuple(&self.fn_name);
for arg in &self.args {
fp.field(arg);
}
fp.finish()?;
if !self.pos.is_none() {
2022-10-29 14:12:18 +08:00
if let Some(ref source) = self.source {
write!(f, ": {source}")?;
2022-01-24 17:04:40 +08:00
}
write!(f, " @ {:?}", self.pos)?;
2022-01-24 17:04:40 +08:00
}
Ok(())
}
}
/// A type providing debugging facilities.
#[derive(Debug, Clone, Hash)]
pub struct Debugger {
2022-01-25 23:59:35 +08:00
/// The current status command.
pub(crate) status: DebuggerStatus,
2022-01-25 23:59:35 +08:00
/// The current set of break-points.
2022-01-24 17:04:40 +08:00
break_points: Vec<BreakPoint>,
2022-01-25 23:59:35 +08:00
/// The current function call stack.
2022-01-24 17:04:40 +08:00
call_stack: Vec<CallStackFrame>,
/// The current state.
state: Dynamic,
2022-01-24 17:04:40 +08:00
}
impl Debugger {
2022-05-03 21:55:01 +08:00
/// Create a new [`Debugger`].
2022-01-28 18:59:18 +08:00
#[inline(always)]
#[must_use]
2022-11-23 13:24:14 +08:00
pub const fn new(status: DebuggerStatus, state: Dynamic) -> Self {
2022-01-24 17:04:40 +08:00
Self {
2022-05-03 21:55:01 +08:00
status,
2022-01-24 17:04:40 +08:00
break_points: Vec::new(),
call_stack: Vec::new(),
state,
2022-01-24 17:04:40 +08:00
}
}
2022-01-25 12:24:30 +08:00
/// Get the current call stack.
#[inline(always)]
2022-01-28 18:59:18 +08:00
#[must_use]
2022-01-25 12:24:30 +08:00
pub fn call_stack(&self) -> &[CallStackFrame] {
&self.call_stack
}
2022-01-24 17:04:40 +08:00
/// Rewind the function call stack to a particular depth.
#[inline(always)]
2022-01-25 12:24:30 +08:00
pub(crate) fn rewind_call_stack(&mut self, len: usize) {
2022-01-24 17:04:40 +08:00
self.call_stack.truncate(len);
}
/// Add a new frame to the function call stack.
#[inline(always)]
2022-01-25 12:24:30 +08:00
pub(crate) fn push_call_stack_frame(
2022-01-24 17:04:40 +08:00
&mut self,
2022-10-29 14:59:20 +08:00
fn_name: ImmutableString,
2022-01-25 14:32:07 +08:00
args: crate::StaticVec<Dynamic>,
2022-10-29 14:12:18 +08:00
source: Option<ImmutableString>,
2022-01-24 17:04:40 +08:00
pos: Position,
) {
2022-01-25 12:24:30 +08:00
self.call_stack.push(CallStackFrame {
2022-11-23 13:24:14 +08:00
fn_name,
2022-01-24 17:04:40 +08:00
args,
2022-10-29 14:12:18 +08:00
source,
2022-01-24 17:04:40 +08:00
pos,
2022-01-25 12:24:30 +08:00
});
2022-01-24 17:04:40 +08:00
}
2022-02-03 11:56:08 +08:00
/// Change the current status to [`CONTINUE`][DebuggerStatus::CONTINUE] and return the previous status.
pub(crate) fn clear_status_if(
&mut self,
2022-06-08 16:34:56 +08:00
filter: impl FnOnce(&DebuggerStatus) -> bool,
2022-02-03 11:56:08 +08:00
) -> 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].
2022-01-25 12:24:30 +08:00
#[inline(always)]
pub(crate) fn reset_status(&mut self, status: Option<DebuggerStatus>) {
2022-02-03 11:56:08 +08:00
if self.status == DebuggerStatus::CONTINUE {
if let Some(cmd) = status {
self.status = cmd;
}
2022-01-25 12:24:30 +08:00
}
}
/// Returns the first break-point triggered by a particular [`AST` Node][ASTNode].
2022-01-28 18:59:18 +08:00
#[must_use]
2022-10-29 14:59:20 +08:00
pub fn is_break_point(&self, src: Option<&str>, node: ASTNode) -> Option<usize> {
2022-01-25 23:59:35 +08:00
let _src = src;
2022-01-25 17:29:34 +08:00
self.break_points()
.iter()
.enumerate()
2022-02-08 09:02:15 +08:00
.filter(|&(.., bp)| bp.is_enabled())
.find(|&(.., bp)| match bp {
2022-01-25 17:29:34 +08:00
#[cfg(not(feature = "no_position"))]
BreakPoint::AtPosition { pos, .. } if pos.is_none() => false,
#[cfg(not(feature = "no_position"))]
BreakPoint::AtPosition { source, pos, .. } if pos.is_beginning_of_line() => {
2022-10-29 14:59:20 +08:00
node.position().line().unwrap_or(0) == pos.line().unwrap()
&& _src == source.as_ref().map(|s| s.as_str())
2022-01-24 17:04:40 +08:00
}
2022-01-25 17:29:34 +08:00
#[cfg(not(feature = "no_position"))]
BreakPoint::AtPosition { source, pos, .. } => {
2022-10-29 14:59:20 +08:00
node.position() == *pos && _src == source.as_ref().map(|s| s.as_str())
2022-01-24 17:04:40 +08:00
}
2022-01-25 17:29:34 +08:00
BreakPoint::AtFunctionName { name, .. } => match node {
2022-02-16 17:51:14 +08:00
ASTNode::Expr(Expr::FnCall(x, ..)) | ASTNode::Stmt(Stmt::FnCall(x, ..)) => {
x.name == *name
}
2022-07-05 16:26:38 +08:00
ASTNode::Stmt(Stmt::Expr(e)) => match &**e {
2022-02-16 17:51:14 +08:00
Expr::FnCall(x, ..) => x.name == *name,
_ => false,
},
2022-01-25 17:29:34 +08:00
_ => false,
},
BreakPoint::AtFunctionCall { name, args, .. } => match node {
2022-02-16 17:51:14 +08:00
ASTNode::Expr(Expr::FnCall(x, ..)) | ASTNode::Stmt(Stmt::FnCall(x, ..)) => {
2022-01-25 17:29:34 +08:00
x.args.len() == *args && x.name == *name
}
2022-07-05 16:26:38 +08:00
ASTNode::Stmt(Stmt::Expr(e)) => match &**e {
2022-02-16 17:51:14 +08:00
Expr::FnCall(x, ..) => x.args.len() == *args && x.name == *name,
_ => false,
},
2022-01-25 17:29:34 +08:00
_ => false,
},
2022-01-25 23:59:35 +08:00
#[cfg(not(feature = "no_object"))]
2022-01-25 18:21:05 +08:00
BreakPoint::AtProperty { name, .. } => match node {
2022-02-08 09:02:15 +08:00
ASTNode::Expr(Expr::Property(x, ..)) => x.2 == *name,
2022-01-25 18:21:05 +08:00
_ => false,
},
2022-01-25 17:29:34 +08:00
})
2022-02-08 09:02:15 +08:00
.map(|(i, ..)| i)
2022-01-24 17:04:40 +08:00
}
/// Get a slice of all [`BreakPoint`]'s.
#[inline(always)]
#[must_use]
2022-01-25 12:24:30 +08:00
pub fn break_points(&self) -> &[BreakPoint] {
2022-01-24 17:04:40 +08:00
&self.break_points
}
/// Get the underlying [`Vec`] holding all [`BreakPoint`]'s.
#[inline(always)]
#[must_use]
pub fn break_points_mut(&mut self) -> &mut Vec<BreakPoint> {
&mut self.break_points
}
/// Get the custom state.
#[inline(always)]
#[must_use]
2022-08-29 14:27:05 +08:00
pub const 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();
}
2022-01-24 17:04:40 +08:00
}
impl Engine {
2022-02-03 11:56:08 +08:00
/// Run the debugger callback if there is a debugging interface registered.
2022-01-25 12:24:30 +08:00
#[inline(always)]
pub(crate) fn run_debugger<'a>(
2022-01-24 17:04:40 +08:00
&self,
global: &mut GlobalRuntimeState,
2022-11-04 21:47:09 +08:00
caches: &mut Caches,
scope: &mut Scope,
this_ptr: &mut Dynamic,
2022-01-25 12:24:30 +08:00
node: impl Into<ASTNode<'a>>,
) -> RhaiResultOf<()> {
2022-02-03 11:56:08 +08:00
if self.debugger.is_some() {
if let Some(cmd) =
2022-11-10 11:49:10 +08:00
self.run_debugger_with_reset_raw(global, caches, scope, this_ptr, node)?
2022-02-03 11:56:08 +08:00
{
global.debugger.status = cmd;
}
2022-01-25 12:24:30 +08:00
}
Ok(())
2022-01-25 12:24:30 +08:00
}
2022-02-03 11:56:08 +08:00
/// Run the debugger callback if there is a debugging interface registered.
///
2022-10-30 18:43:18 +08:00
/// Returns [`Some`] if the debugger needs to be reactivated at the end of the block, statement or
2022-02-03 11:56:08 +08:00
/// function call.
///
/// It is up to the [`Engine`] to reactivate the debugger.
#[inline(always)]
pub(crate) fn run_debugger_with_reset<'a>(
&self,
global: &mut GlobalRuntimeState,
2022-11-04 21:47:09 +08:00
caches: &mut Caches,
scope: &mut Scope,
this_ptr: &mut Dynamic,
2022-02-03 11:56:08 +08:00
node: impl Into<ASTNode<'a>>,
) -> RhaiResultOf<Option<DebuggerStatus>> {
if self.debugger.is_some() {
2022-11-10 11:49:10 +08:00
self.run_debugger_with_reset_raw(global, caches, scope, this_ptr, node)
2022-02-03 11:56:08 +08:00
} else {
Ok(None)
}
}
2022-01-25 12:24:30 +08:00
/// Run the debugger callback.
///
2022-10-30 18:43:18 +08:00
/// Returns [`Some`] if the debugger needs to be reactivated at the end of the block, statement or
2022-01-25 12:24:30 +08:00
/// function call.
///
/// It is up to the [`Engine`] to reactivate the debugger.
#[inline]
2022-02-03 11:56:08 +08:00
pub(crate) fn run_debugger_with_reset_raw<'a>(
2022-01-25 12:24:30 +08:00
&self,
global: &mut GlobalRuntimeState,
2022-11-04 21:47:09 +08:00
caches: &mut Caches,
scope: &mut Scope,
this_ptr: &mut Dynamic,
2022-01-25 12:24:30 +08:00
node: impl Into<ASTNode<'a>>,
) -> RhaiResultOf<Option<DebuggerStatus>> {
let node = node.into();
2022-01-25 12:24:30 +08:00
// Skip transitive nodes
match node {
2022-02-08 09:46:14 +08:00
ASTNode::Expr(Expr::Stmt(..)) | ASTNode::Stmt(Stmt::Expr(..)) => return Ok(None),
_ => (),
}
2022-01-26 22:15:47 +08:00
2022-04-26 16:36:24 +08:00
let event = match global.debugger.status {
DebuggerStatus::Init => Some(DebuggerEvent::Start),
DebuggerStatus::CONTINUE => None,
DebuggerStatus::NEXT if matches!(node, ASTNode::Stmt(..)) => Some(DebuggerEvent::Step),
DebuggerStatus::NEXT => None,
DebuggerStatus::INTO if matches!(node, ASTNode::Expr(..)) => Some(DebuggerEvent::Step),
DebuggerStatus::INTO => None,
DebuggerStatus::STEP => Some(DebuggerEvent::Step),
DebuggerStatus::FunctionExit(..) => None,
DebuggerStatus::Terminate => Some(DebuggerEvent::End),
};
2022-01-25 12:24:30 +08:00
2022-04-26 16:36:24 +08:00
let event = match event {
Some(e) => e,
2022-10-29 14:59:20 +08:00
None => match global.debugger.is_break_point(global.source(), node) {
2022-10-10 16:46:35 +08:00
Some(bp) => DebuggerEvent::BreakPoint(bp),
None => return Ok(None),
},
};
2022-01-25 12:24:30 +08:00
2022-11-10 11:49:10 +08:00
self.run_debugger_raw(global, caches, scope, this_ptr, node, event)
}
/// Run the debugger callback unconditionally.
///
2022-10-30 18:43:18 +08:00
/// 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]
pub(crate) fn run_debugger_raw<'a>(
&self,
global: &mut GlobalRuntimeState,
2022-11-04 21:47:09 +08:00
caches: &mut Caches,
scope: &mut Scope,
this_ptr: &mut Dynamic,
node: ASTNode<'a>,
event: DebuggerEvent,
) -> Result<Option<DebuggerStatus>, Box<crate::EvalAltResult>> {
2022-10-29 14:12:18 +08:00
let src = global.source_raw().cloned();
let src = src.as_ref().map(|s| s.as_str());
2022-11-10 11:49:10 +08:00
let context = crate::EvalContext::new(self, global, caches, scope, this_ptr);
2022-01-25 12:24:30 +08:00
2022-02-08 09:02:15 +08:00
if let Some((.., ref on_debugger)) = self.debugger {
2022-10-29 14:12:18 +08:00
let command = on_debugger(context, event, node, src, node.position())?;
2022-01-25 12:24:30 +08:00
match command {
DebuggerCommand::Continue => {
global.debugger.status = DebuggerStatus::CONTINUE;
Ok(None)
}
DebuggerCommand::Next => {
global.debugger.status = DebuggerStatus::CONTINUE;
Ok(Some(DebuggerStatus::NEXT))
}
DebuggerCommand::StepOver => {
global.debugger.status = DebuggerStatus::CONTINUE;
Ok(Some(DebuggerStatus::STEP))
2022-01-25 12:24:30 +08:00
}
DebuggerCommand::StepInto => {
global.debugger.status = DebuggerStatus::STEP;
Ok(None)
2022-01-25 12:24:30 +08:00
}
DebuggerCommand::FunctionExit => {
// Bump a level if it is a function call
let level = match node {
2022-02-16 17:51:14 +08:00
ASTNode::Expr(Expr::FnCall(..)) | ASTNode::Stmt(Stmt::FnCall(..)) => {
2022-11-08 21:28:20 +08:00
global.level + 1
2022-02-16 17:51:14 +08:00
}
2022-07-05 16:26:38 +08:00
ASTNode::Stmt(Stmt::Expr(e)) if matches!(**e, Expr::FnCall(..)) => {
2022-11-08 21:28:20 +08:00
global.level + 1
2022-02-16 17:51:14 +08:00
}
2022-11-08 21:28:20 +08:00
_ => global.level,
};
global.debugger.status = DebuggerStatus::FunctionExit(level);
Ok(None)
2022-01-24 17:04:40 +08:00
}
}
2022-01-25 12:24:30 +08:00
} else {
Ok(None)
2022-01-24 17:04:40 +08:00
}
}
}