Refine debugger.
This commit is contained in:
parent
fc87dec128
commit
40aaab60c3
@ -71,16 +71,22 @@ fn print_error(input: &str, mut err: EvalAltResult) {
|
|||||||
|
|
||||||
/// Print debug help.
|
/// Print debug help.
|
||||||
fn print_debug_help() {
|
fn print_debug_help() {
|
||||||
println!("help => print this help");
|
println!("help => print this help");
|
||||||
println!("quit, exit => quit");
|
println!("quit, exit, kill => quit");
|
||||||
println!("scope => print all variables in the scope");
|
println!("scope => print all variables in the scope");
|
||||||
println!("node => print the current AST node");
|
println!("node => print the current AST node");
|
||||||
println!("breakpoints => print all break-points");
|
println!("backtrace => print the current call-stack");
|
||||||
println!("clear => delete all break-points");
|
println!("breakpoints => print all break-points");
|
||||||
println!("break => set a new break-point at the current position");
|
println!("delete <breakpoint#> => delete a break-point");
|
||||||
println!("step => go to the next expression, diving into functions");
|
println!("clear => delete all break-points");
|
||||||
println!("next => go to the next statement but don't dive into functions");
|
println!("break => set a new break-point at the current position");
|
||||||
println!("continue => continue normal execution");
|
println!("break <func> => set a new break-point for a function call");
|
||||||
|
println!(
|
||||||
|
"break <func> <#args> => set a new break-point for a function call with #args arguments"
|
||||||
|
);
|
||||||
|
println!("step => go to the next expression, diving into functions");
|
||||||
|
println!("next => go to the next statement but don't dive into functions");
|
||||||
|
println!("continue => continue normal execution");
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,21 +207,30 @@ fn main() {
|
|||||||
|
|
||||||
match stdin().read_line(&mut input) {
|
match stdin().read_line(&mut input) {
|
||||||
Ok(0) => break DebuggerCommand::Continue,
|
Ok(0) => break DebuggerCommand::Continue,
|
||||||
Ok(_) => match input.as_str().trim_end() {
|
Ok(_) => match input.trim_end().split(' ').collect::<Vec<_>>().as_slice() {
|
||||||
"help" => print_debug_help(),
|
["help", ..] => print_debug_help(),
|
||||||
"exit" | "quit" => {
|
["exit", ..] | ["quit", ..] | ["kill", ..] => {
|
||||||
println!("Script terminated. Bye!");
|
println!("Script terminated. Bye!");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
"node" => {
|
["node", ..] => {
|
||||||
println!("{:?} {}@{:?}", node, source.unwrap_or_default(), pos);
|
println!("{:?} {}@{:?}", node, source.unwrap_or_default(), pos);
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
"continue" => break DebuggerCommand::Continue,
|
["continue", ..] => break DebuggerCommand::Continue,
|
||||||
"" | "step" => break DebuggerCommand::StepInto,
|
[""] | ["step", ..] => break DebuggerCommand::StepInto,
|
||||||
"next" => break DebuggerCommand::StepOver,
|
["next", ..] => break DebuggerCommand::StepOver,
|
||||||
"scope" => print_scope(context.scope()),
|
["scope", ..] => print_scope(context.scope()),
|
||||||
"clear" => {
|
["backtrace", ..] => {
|
||||||
|
context
|
||||||
|
.global_runtime_state()
|
||||||
|
.debugger
|
||||||
|
.call_stack()
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.for_each(|frame| println!("{}", frame));
|
||||||
|
}
|
||||||
|
["clear", ..] => {
|
||||||
context
|
context
|
||||||
.global_runtime_state_mut()
|
.global_runtime_state_mut()
|
||||||
.debugger
|
.debugger
|
||||||
@ -223,30 +238,80 @@ fn main() {
|
|||||||
.clear();
|
.clear();
|
||||||
println!("All break-points cleared.");
|
println!("All break-points cleared.");
|
||||||
}
|
}
|
||||||
"breakpoints" => context
|
["breakpoints", ..] => context
|
||||||
.global_runtime_state_mut()
|
.global_runtime_state()
|
||||||
.debugger
|
.debugger
|
||||||
.iter_break_points()
|
.break_points()
|
||||||
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.for_each(|(i, bp)| match bp {
|
.for_each(|(i, bp)| match bp {
|
||||||
BreakPoint::AtPosition { pos, .. } => {
|
BreakPoint::AtPosition { pos, .. } => {
|
||||||
println!("[{}]", i);
|
println!("[{}]", i + 1);
|
||||||
print_source(&lines, *pos);
|
print_source(&lines, *pos);
|
||||||
}
|
}
|
||||||
_ => println!("[{}]\n{}", i, bp),
|
_ => println!("[{}]\n{}", i + 1, bp),
|
||||||
}),
|
}),
|
||||||
"break" => {
|
["delete", n, ..] => {
|
||||||
|
if let Ok(n) = n.parse::<usize>() {
|
||||||
|
let range = 1..=context
|
||||||
|
.global_runtime_state_mut()
|
||||||
|
.debugger
|
||||||
|
.break_points()
|
||||||
|
.len();
|
||||||
|
if range.contains(&n) {
|
||||||
|
context
|
||||||
|
.global_runtime_state_mut()
|
||||||
|
.debugger
|
||||||
|
.break_points_mut()
|
||||||
|
.remove(n - 1);
|
||||||
|
println!("Break-point #{} deleted.", n)
|
||||||
|
} else {
|
||||||
|
eprintln!("Invalid break-point: {}", n);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
eprintln!("Invalid break-point: '{}'", n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
["break", fn_name, args, ..] => {
|
||||||
|
if let Ok(args) = args.parse::<usize>() {
|
||||||
|
let bp = rhai::debugger::BreakPoint::AtFunctionCall {
|
||||||
|
name: fn_name.trim().into(),
|
||||||
|
args,
|
||||||
|
};
|
||||||
|
println!("Break-point added for {}", bp);
|
||||||
|
context
|
||||||
|
.global_runtime_state_mut()
|
||||||
|
.debugger
|
||||||
|
.break_points_mut()
|
||||||
|
.push(bp);
|
||||||
|
} else {
|
||||||
|
eprintln!("Invalid number of arguments: '{}'", args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
["break", fn_name] => {
|
||||||
|
let bp = rhai::debugger::BreakPoint::AtFunctionName {
|
||||||
|
name: fn_name.trim().into(),
|
||||||
|
};
|
||||||
|
println!("Break-point added for {}", bp);
|
||||||
context
|
context
|
||||||
.global_runtime_state_mut()
|
.global_runtime_state_mut()
|
||||||
.debugger
|
.debugger
|
||||||
.break_points_mut()
|
.break_points_mut()
|
||||||
.push(rhai::debugger::BreakPoint::AtPosition {
|
.push(bp);
|
||||||
source: source.unwrap_or("").into(),
|
|
||||||
pos,
|
|
||||||
});
|
|
||||||
println!("Break-point added at the current position.");
|
|
||||||
}
|
}
|
||||||
cmd => eprintln!("Invalid debugger command: '{}'", cmd),
|
["break", ..] => {
|
||||||
|
let bp = rhai::debugger::BreakPoint::AtPosition {
|
||||||
|
source: source.unwrap_or("").into(),
|
||||||
|
pos,
|
||||||
|
};
|
||||||
|
println!("Break-point added {}", bp);
|
||||||
|
context
|
||||||
|
.global_runtime_state_mut()
|
||||||
|
.debugger
|
||||||
|
.break_points_mut()
|
||||||
|
.push(bp);
|
||||||
|
}
|
||||||
|
cmd => eprintln!("Invalid debugger command: '{}'", cmd[0]),
|
||||||
},
|
},
|
||||||
Err(err) => panic!("input error: {}", err),
|
Err(err) => panic!("input error: {}", err),
|
||||||
}
|
}
|
||||||
|
@ -125,6 +125,7 @@ impl Engine {
|
|||||||
this_ptr: &mut Option<&mut Dynamic>,
|
this_ptr: &mut Option<&mut Dynamic>,
|
||||||
target: &mut Target,
|
target: &mut Target,
|
||||||
root: (&str, Position),
|
root: (&str, Position),
|
||||||
|
parent: &Expr,
|
||||||
rhs: &Expr,
|
rhs: &Expr,
|
||||||
terminate_chaining: bool,
|
terminate_chaining: bool,
|
||||||
idx_values: &mut StaticVec<super::ChainArgument>,
|
idx_values: &mut StaticVec<super::ChainArgument>,
|
||||||
@ -138,6 +139,9 @@ impl Engine {
|
|||||||
// Pop the last index value
|
// Pop the last index value
|
||||||
let idx_val = idx_values.pop().unwrap();
|
let idx_val = idx_values.pop().unwrap();
|
||||||
|
|
||||||
|
#[cfg(feature = "debugging")]
|
||||||
|
let scope = &mut Scope::new();
|
||||||
|
|
||||||
match chain_type {
|
match chain_type {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
ChainType::Indexing => {
|
ChainType::Indexing => {
|
||||||
@ -150,6 +154,9 @@ impl Engine {
|
|||||||
Expr::Dot(x, term, x_pos) | Expr::Index(x, term, x_pos)
|
Expr::Dot(x, term, x_pos) | Expr::Index(x, term, x_pos)
|
||||||
if !_terminate_chaining =>
|
if !_terminate_chaining =>
|
||||||
{
|
{
|
||||||
|
#[cfg(feature = "debugging")]
|
||||||
|
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();
|
||||||
let rhs_chain = rhs.into();
|
let rhs_chain = rhs.into();
|
||||||
@ -162,7 +169,7 @@ impl Engine {
|
|||||||
let obj_ptr = &mut obj;
|
let obj_ptr = &mut obj;
|
||||||
|
|
||||||
match self.eval_dot_index_chain_helper(
|
match self.eval_dot_index_chain_helper(
|
||||||
global, state, lib, this_ptr, obj_ptr, root, &x.rhs, *term,
|
global, state, lib, this_ptr, obj_ptr, root, rhs, &x.rhs, *term,
|
||||||
idx_values, rhs_chain, level, new_val,
|
idx_values, rhs_chain, level, new_val,
|
||||||
) {
|
) {
|
||||||
Ok((result, true)) if is_obj_temp_val => {
|
Ok((result, true)) if is_obj_temp_val => {
|
||||||
@ -195,6 +202,9 @@ 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")]
|
||||||
|
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();
|
||||||
|
|
||||||
@ -236,11 +246,15 @@ impl Engine {
|
|||||||
Ok((Dynamic::UNIT, true))
|
Ok((Dynamic::UNIT, true))
|
||||||
}
|
}
|
||||||
// xxx[rhs]
|
// xxx[rhs]
|
||||||
_ => self
|
_ => {
|
||||||
.get_indexed_mut(
|
#[cfg(feature = "debugging")]
|
||||||
|
self.run_debugger(scope, global, state, lib, this_ptr, parent, level);
|
||||||
|
|
||||||
|
self.get_indexed_mut(
|
||||||
global, state, lib, target, idx_val, pos, false, true, level,
|
global, state, lib, target, idx_val, pos, false, true, level,
|
||||||
)
|
)
|
||||||
.map(|v| (v.take_or_clone(), false)),
|
.map(|v| (v.take_or_clone(), false))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,9 +265,20 @@ impl Engine {
|
|||||||
Expr::FnCall(x, pos) if !x.is_qualified() && new_val.is_none() => {
|
Expr::FnCall(x, pos) if !x.is_qualified() && new_val.is_none() => {
|
||||||
let crate::ast::FnCallExpr { name, hashes, .. } = x.as_ref();
|
let crate::ast::FnCallExpr { name, hashes, .. } = x.as_ref();
|
||||||
let call_args = &mut idx_val.into_fn_call_args();
|
let call_args = &mut idx_val.into_fn_call_args();
|
||||||
self.make_method_call(
|
|
||||||
|
#[cfg(feature = "debugging")]
|
||||||
|
let reset_debugger = self.run_debugger_with_reset(
|
||||||
|
scope, global, state, lib, this_ptr, rhs, level,
|
||||||
|
);
|
||||||
|
|
||||||
|
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,
|
||||||
)
|
);
|
||||||
|
|
||||||
|
#[cfg(feature = "debugging")]
|
||||||
|
global.debugger.reset_status(reset_debugger);
|
||||||
|
|
||||||
|
result
|
||||||
}
|
}
|
||||||
// xxx.fn_name(...) = ???
|
// xxx.fn_name(...) = ???
|
||||||
Expr::FnCall(_, _) if new_val.is_some() => {
|
Expr::FnCall(_, _) if new_val.is_some() => {
|
||||||
@ -265,6 +290,9 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
// {xxx:map}.id op= ???
|
// {xxx:map}.id op= ???
|
||||||
Expr::Property(x) if target.is::<crate::Map>() && new_val.is_some() => {
|
Expr::Property(x) if target.is::<crate::Map>() && new_val.is_some() => {
|
||||||
|
#[cfg(feature = "debugging")]
|
||||||
|
self.run_debugger(scope, global, state, lib, this_ptr, rhs, level);
|
||||||
|
|
||||||
let (name, pos) = &x.2;
|
let (name, pos) = &x.2;
|
||||||
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 index = name.into();
|
let index = name.into();
|
||||||
@ -283,6 +311,9 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
// {xxx:map}.id
|
// {xxx:map}.id
|
||||||
Expr::Property(x) if target.is::<crate::Map>() => {
|
Expr::Property(x) if target.is::<crate::Map>() => {
|
||||||
|
#[cfg(feature = "debugging")]
|
||||||
|
self.run_debugger(scope, global, state, lib, this_ptr, rhs, level);
|
||||||
|
|
||||||
let (name, pos) = &x.2;
|
let (name, pos) = &x.2;
|
||||||
let index = name.into();
|
let index = name.into();
|
||||||
let val = self.get_indexed_mut(
|
let val = self.get_indexed_mut(
|
||||||
@ -292,6 +323,9 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
// xxx.id op= ???
|
// xxx.id op= ???
|
||||||
Expr::Property(x) if new_val.is_some() => {
|
Expr::Property(x) if new_val.is_some() => {
|
||||||
|
#[cfg(feature = "debugging")]
|
||||||
|
self.run_debugger(scope, global, state, lib, this_ptr, rhs, level);
|
||||||
|
|
||||||
let ((getter, hash_get), (setter, hash_set), (name, pos)) = x.as_ref();
|
let ((getter, hash_get), (setter, hash_set), (name, pos)) = 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`");
|
||||||
|
|
||||||
@ -368,6 +402,9 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
// xxx.id
|
// xxx.id
|
||||||
Expr::Property(x) => {
|
Expr::Property(x) => {
|
||||||
|
#[cfg(feature = "debugging")]
|
||||||
|
self.run_debugger(scope, global, state, lib, this_ptr, rhs, level);
|
||||||
|
|
||||||
let ((getter, hash_get), _, (name, pos)) = x.as_ref();
|
let ((getter, hash_get), _, (name, pos)) = x.as_ref();
|
||||||
let hash = crate::ast::FnCallHashes::from_native(*hash_get);
|
let hash = crate::ast::FnCallHashes::from_native(*hash_get);
|
||||||
let args = &mut [target.as_mut()];
|
let args = &mut [target.as_mut()];
|
||||||
@ -401,8 +438,13 @@ impl Engine {
|
|||||||
Expr::Index(x, term, x_pos) | Expr::Dot(x, term, x_pos)
|
Expr::Index(x, term, x_pos) | Expr::Dot(x, term, x_pos)
|
||||||
if target.is::<crate::Map>() =>
|
if target.is::<crate::Map>() =>
|
||||||
{
|
{
|
||||||
|
let node = &x.lhs;
|
||||||
|
|
||||||
let val_target = &mut match x.lhs {
|
let val_target = &mut match x.lhs {
|
||||||
Expr::Property(ref p) => {
|
Expr::Property(ref p) => {
|
||||||
|
#[cfg(feature = "debugging")]
|
||||||
|
self.run_debugger(scope, global, state, lib, this_ptr, node, level);
|
||||||
|
|
||||||
let (name, pos) = &p.2;
|
let (name, pos) = &p.2;
|
||||||
let index = name.into();
|
let index = name.into();
|
||||||
self.get_indexed_mut(
|
self.get_indexed_mut(
|
||||||
@ -413,11 +455,21 @@ impl Engine {
|
|||||||
Expr::FnCall(ref x, pos) if !x.is_qualified() => {
|
Expr::FnCall(ref x, pos) if !x.is_qualified() => {
|
||||||
let crate::ast::FnCallExpr { name, hashes, .. } = x.as_ref();
|
let crate::ast::FnCallExpr { name, hashes, .. } = x.as_ref();
|
||||||
let call_args = &mut idx_val.into_fn_call_args();
|
let call_args = &mut idx_val.into_fn_call_args();
|
||||||
let (val, _) = self.make_method_call(
|
|
||||||
|
#[cfg(feature = "debugging")]
|
||||||
|
let reset_debugger = self.run_debugger_with_reset(
|
||||||
|
scope, global, state, lib, this_ptr, node, level,
|
||||||
|
);
|
||||||
|
|
||||||
|
let result = self.make_method_call(
|
||||||
global, state, lib, name, *hashes, target, call_args, pos,
|
global, state, lib, name, *hashes, target, call_args, pos,
|
||||||
level,
|
level,
|
||||||
)?;
|
);
|
||||||
val.into()
|
|
||||||
|
#[cfg(feature = "debugging")]
|
||||||
|
global.debugger.reset_status(reset_debugger);
|
||||||
|
|
||||||
|
result?.0.into()
|
||||||
}
|
}
|
||||||
// {xxx:map}.module::fn_name(...) - syntax error
|
// {xxx:map}.module::fn_name(...) - syntax error
|
||||||
Expr::FnCall(_, _) => unreachable!(
|
Expr::FnCall(_, _) => unreachable!(
|
||||||
@ -429,16 +481,21 @@ impl Engine {
|
|||||||
let rhs_chain = rhs.into();
|
let rhs_chain = rhs.into();
|
||||||
|
|
||||||
self.eval_dot_index_chain_helper(
|
self.eval_dot_index_chain_helper(
|
||||||
global, state, lib, this_ptr, val_target, root, &x.rhs, *term,
|
global, state, lib, this_ptr, val_target, root, rhs, &x.rhs, *term,
|
||||||
idx_values, rhs_chain, level, new_val,
|
idx_values, rhs_chain, level, new_val,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.fill_position(*x_pos))
|
.map_err(|err| err.fill_position(*x_pos))
|
||||||
}
|
}
|
||||||
// xxx.sub_lhs[expr] | xxx.sub_lhs.expr
|
// xxx.sub_lhs[expr] | xxx.sub_lhs.expr
|
||||||
Expr::Index(x, term, x_pos) | Expr::Dot(x, term, x_pos) => {
|
Expr::Index(x, term, x_pos) | Expr::Dot(x, term, x_pos) => {
|
||||||
|
let node = &x.lhs;
|
||||||
|
|
||||||
match x.lhs {
|
match x.lhs {
|
||||||
// xxx.prop[expr] | xxx.prop.expr
|
// xxx.prop[expr] | xxx.prop.expr
|
||||||
Expr::Property(ref p) => {
|
Expr::Property(ref p) => {
|
||||||
|
#[cfg(feature = "debugging")]
|
||||||
|
self.run_debugger(scope, global, state, lib, this_ptr, node, level);
|
||||||
|
|
||||||
let ((getter, hash_get), (setter, hash_set), (name, pos)) =
|
let ((getter, hash_get), (setter, hash_set), (name, pos)) =
|
||||||
p.as_ref();
|
p.as_ref();
|
||||||
let rhs_chain = rhs.into();
|
let rhs_chain = rhs.into();
|
||||||
@ -482,6 +539,7 @@ impl Engine {
|
|||||||
this_ptr,
|
this_ptr,
|
||||||
&mut val.into(),
|
&mut val.into(),
|
||||||
root,
|
root,
|
||||||
|
rhs,
|
||||||
&x.rhs,
|
&x.rhs,
|
||||||
*term,
|
*term,
|
||||||
idx_values,
|
idx_values,
|
||||||
@ -536,14 +594,24 @@ impl Engine {
|
|||||||
let crate::ast::FnCallExpr { name, hashes, .. } = f.as_ref();
|
let crate::ast::FnCallExpr { name, hashes, .. } = f.as_ref();
|
||||||
let rhs_chain = rhs.into();
|
let rhs_chain = rhs.into();
|
||||||
let args = &mut idx_val.into_fn_call_args();
|
let args = &mut idx_val.into_fn_call_args();
|
||||||
let (mut val, _) = self.make_method_call(
|
|
||||||
|
#[cfg(feature = "debugging")]
|
||||||
|
let reset_debugger = self.run_debugger_with_reset(
|
||||||
|
scope, global, state, lib, this_ptr, node, level,
|
||||||
|
);
|
||||||
|
|
||||||
|
let result = self.make_method_call(
|
||||||
global, state, lib, name, *hashes, target, args, pos, level,
|
global, state, lib, name, *hashes, target, args, pos, level,
|
||||||
)?;
|
);
|
||||||
let val = &mut val;
|
|
||||||
|
#[cfg(feature = "debugging")]
|
||||||
|
global.debugger.reset_status(reset_debugger);
|
||||||
|
|
||||||
|
let val = &mut result?.0;
|
||||||
let target = &mut val.into();
|
let target = &mut val.into();
|
||||||
|
|
||||||
self.eval_dot_index_chain_helper(
|
self.eval_dot_index_chain_helper(
|
||||||
global, state, lib, this_ptr, target, root, &x.rhs, *term,
|
global, state, lib, this_ptr, target, root, rhs, &x.rhs, *term,
|
||||||
idx_values, rhs_chain, level, new_val,
|
idx_values, rhs_chain, level, new_val,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.fill_position(pos))
|
.map_err(|err| err.fill_position(pos))
|
||||||
@ -594,6 +662,9 @@ impl Engine {
|
|||||||
match lhs {
|
match lhs {
|
||||||
// id.??? or id[???]
|
// id.??? or id[???]
|
||||||
Expr::Variable(_, var_pos, x) => {
|
Expr::Variable(_, var_pos, x) => {
|
||||||
|
#[cfg(feature = "debugging")]
|
||||||
|
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)?;
|
||||||
|
|
||||||
@ -604,7 +675,7 @@ impl Engine {
|
|||||||
let root = (x.2.as_str(), *var_pos);
|
let root = (x.2.as_str(), *var_pos);
|
||||||
|
|
||||||
self.eval_dot_index_chain_helper(
|
self.eval_dot_index_chain_helper(
|
||||||
global, state, lib, &mut None, obj_ptr, root, rhs, term, idx_values,
|
global, state, lib, &mut None, obj_ptr, root, expr, rhs, term, idx_values,
|
||||||
chain_type, level, new_val,
|
chain_type, level, new_val,
|
||||||
)
|
)
|
||||||
.map(|(v, _)| v)
|
.map(|(v, _)| v)
|
||||||
@ -618,8 +689,8 @@ impl Engine {
|
|||||||
let obj_ptr = &mut value.into();
|
let obj_ptr = &mut value.into();
|
||||||
let root = ("", expr.position());
|
let root = ("", expr.position());
|
||||||
self.eval_dot_index_chain_helper(
|
self.eval_dot_index_chain_helper(
|
||||||
global, state, lib, this_ptr, obj_ptr, root, rhs, term, idx_values, chain_type,
|
global, state, lib, this_ptr, obj_ptr, root, expr, rhs, term, idx_values,
|
||||||
level, new_val,
|
chain_type, level, new_val,
|
||||||
)
|
)
|
||||||
.map(|(v, _)| if is_assignment { Dynamic::UNIT } else { v })
|
.map(|(v, _)| if is_assignment { Dynamic::UNIT } else { v })
|
||||||
.map_err(|err| err.fill_position(op_pos))
|
.map_err(|err| err.fill_position(op_pos))
|
||||||
|
@ -42,9 +42,9 @@ pub enum BreakPoint {
|
|||||||
#[cfg(not(feature = "no_position"))]
|
#[cfg(not(feature = "no_position"))]
|
||||||
AtPosition { source: Identifier, pos: Position },
|
AtPosition { source: Identifier, pos: Position },
|
||||||
/// Break at a particular function call.
|
/// Break at a particular function call.
|
||||||
AtFunctionName { fn_name: Identifier },
|
AtFunctionName { name: Identifier },
|
||||||
/// Break at a particular function call with a particular number of arguments.
|
/// Break at a particular function call with a particular number of arguments.
|
||||||
AtFunctionCall { fn_name: Identifier, args: usize },
|
AtFunctionCall { name: Identifier, args: usize },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for BreakPoint {
|
impl fmt::Display for BreakPoint {
|
||||||
@ -57,8 +57,11 @@ impl fmt::Display for BreakPoint {
|
|||||||
write!(f, "@ {:?}", pos)
|
write!(f, "@ {:?}", pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::AtFunctionName { fn_name } => write!(f, "{} (...)", fn_name),
|
Self::AtFunctionName { name: fn_name } => write!(f, "{} (...)", fn_name),
|
||||||
Self::AtFunctionCall { fn_name, args } => write!(
|
Self::AtFunctionCall {
|
||||||
|
name: fn_name,
|
||||||
|
args,
|
||||||
|
} => write!(
|
||||||
f,
|
f,
|
||||||
"{} ({})",
|
"{} ({})",
|
||||||
fn_name,
|
fn_name,
|
||||||
@ -71,6 +74,7 @@ impl fmt::Display for BreakPoint {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A function call.
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
pub struct CallStackFrame {
|
pub struct CallStackFrame {
|
||||||
pub fn_name: Identifier,
|
pub fn_name: Identifier,
|
||||||
@ -104,7 +108,7 @@ impl fmt::Display for CallStackFrame {
|
|||||||
/// A type providing debugging facilities.
|
/// A type providing debugging facilities.
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
pub struct Debugger {
|
pub struct Debugger {
|
||||||
active: bool,
|
status: DebuggerCommand,
|
||||||
break_points: Vec<BreakPoint>,
|
break_points: Vec<BreakPoint>,
|
||||||
call_stack: Vec<CallStackFrame>,
|
call_stack: Vec<CallStackFrame>,
|
||||||
}
|
}
|
||||||
@ -113,7 +117,7 @@ impl Debugger {
|
|||||||
/// Create a new [`Debugger`].
|
/// Create a new [`Debugger`].
|
||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
active: false,
|
status: DebuggerCommand::Continue,
|
||||||
break_points: Vec::new(),
|
break_points: Vec::new(),
|
||||||
call_stack: Vec::new(),
|
call_stack: Vec::new(),
|
||||||
}
|
}
|
||||||
@ -123,54 +127,74 @@ impl Debugger {
|
|||||||
pub fn call_stack_len(&self) -> usize {
|
pub fn call_stack_len(&self) -> usize {
|
||||||
self.call_stack.len()
|
self.call_stack.len()
|
||||||
}
|
}
|
||||||
|
/// Get the current call stack.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn call_stack(&self) -> &[CallStackFrame] {
|
||||||
|
&self.call_stack
|
||||||
|
}
|
||||||
/// Rewind the function call stack to a particular depth.
|
/// Rewind the function call stack to a particular depth.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn rewind_call_stack(&mut self, len: usize) {
|
pub(crate) fn rewind_call_stack(&mut self, len: usize) {
|
||||||
self.call_stack.truncate(len);
|
self.call_stack.truncate(len);
|
||||||
}
|
}
|
||||||
/// Add a new frame to the function call stack.
|
/// Add a new frame to the function call stack.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn push_call_stack_frame(
|
pub(crate) fn push_call_stack_frame(
|
||||||
&mut self,
|
&mut self,
|
||||||
fn_name: impl Into<Identifier>,
|
fn_name: impl Into<Identifier>,
|
||||||
args: StaticVec<Dynamic>,
|
args: StaticVec<Dynamic>,
|
||||||
source: impl Into<Identifier>,
|
source: impl Into<Identifier>,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
) {
|
) {
|
||||||
let fp = CallStackFrame {
|
self.call_stack.push(CallStackFrame {
|
||||||
fn_name: fn_name.into(),
|
fn_name: fn_name.into(),
|
||||||
args,
|
args,
|
||||||
source: source.into(),
|
source: source.into(),
|
||||||
pos,
|
pos,
|
||||||
};
|
});
|
||||||
println!("{}", fp);
|
|
||||||
self.call_stack.push(fp);
|
|
||||||
}
|
}
|
||||||
/// Is this [`Debugger`] currently active?
|
/// Get the current status of this [`Debugger`].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_active(&self) -> bool {
|
pub fn status(&self) -> DebuggerCommand {
|
||||||
self.active
|
self.status
|
||||||
}
|
}
|
||||||
/// Activate or deactivate this [`Debugger`].
|
/// Set the status of this [`Debugger`].
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_status(&mut self, status: DebuggerCommand) {
|
||||||
|
self.status = status;
|
||||||
|
}
|
||||||
|
/// Set the status of this [`Debugger`].
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn reset_status(&mut self, status: Option<DebuggerCommand>) {
|
||||||
|
if let Some(cmd) = status {
|
||||||
|
self.status = cmd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Activate: set the status of this [`Debugger`] to [`DebuggerCommand::StepInto`].
|
||||||
|
/// Deactivate: set the status of this [`Debugger`] to [`DebuggerCommand::Continue`].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn activate(&mut self, active: bool) {
|
pub fn activate(&mut self, active: bool) {
|
||||||
self.active = active;
|
if active {
|
||||||
|
self.set_status(DebuggerCommand::StepInto);
|
||||||
|
} else {
|
||||||
|
self.set_status(DebuggerCommand::Continue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/// Does a particular [`AST` Node][ASTNode] trigger a break-point?
|
/// Does a particular [`AST` Node][ASTNode] trigger a break-point?
|
||||||
pub fn is_break_point(&self, src: &str, node: ASTNode) -> bool {
|
pub fn is_break_point(&self, src: &str, node: ASTNode) -> bool {
|
||||||
self.iter_break_points().any(|bp| match bp {
|
self.break_points().iter().any(|bp| match bp {
|
||||||
#[cfg(not(feature = "no_position"))]
|
#[cfg(not(feature = "no_position"))]
|
||||||
BreakPoint::AtPosition { source, pos } => node.position() == *pos && src == source,
|
BreakPoint::AtPosition { source, pos } => node.position() == *pos && src == source,
|
||||||
BreakPoint::AtFunctionName { fn_name } => match node {
|
BreakPoint::AtFunctionName { name } => match node {
|
||||||
ASTNode::Expr(Expr::FnCall(x, _)) | ASTNode::Stmt(Stmt::FnCall(x, _)) => {
|
ASTNode::Expr(Expr::FnCall(x, _)) | ASTNode::Stmt(Stmt::FnCall(x, _)) => {
|
||||||
x.name == *fn_name
|
x.name == *name
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
BreakPoint::AtFunctionCall { fn_name, args } => match node {
|
BreakPoint::AtFunctionCall { name, args } => match node {
|
||||||
ASTNode::Expr(Expr::FnCall(x, _)) | ASTNode::Stmt(Stmt::FnCall(x, _)) => {
|
ASTNode::Expr(Expr::FnCall(x, _)) | ASTNode::Stmt(Stmt::FnCall(x, _)) => {
|
||||||
x.args.len() == *args && x.name == *fn_name
|
x.args.len() == *args && x.name == *name
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
@ -179,7 +203,7 @@ impl Debugger {
|
|||||||
/// Get a slice of all [`BreakPoint`]'s.
|
/// Get a slice of all [`BreakPoint`]'s.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn break_points(&mut self) -> &[BreakPoint] {
|
pub fn break_points(&self) -> &[BreakPoint] {
|
||||||
&self.break_points
|
&self.break_points
|
||||||
}
|
}
|
||||||
/// Get the underlying [`Vec`] holding all [`BreakPoint`]'s.
|
/// Get the underlying [`Vec`] holding all [`BreakPoint`]'s.
|
||||||
@ -188,66 +212,98 @@ 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 an iterator over all [`BreakPoint`]'s.
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub fn iter_break_points(&self) -> impl Iterator<Item = &BreakPoint> {
|
|
||||||
self.break_points.iter()
|
|
||||||
}
|
|
||||||
/// Get a mutable iterator over all [`BreakPoint`]'s.
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub fn iter_break_points_mut(&mut self) -> impl Iterator<Item = &mut BreakPoint> {
|
|
||||||
self.break_points.iter_mut()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Engine {
|
impl Engine {
|
||||||
pub(crate) fn run_debugger(
|
/// Run the debugger callback.
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn run_debugger<'a>(
|
||||||
&self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
global: &mut GlobalRuntimeState,
|
global: &mut GlobalRuntimeState,
|
||||||
state: &mut EvalState,
|
state: &mut EvalState,
|
||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
this_ptr: &mut Option<&mut Dynamic>,
|
this_ptr: &mut Option<&mut Dynamic>,
|
||||||
node: ASTNode,
|
node: impl Into<ASTNode<'a>>,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> bool {
|
) {
|
||||||
|
if let Some(cmd) =
|
||||||
|
self.run_debugger_with_reset(scope, global, state, lib, this_ptr, node, level)
|
||||||
|
{
|
||||||
|
global.debugger.set_status(cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Run the debugger callback.
|
||||||
|
///
|
||||||
|
/// Returns `true` if the debugger needs to be reactivated at the end of the block, statement or
|
||||||
|
/// function call.
|
||||||
|
///
|
||||||
|
/// # Note
|
||||||
|
///
|
||||||
|
/// When the debugger callback return [`DebuggerCommand::StepOver`], the debugger if temporarily
|
||||||
|
/// disabled and `true` is returned.
|
||||||
|
///
|
||||||
|
/// It is up to the [`Engine`] to reactivate the debugger.
|
||||||
|
#[inline]
|
||||||
|
#[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,
|
||||||
|
) -> Option<DebuggerCommand> {
|
||||||
if let Some(ref on_debugger) = self.debugger {
|
if let Some(ref on_debugger) = self.debugger {
|
||||||
if global.debugger.active || global.debugger.is_break_point(&global.source, node) {
|
let node = node.into();
|
||||||
let source = global.source.clone();
|
|
||||||
let source = if source.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(source.as_str())
|
|
||||||
};
|
|
||||||
let mut context = crate::EvalContext {
|
|
||||||
engine: self,
|
|
||||||
scope,
|
|
||||||
global,
|
|
||||||
state,
|
|
||||||
lib,
|
|
||||||
this_ptr,
|
|
||||||
level,
|
|
||||||
};
|
|
||||||
|
|
||||||
match on_debugger(&mut context, node, source, node.position()) {
|
let stop = match global.debugger.status {
|
||||||
DebuggerCommand::Continue => {
|
DebuggerCommand::Continue => false,
|
||||||
global.debugger.activate(false);
|
DebuggerCommand::StepOver => matches!(node, ASTNode::Stmt(_)),
|
||||||
return false;
|
DebuggerCommand::StepInto => true,
|
||||||
}
|
};
|
||||||
DebuggerCommand::StepInto => {
|
|
||||||
global.debugger.activate(true);
|
if !stop && !global.debugger.is_break_point(&global.source, node) {
|
||||||
return true;
|
return None;
|
||||||
}
|
}
|
||||||
DebuggerCommand::StepOver => {
|
|
||||||
global.debugger.activate(false);
|
let source = global.source.clone();
|
||||||
return true;
|
let source = if source.is_empty() {
|
||||||
}
|
None
|
||||||
|
} else {
|
||||||
|
Some(source.as_str())
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut context = crate::EvalContext {
|
||||||
|
engine: self,
|
||||||
|
scope,
|
||||||
|
global,
|
||||||
|
state,
|
||||||
|
lib,
|
||||||
|
this_ptr,
|
||||||
|
level,
|
||||||
|
};
|
||||||
|
|
||||||
|
let command = on_debugger(&mut context, node, source, node.position());
|
||||||
|
|
||||||
|
match command {
|
||||||
|
DebuggerCommand::Continue => {
|
||||||
|
global.debugger.set_status(DebuggerCommand::Continue);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
DebuggerCommand::StepInto => {
|
||||||
|
global.debugger.set_status(DebuggerCommand::StepInto);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
DebuggerCommand::StepOver => {
|
||||||
|
global.debugger.set_status(DebuggerCommand::Continue);
|
||||||
|
Some(DebuggerCommand::StepOver)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -259,16 +259,16 @@ impl Engine {
|
|||||||
expr: &Expr,
|
expr: &Expr,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> RhaiResult {
|
) -> RhaiResult {
|
||||||
#[cfg(feature = "debugging")]
|
|
||||||
let reset_debugger_command =
|
|
||||||
self.run_debugger(scope, global, state, lib, this_ptr, expr.into(), level);
|
|
||||||
|
|
||||||
// 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.
|
||||||
|
|
||||||
// Function calls should account for a relatively larger portion of expressions because
|
// Function calls should account for a relatively larger portion of expressions because
|
||||||
// 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")]
|
||||||
|
let reset_debugger =
|
||||||
|
self.run_debugger_with_reset(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())?;
|
||||||
|
|
||||||
@ -276,7 +276,7 @@ impl Engine {
|
|||||||
self.eval_fn_call_expr(scope, global, state, lib, this_ptr, x, *pos, level);
|
self.eval_fn_call_expr(scope, global, state, lib, this_ptr, x, *pos, level);
|
||||||
|
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
global.debugger.activate(reset_debugger_command);
|
global.debugger.reset_status(reset_debugger);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -285,10 +285,13 @@ impl Engine {
|
|||||||
// We shouldn't do this for too many variants because, soon or later, the added comparisons
|
// We shouldn't do this for too many variants because, soon or later, the added comparisons
|
||||||
// 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")]
|
||||||
|
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())?;
|
||||||
|
|
||||||
let result = if index.is_none() && x.0.is_none() && x.2 == KEYWORD_THIS {
|
return if index.is_none() && x.0.is_none() && x.2 == KEYWORD_THIS {
|
||||||
this_ptr
|
this_ptr
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.cloned()
|
.cloned()
|
||||||
@ -297,13 +300,12 @@ impl Engine {
|
|||||||
self.search_namespace(scope, global, state, lib, this_ptr, expr)
|
self.search_namespace(scope, global, state, lib, this_ptr, expr)
|
||||||
.map(|(val, _)| val.take_or_clone())
|
.map(|(val, _)| val.take_or_clone())
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "debugging")]
|
|
||||||
global.debugger.activate(reset_debugger_command);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "debugging")]
|
||||||
|
let reset_debugger =
|
||||||
|
self.run_debugger_with_reset(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())?;
|
||||||
|
|
||||||
@ -523,7 +525,7 @@ impl Engine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
global.debugger.activate(reset_debugger_command);
|
global.debugger.reset_status(reset_debugger);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ mod target;
|
|||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
pub use chaining::{ChainArgument, ChainType};
|
pub use chaining::{ChainArgument, ChainType};
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
pub use debugger::{BreakPoint, Debugger, DebuggerCommand, OnDebuggerCallback};
|
pub use debugger::{BreakPoint, CallStackFrame, Debugger, DebuggerCommand, OnDebuggerCallback};
|
||||||
pub use eval_context::EvalContext;
|
pub use eval_context::EvalContext;
|
||||||
pub use eval_state::EvalState;
|
pub use eval_state::EvalState;
|
||||||
pub use global_state::GlobalRuntimeState;
|
pub use global_state::GlobalRuntimeState;
|
||||||
|
@ -195,8 +195,8 @@ impl Engine {
|
|||||||
level: usize,
|
level: usize,
|
||||||
) -> RhaiResult {
|
) -> RhaiResult {
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
let reset_debugger_command =
|
let reset_debugger =
|
||||||
self.run_debugger(scope, global, state, lib, this_ptr, stmt.into(), level);
|
self.run_debugger_with_reset(scope, global, state, lib, this_ptr, stmt, level);
|
||||||
|
|
||||||
// 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.
|
||||||
@ -210,7 +210,7 @@ impl Engine {
|
|||||||
self.eval_fn_call_expr(scope, global, state, lib, this_ptr, x, *pos, level);
|
self.eval_fn_call_expr(scope, global, state, lib, this_ptr, x, *pos, level);
|
||||||
|
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
global.debugger.activate(reset_debugger_command);
|
global.debugger.reset_status(reset_debugger);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -301,7 +301,7 @@ impl Engine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
global.debugger.activate(reset_debugger_command);
|
global.debugger.reset_status(reset_debugger);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -931,7 +931,7 @@ impl Engine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
global.debugger.activate(reset_debugger_command);
|
global.debugger.reset_status(reset_debugger);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -890,19 +890,11 @@ impl Engine {
|
|||||||
Ok((
|
Ok((
|
||||||
if let Expr::Stack(slot, _) = arg_expr {
|
if let Expr::Stack(slot, _) = arg_expr {
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
let active =
|
self.run_debugger(scope, global, state, lib, this_ptr, arg_expr, level);
|
||||||
self.run_debugger(scope, global, state, lib, this_ptr, arg_expr.into(), level);
|
|
||||||
#[cfg(feature = "debugging")]
|
|
||||||
global.debugger.activate(active);
|
|
||||||
|
|
||||||
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")]
|
||||||
let active =
|
self.run_debugger(scope, global, state, lib, this_ptr, arg_expr, level);
|
||||||
self.run_debugger(scope, global, state, lib, this_ptr, arg_expr.into(), level);
|
|
||||||
#[cfg(feature = "debugging")]
|
|
||||||
global.debugger.activate(active);
|
|
||||||
|
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
self.eval_expr(scope, global, state, lib, this_ptr, arg_expr, level)?
|
self.eval_expr(scope, global, state, lib, this_ptr, arg_expr, level)?
|
||||||
@ -1148,12 +1140,7 @@ impl Engine {
|
|||||||
let first_expr = first_arg.unwrap();
|
let first_expr = first_arg.unwrap();
|
||||||
|
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
{
|
self.run_debugger(scope, global, state, lib, this_ptr, first_expr, level);
|
||||||
let node = first_expr.into();
|
|
||||||
let active =
|
|
||||||
self.run_debugger(scope, global, state, lib, this_ptr, node, level);
|
|
||||||
global.debugger.activate(active);
|
|
||||||
}
|
|
||||||
|
|
||||||
// func(x, ...) -> x.func(...)
|
// func(x, ...) -> x.func(...)
|
||||||
a_expr.iter().try_for_each(|expr| {
|
a_expr.iter().try_for_each(|expr| {
|
||||||
@ -1236,12 +1223,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")]
|
||||||
{
|
self.run_debugger(scope, global, state, lib, this_ptr, &args_expr[0], level);
|
||||||
let node = (&args_expr[0]).into();
|
|
||||||
let active =
|
|
||||||
self.run_debugger(scope, global, state, lib, this_ptr, node, level);
|
|
||||||
global.debugger.activate(active);
|
|
||||||
}
|
|
||||||
|
|
||||||
// func(x, ...) -> x.func(...)
|
// func(x, ...) -> x.func(...)
|
||||||
arg_values.push(Dynamic::UNIT);
|
arg_values.push(Dynamic::UNIT);
|
||||||
|
@ -160,7 +160,7 @@ pub use types::{
|
|||||||
/// Exported under the `debugging` feature only.
|
/// Exported under the `debugging` feature only.
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
pub mod debugger {
|
pub mod debugger {
|
||||||
pub use super::eval::{BreakPoint, Debugger, DebuggerCommand};
|
pub use super::eval::{BreakPoint, CallStackFrame, Debugger, DebuggerCommand};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An identifier in Rhai. [`SmartString`](https://crates.io/crates/smartstring) is used because most
|
/// An identifier in Rhai. [`SmartString`](https://crates.io/crates/smartstring) is used because most
|
||||||
|
Loading…
x
Reference in New Issue
Block a user