Fix function exit trigger and add function enter trigger.

This commit is contained in:
Stephen Chung 2022-02-02 22:42:33 +08:00
parent db2f1a601c
commit 8322e62c18
9 changed files with 115 additions and 68 deletions

View File

@ -576,7 +576,7 @@ Breaking changes
New features New features
------------ ------------
* Line continuation (via `\`) and multi-line literal strings (wrapped with <code>\`</code>) support are added. * Line continuation (via `\`) and multi-line literal strings (wrapped with `` ` ``) support are added.
* Rhai scripts can now start with a shebang `#!` which is ignored. * Rhai scripts can now start with a shebang `#!` which is ignored.
Enhancements Enhancements

View File

@ -190,8 +190,8 @@ impl Engine {
&mut this_ptr, &mut this_ptr,
fn_def, fn_def,
&mut args, &mut args,
Position::NONE,
rewind_scope, rewind_scope,
Position::NONE,
0, 0,
); );

View File

@ -191,8 +191,8 @@ impl Engine {
let fn_name = crate::engine::FN_IDX_SET; let fn_name = crate::engine::FN_IDX_SET;
if let Err(err) = self.exec_fn_call( if let Err(err) = self.exec_fn_call(
global, state, lib, fn_name, hash_set, args, is_ref_mut, true, None, global, state, lib, fn_name, hash_set, args, is_ref_mut,
root_pos, None, level, true, root_pos, level,
) { ) {
// Just ignore if there is no index setter // Just ignore if there is no index setter
if !matches!(*err, ERR::ErrorFunctionNotFound(_, _)) { if !matches!(*err, ERR::ErrorFunctionNotFound(_, _)) {
@ -244,8 +244,8 @@ impl Engine {
let fn_name = crate::engine::FN_IDX_SET; let fn_name = crate::engine::FN_IDX_SET;
self.exec_fn_call( self.exec_fn_call(
global, state, lib, fn_name, hash_set, args, is_ref_mut, true, None, global, state, lib, fn_name, hash_set, args, is_ref_mut,
root_pos, None, level, true, root_pos, level,
)?; )?;
} }
@ -351,8 +351,8 @@ impl Engine {
let args = &mut [target.as_mut()]; let args = &mut [target.as_mut()];
let (mut orig_val, _) = self let (mut orig_val, _) = self
.exec_fn_call( .exec_fn_call(
global, state, lib, getter, hash, args, is_ref_mut, true, *pos, None, global, state, lib, getter, hash, args, is_ref_mut, true,
None, level, *pos, level,
) )
.or_else(|err| match *err { .or_else(|err| match *err {
// Try an indexer if property does not exist // Try an indexer if property does not exist
@ -392,7 +392,7 @@ impl Engine {
let hash = crate::ast::FnCallHashes::from_native(*hash_set); let hash = crate::ast::FnCallHashes::from_native(*hash_set);
let args = &mut [target.as_mut(), &mut new_val]; let args = &mut [target.as_mut(), &mut new_val];
self.exec_fn_call( self.exec_fn_call(
global, state, lib, setter, hash, args, is_ref_mut, true, *pos, None, None, global, state, lib, setter, hash, args, is_ref_mut, true, *pos,
level, level,
) )
.or_else(|err| match *err { .or_else(|err| match *err {
@ -405,8 +405,8 @@ impl Engine {
let pos = Position::NONE; let pos = Position::NONE;
self.exec_fn_call( self.exec_fn_call(
global, state, lib, fn_name, hash_set, args, is_ref_mut, true, None, global, state, lib, fn_name, hash_set, args, is_ref_mut,
pos, None, level, true, pos, level,
) )
.map_err( .map_err(
|idx_err| match *idx_err { |idx_err| match *idx_err {
@ -429,7 +429,7 @@ impl Engine {
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()];
self.exec_fn_call( self.exec_fn_call(
global, state, lib, getter, hash, args, is_ref_mut, true, *pos, None, None, global, state, lib, getter, hash, args, is_ref_mut, true, *pos,
level, level,
) )
.map_or_else( .map_or_else(
@ -537,8 +537,8 @@ impl Engine {
// Assume getters are always pure // Assume getters are always pure
let (mut val, _) = self let (mut val, _) = self
.exec_fn_call( .exec_fn_call(
global, state, lib, getter, hash_get, args, is_ref_mut, None, global, state, lib, getter, hash_get, args,
true, pos, None, level, is_ref_mut, true, pos, level,
) )
.or_else(|err| match *err { .or_else(|err| match *err {
// Try an indexer if property does not exist // Try an indexer if property does not exist
@ -585,8 +585,8 @@ impl Engine {
let mut arg_values = [target.as_mut(), val]; let mut arg_values = [target.as_mut(), val];
let args = &mut arg_values; let args = &mut arg_values;
self.exec_fn_call( self.exec_fn_call(
global, state, lib, setter, hash_set, args, is_ref_mut, None, global, state, lib, setter, hash_set, args,
true, pos, None, level, is_ref_mut, true, pos, level,
) )
.or_else( .or_else(
|err| match *err { |err| match *err {
@ -600,8 +600,8 @@ impl Engine {
global.hash_idx_set(), global.hash_idx_set(),
); );
self.exec_fn_call( self.exec_fn_call(
global, state, lib, fn_name, hash_set, args, None, global, state, lib, fn_name, hash_set,
is_ref_mut, true, pos, None, level, args, is_ref_mut, true, pos, level,
) )
.or_else(|idx_err| match *idx_err { .or_else(|idx_err| match *idx_err {
ERR::ErrorIndexingType(_, _) => { ERR::ErrorIndexingType(_, _) => {
@ -767,7 +767,7 @@ impl Engine {
(crate::FnArgsVec::with_capacity(args.len()), Position::NONE), (crate::FnArgsVec::with_capacity(args.len()), Position::NONE),
|(mut values, mut pos), expr| -> RhaiResultOf<_> { |(mut values, mut pos), expr| -> RhaiResultOf<_> {
let (value, arg_pos) = self.get_arg_value( let (value, arg_pos) = self.get_arg_value(
scope, global, state, lib, this_ptr, level, expr, constants, scope, global, state, lib, this_ptr, expr, constants, level,
)?; )?;
if values.is_empty() { if values.is_empty() {
pos = arg_pos; pos = arg_pos;
@ -813,7 +813,7 @@ impl Engine {
(crate::FnArgsVec::with_capacity(args.len()), Position::NONE), (crate::FnArgsVec::with_capacity(args.len()), Position::NONE),
|(mut values, mut pos), expr| -> RhaiResultOf<_> { |(mut values, mut pos), expr| -> RhaiResultOf<_> {
let (value, arg_pos) = self.get_arg_value( let (value, arg_pos) = self.get_arg_value(
scope, global, state, lib, this_ptr, level, expr, constants, scope, global, state, lib, this_ptr, expr, constants, level,
)?; )?;
if values.is_empty() { if values.is_empty() {
pos = arg_pos pos = arg_pos
@ -1079,7 +1079,7 @@ impl Engine {
let pos = Position::NONE; let pos = Position::NONE;
self.exec_fn_call( self.exec_fn_call(
global, state, lib, fn_name, hash_get, args, true, true, pos, None, level, None, global, state, lib, fn_name, hash_get, args, true, true, pos, level,
) )
.map(|(v, _)| v.into()) .map(|(v, _)| v.into())
} }

View File

@ -51,6 +51,13 @@ pub enum DebuggerCommand {
FunctionExit, FunctionExit,
} }
impl Default for DebuggerCommand {
#[inline(always)]
fn default() -> Self {
Self::Continue
}
}
/// The debugger status. /// The debugger status.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub enum DebuggerStatus { pub enum DebuggerStatus {
@ -60,6 +67,19 @@ pub enum DebuggerStatus {
FunctionExit(usize), FunctionExit(usize),
} }
impl Default for DebuggerStatus {
#[inline(always)]
fn default() -> Self {
Self::CONTINUE
}
}
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);
}
/// A event that triggers the debugger. /// A event that triggers the debugger.
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum DebuggerEvent<'a> { pub enum DebuggerEvent<'a> {
@ -231,7 +251,7 @@ impl fmt::Display for CallStackFrame {
#[derive(Debug, Clone, Hash)] #[derive(Debug, Clone, Hash)]
pub struct Debugger { pub struct Debugger {
/// The current status command. /// The current status command.
status: DebuggerStatus, pub(crate) status: DebuggerStatus,
/// The current state. /// The current state.
state: Dynamic, state: Dynamic,
/// The current set of break-points. /// The current set of break-points.
@ -247,9 +267,9 @@ impl Debugger {
pub fn new(engine: &Engine) -> Self { pub fn new(engine: &Engine) -> Self {
Self { Self {
status: if engine.debugger.is_some() { status: if engine.debugger.is_some() {
DebuggerStatus::Next(true, true) DebuggerStatus::STEP
} else { } else {
DebuggerStatus::Next(false, false) DebuggerStatus::CONTINUE
}, },
state: if let Some((ref init, _)) = engine.debugger { state: if let Some((ref init, _)) = engine.debugger {
init() init()
@ -299,12 +319,6 @@ impl Debugger {
pos, pos,
}); });
} }
/// Get the current status of this [`Debugger`].
#[inline(always)]
#[must_use]
pub(crate) fn status(&self) -> DebuggerStatus {
self.status
}
/// Set the status of this [`Debugger`]. /// Set the status of this [`Debugger`].
#[inline(always)] #[inline(always)]
pub(crate) fn reset_status(&mut self, status: Option<DebuggerStatus>) { pub(crate) fn reset_status(&mut self, status: Option<DebuggerStatus>) {
@ -476,19 +490,19 @@ impl Engine {
match command { match command {
DebuggerCommand::Continue => { DebuggerCommand::Continue => {
global.debugger.status = DebuggerStatus::Next(false, false); global.debugger.status = DebuggerStatus::CONTINUE;
Ok(None) Ok(None)
} }
DebuggerCommand::Next => { DebuggerCommand::Next => {
global.debugger.status = DebuggerStatus::Next(false, false); global.debugger.status = DebuggerStatus::CONTINUE;
Ok(Some(DebuggerStatus::Next(true, false))) Ok(Some(DebuggerStatus::NEXT))
} }
DebuggerCommand::StepOver => { DebuggerCommand::StepOver => {
global.debugger.status = DebuggerStatus::Next(false, false); global.debugger.status = DebuggerStatus::CONTINUE;
Ok(Some(DebuggerStatus::Next(true, true))) Ok(Some(DebuggerStatus::STEP))
} }
DebuggerCommand::StepInto => { DebuggerCommand::StepInto => {
global.debugger.status = DebuggerStatus::Next(true, true); global.debugger.status = DebuggerStatus::STEP;
Ok(None) Ok(None)
} }
DebuggerCommand::FunctionExit => { DebuggerCommand::FunctionExit => {
@ -499,6 +513,7 @@ 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

@ -236,8 +236,8 @@ impl Engine {
); );
self.make_function_call( self.make_function_call(
scope, global, state, lib, this_ptr, name, first_arg, args, constants, *hashes, pos, scope, global, state, lib, this_ptr, name, first_arg, args, constants, *hashes,
*capture, level, *capture, pos, level,
) )
} }

View File

@ -153,6 +153,7 @@ impl Engine {
let hash = hash_op_assign; let hash = hash_op_assign;
let args = &mut [lhs_ptr_inner, &mut new_val]; let args = &mut [lhs_ptr_inner, &mut new_val];
let level = level + 1;
match self.call_native_fn( match self.call_native_fn(
global, state, lib, op_assign, hash, args, true, true, op_pos, level, global, state, lib, op_assign, hash, args, true, true, op_pos, level,

View File

@ -427,7 +427,7 @@ impl Engine {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
if self.debugger.is_some() { if self.debugger.is_some() {
match global.debugger.status() { match global.debugger.status {
crate::eval::DebuggerStatus::FunctionExit(n) if n >= level => { crate::eval::DebuggerStatus::FunctionExit(n) if n >= level => {
let scope = &mut &mut Scope::new(); let scope = &mut &mut Scope::new();
let node = crate::ast::Stmt::Noop(pos); let node = crate::ast::Stmt::Noop(pos);
@ -591,6 +591,7 @@ impl Engine {
/// **DO NOT** reuse the argument values unless for the first `&mut` argument - all others are silently replaced by `()`! /// **DO NOT** reuse the argument values unless for the first `&mut` argument - all others are silently replaced by `()`!
pub(crate) fn exec_fn_call( pub(crate) fn exec_fn_call(
&self, &self,
scope: Option<&mut Scope>,
global: &mut GlobalRuntimeState, global: &mut GlobalRuntimeState,
state: &mut EvalState, state: &mut EvalState,
lib: &[&Module], lib: &[&Module],
@ -600,7 +601,6 @@ impl Engine {
is_ref_mut: bool, is_ref_mut: bool,
is_method_call: bool, is_method_call: bool,
pos: Position, pos: Position,
scope: Option<&mut Scope>,
level: usize, level: usize,
) -> RhaiResultOf<(Dynamic, bool)> { ) -> RhaiResultOf<(Dynamic, bool)> {
fn no_method_err(name: &str, pos: Position) -> RhaiResultOf<(Dynamic, bool)> { fn no_method_err(name: &str, pos: Position) -> RhaiResultOf<(Dynamic, bool)> {
@ -711,8 +711,8 @@ impl Engine {
&mut Some(*first_arg), &mut Some(*first_arg),
func, func,
rest_args, rest_args,
pos,
true, true,
pos,
level, level,
); );
@ -730,7 +730,7 @@ impl Engine {
} }
let result = self.call_script_fn( let result = self.call_script_fn(
scope, global, state, lib, &mut None, func, args, pos, true, level, scope, global, state, lib, &mut None, func, args, true, pos, level,
); );
// Restore the original reference // Restore the original reference
@ -812,7 +812,7 @@ impl Engine {
// Map it to name(args) in function-call style // Map it to name(args) in function-call style
self.exec_fn_call( self.exec_fn_call(
global, state, lib, fn_name, new_hash, &mut args, false, false, pos, None, None, global, state, lib, fn_name, new_hash, &mut args, false, false, pos,
level, level,
) )
} }
@ -852,7 +852,7 @@ impl Engine {
// Map it to name(args) in function-call style // Map it to name(args) in function-call style
self.exec_fn_call( self.exec_fn_call(
global, state, lib, fn_name, new_hash, &mut args, is_ref_mut, true, pos, None, None, global, state, lib, fn_name, new_hash, &mut args, is_ref_mut, true, pos,
level, level,
) )
} }
@ -924,7 +924,7 @@ impl Engine {
args.extend(call_args.iter_mut()); args.extend(call_args.iter_mut());
self.exec_fn_call( self.exec_fn_call(
global, state, lib, fn_name, hash, &mut args, is_ref_mut, true, pos, None, None, global, state, lib, fn_name, hash, &mut args, is_ref_mut, true, pos,
level, level,
) )
} }
@ -949,9 +949,9 @@ impl Engine {
state: &mut EvalState, state: &mut EvalState,
lib: &[&Module], lib: &[&Module],
this_ptr: &mut Option<&mut Dynamic>, this_ptr: &mut Option<&mut Dynamic>,
level: usize,
arg_expr: &Expr, arg_expr: &Expr,
constants: &[Dynamic], constants: &[Dynamic],
level: usize,
) -> RhaiResultOf<(Dynamic, Position)> { ) -> RhaiResultOf<(Dynamic, Position)> {
Ok(( Ok((
if let Expr::Stack(slot, _) = arg_expr { if let Expr::Stack(slot, _) = arg_expr {
@ -967,7 +967,26 @@ impl Engine {
} }
value value
} else { } else {
self.eval_expr(scope, global, state, lib, this_ptr, arg_expr, level)? // Do not match function exit for arguments
#[cfg(feature = "debugging")]
let reset_debugger = match global.debugger.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);
// Restore function exit if status is not active
#[cfg(feature = "debugging")]
if self.debugger.is_some()
&& global.debugger.status == crate::eval::DebuggerStatus::CONTINUE
{
global.debugger.reset_status(reset_debugger);
}
result?
}, },
arg_expr.position(), arg_expr.position(),
)) ))
@ -986,8 +1005,8 @@ impl Engine {
args_expr: &[Expr], args_expr: &[Expr],
constants: &[Dynamic], constants: &[Dynamic],
hashes: FnCallHashes, hashes: FnCallHashes,
pos: Position,
capture_scope: bool, capture_scope: bool,
pos: Position,
level: usize, level: usize,
) -> RhaiResult { ) -> RhaiResult {
let mut first_arg = first_arg; let mut first_arg = first_arg;
@ -1003,7 +1022,7 @@ impl Engine {
KEYWORD_FN_PTR_CALL if total_args >= 1 => { KEYWORD_FN_PTR_CALL if total_args >= 1 => {
let arg = first_arg.unwrap(); let arg = first_arg.unwrap();
let (arg_value, arg_pos) = let (arg_value, arg_pos) =
self.get_arg_value(scope, global, state, lib, this_ptr, level, arg, constants)?; self.get_arg_value(scope, global, state, lib, this_ptr, arg, constants, level)?;
if !arg_value.is::<FnPtr>() { if !arg_value.is::<FnPtr>() {
return Err(self.make_type_mismatch_err::<FnPtr>( return Err(self.make_type_mismatch_err::<FnPtr>(
@ -1038,7 +1057,7 @@ impl Engine {
KEYWORD_FN_PTR if total_args == 1 => { KEYWORD_FN_PTR if total_args == 1 => {
let arg = first_arg.unwrap(); let arg = first_arg.unwrap();
let (arg_value, arg_pos) = let (arg_value, arg_pos) =
self.get_arg_value(scope, global, state, lib, this_ptr, level, arg, constants)?; self.get_arg_value(scope, global, state, lib, this_ptr, arg, constants, level)?;
// Fn - only in function call style // Fn - only in function call style
return arg_value return arg_value
@ -1053,7 +1072,7 @@ impl Engine {
KEYWORD_FN_PTR_CURRY if total_args > 1 => { KEYWORD_FN_PTR_CURRY if total_args > 1 => {
let first = first_arg.unwrap(); let first = first_arg.unwrap();
let (arg_value, arg_pos) = self let (arg_value, arg_pos) = self
.get_arg_value(scope, global, state, lib, this_ptr, level, first, constants)?; .get_arg_value(scope, global, state, lib, this_ptr, first, constants, level)?;
if !arg_value.is::<FnPtr>() { if !arg_value.is::<FnPtr>() {
return Err(self.make_type_mismatch_err::<FnPtr>( return Err(self.make_type_mismatch_err::<FnPtr>(
@ -1070,7 +1089,7 @@ impl Engine {
.iter() .iter()
.try_fold(fn_curry, |mut curried, expr| -> RhaiResultOf<_> { .try_fold(fn_curry, |mut curried, expr| -> RhaiResultOf<_> {
let (value, _) = self.get_arg_value( let (value, _) = self.get_arg_value(
scope, global, state, lib, this_ptr, level, expr, constants, scope, global, state, lib, this_ptr, expr, constants, level,
)?; )?;
curried.push(value); curried.push(value);
Ok(curried) Ok(curried)
@ -1084,7 +1103,7 @@ impl Engine {
crate::engine::KEYWORD_IS_SHARED if total_args == 1 => { crate::engine::KEYWORD_IS_SHARED if total_args == 1 => {
let arg = first_arg.unwrap(); let arg = first_arg.unwrap();
let (arg_value, _) = let (arg_value, _) =
self.get_arg_value(scope, global, state, lib, this_ptr, level, arg, constants)?; self.get_arg_value(scope, global, state, lib, this_ptr, arg, constants, level)?;
return Ok(arg_value.is_shared().into()); return Ok(arg_value.is_shared().into());
} }
@ -1093,14 +1112,14 @@ impl Engine {
crate::engine::KEYWORD_IS_DEF_FN if total_args == 2 => { crate::engine::KEYWORD_IS_DEF_FN if total_args == 2 => {
let first = first_arg.unwrap(); let first = first_arg.unwrap();
let (arg_value, arg_pos) = self let (arg_value, arg_pos) = self
.get_arg_value(scope, global, state, lib, this_ptr, level, first, constants)?; .get_arg_value(scope, global, state, lib, this_ptr, first, constants, level)?;
let fn_name = arg_value let fn_name = arg_value
.into_immutable_string() .into_immutable_string()
.map_err(|typ| self.make_type_mismatch_err::<ImmutableString>(typ, arg_pos))?; .map_err(|typ| self.make_type_mismatch_err::<ImmutableString>(typ, arg_pos))?;
let (arg_value, arg_pos) = self.get_arg_value( let (arg_value, arg_pos) = self.get_arg_value(
scope, global, state, lib, this_ptr, level, &a_expr[0], constants, scope, global, state, lib, this_ptr, &a_expr[0], constants, level,
)?; )?;
let num_params = arg_value let num_params = arg_value
@ -1120,7 +1139,7 @@ impl Engine {
KEYWORD_IS_DEF_VAR if total_args == 1 => { KEYWORD_IS_DEF_VAR if total_args == 1 => {
let arg = first_arg.unwrap(); let arg = first_arg.unwrap();
let (arg_value, arg_pos) = let (arg_value, arg_pos) =
self.get_arg_value(scope, global, state, lib, this_ptr, level, arg, constants)?; self.get_arg_value(scope, global, state, lib, this_ptr, arg, constants, level)?;
let var_name = arg_value let var_name = arg_value
.into_immutable_string() .into_immutable_string()
.map_err(|typ| self.make_type_mismatch_err::<ImmutableString>(typ, arg_pos))?; .map_err(|typ| self.make_type_mismatch_err::<ImmutableString>(typ, arg_pos))?;
@ -1133,7 +1152,7 @@ impl Engine {
let orig_scope_len = scope.len(); let orig_scope_len = scope.len();
let arg = first_arg.unwrap(); let arg = first_arg.unwrap();
let (arg_value, pos) = let (arg_value, pos) =
self.get_arg_value(scope, global, state, lib, this_ptr, level, arg, constants)?; self.get_arg_value(scope, global, state, lib, this_ptr, arg, constants, level)?;
let script = &arg_value let script = &arg_value
.into_immutable_string() .into_immutable_string()
.map_err(|typ| self.make_type_mismatch_err::<ImmutableString>(typ, pos))?; .map_err(|typ| self.make_type_mismatch_err::<ImmutableString>(typ, pos))?;
@ -1182,7 +1201,7 @@ impl Engine {
.map(|&v| v) .map(|&v| v)
.chain(a_expr.iter()) .chain(a_expr.iter())
.try_for_each(|expr| { .try_for_each(|expr| {
self.get_arg_value(scope, global, state, lib, this_ptr, level, expr, constants) self.get_arg_value(scope, global, state, lib, this_ptr, expr, constants, level)
.map(|(value, _)| arg_values.push(value.flatten())) .map(|(value, _)| arg_values.push(value.flatten()))
})?; })?;
args.extend(curry.iter_mut()); args.extend(curry.iter_mut());
@ -1193,7 +1212,7 @@ impl Engine {
return self return self
.exec_fn_call( .exec_fn_call(
global, state, lib, name, hashes, &mut args, is_ref_mut, false, pos, scope, scope, global, state, lib, name, hashes, &mut args, is_ref_mut, false, pos,
level, level,
) )
.map(|(v, _)| v); .map(|(v, _)| v);
@ -1216,7 +1235,7 @@ impl Engine {
// func(x, ...) -> x.func(...) // func(x, ...) -> x.func(...)
a_expr.iter().try_for_each(|expr| { a_expr.iter().try_for_each(|expr| {
self.get_arg_value(scope, global, state, lib, this_ptr, level, expr, constants) self.get_arg_value(scope, global, state, lib, this_ptr, expr, constants, level)
.map(|(value, _)| arg_values.push(value.flatten())) .map(|(value, _)| arg_values.push(value.flatten()))
})?; })?;
@ -1252,7 +1271,7 @@ impl Engine {
.chain(a_expr.iter()) .chain(a_expr.iter())
.try_for_each(|expr| { .try_for_each(|expr| {
self.get_arg_value( self.get_arg_value(
scope, global, state, lib, this_ptr, level, expr, constants, scope, global, state, lib, this_ptr, expr, constants, level,
) )
.map(|(value, _)| arg_values.push(value.flatten())) .map(|(value, _)| arg_values.push(value.flatten()))
})?; })?;
@ -1262,7 +1281,7 @@ impl Engine {
} }
self.exec_fn_call( self.exec_fn_call(
global, state, lib, name, hashes, &mut args, is_ref_mut, false, pos, None, level, None, global, state, lib, name, hashes, &mut args, is_ref_mut, false, pos, level,
) )
.map(|(v, _)| v) .map(|(v, _)| v)
} }
@ -1305,7 +1324,7 @@ impl Engine {
arg_values.push(Dynamic::UNIT); arg_values.push(Dynamic::UNIT);
args_expr.iter().skip(1).try_for_each(|expr| { args_expr.iter().skip(1).try_for_each(|expr| {
self.get_arg_value(scope, global, state, lib, this_ptr, level, expr, constants) self.get_arg_value(scope, global, state, lib, this_ptr, expr, constants, level)
.map(|(value, _)| arg_values.push(value.flatten())) .map(|(value, _)| arg_values.push(value.flatten()))
})?; })?;
@ -1335,7 +1354,7 @@ impl Engine {
} else { } else {
// func(..., ...) or func(mod::x, ...) // func(..., ...) or func(mod::x, ...)
args_expr.iter().try_for_each(|expr| { args_expr.iter().try_for_each(|expr| {
self.get_arg_value(scope, global, state, lib, this_ptr, level, expr, constants) self.get_arg_value(scope, global, state, lib, this_ptr, expr, constants, level)
.map(|(value, _)| arg_values.push(value.flatten())) .map(|(value, _)| arg_values.push(value.flatten()))
})?; })?;
args.extend(arg_values.iter_mut()); args.extend(arg_values.iter_mut());
@ -1385,7 +1404,7 @@ impl Engine {
mem::swap(&mut global.source, &mut source); mem::swap(&mut global.source, &mut source);
let result = self.call_script_fn( let result = self.call_script_fn(
new_scope, global, state, lib, &mut None, fn_def, &mut args, pos, true, new_scope, global, state, lib, &mut None, fn_def, &mut args, true, pos,
level, level,
); );

View File

@ -321,6 +321,7 @@ impl<'a> NativeCallContext<'a> {
self.engine() self.engine()
.exec_fn_call( .exec_fn_call(
None,
&mut global, &mut global,
&mut state, &mut state,
self.lib, self.lib,
@ -330,7 +331,6 @@ impl<'a> NativeCallContext<'a> {
is_ref_mut, is_ref_mut,
is_method_call, is_method_call,
Position::NONE, Position::NONE,
None,
self.level + 1, self.level + 1,
) )
.map(|(r, _)| r) .map(|(r, _)| r)

View File

@ -31,8 +31,8 @@ impl Engine {
this_ptr: &mut Option<&mut Dynamic>, this_ptr: &mut Option<&mut Dynamic>,
fn_def: &ScriptFnDef, fn_def: &ScriptFnDef,
args: &mut FnCallArgs, args: &mut FnCallArgs,
pos: Position,
rewind_scope: bool, rewind_scope: bool,
pos: Position,
level: usize, level: usize,
) -> RhaiResult { ) -> RhaiResult {
#[inline(never)] #[inline(never)]
@ -73,6 +73,11 @@ impl Engine {
return Err(ERR::ErrorStackOverflow(pos).into()); return Err(ERR::ErrorStackOverflow(pos).into());
} }
#[cfg(feature = "debugging")]
if self.debugger.is_none() && fn_def.body.is_empty() {
return Ok(Dynamic::UNIT);
}
#[cfg(not(feature = "debugging"))]
if fn_def.body.is_empty() { if fn_def.body.is_empty() {
return Ok(Dynamic::UNIT); return Ok(Dynamic::UNIT);
} }
@ -136,6 +141,13 @@ impl Engine {
(lib, None) (lib, None)
}; };
#[cfg(feature = "debugging")]
if self.debugger.is_some() {
println!("Level = {}", level);
let node = crate::ast::Stmt::Noop(fn_def.body.position());
self.run_debugger(scope, global, state, lib, this_ptr, &node, level)?;
}
// Evaluate the function // Evaluate the function
let mut _result = self let mut _result = self
.eval_stmt_block( .eval_stmt_block(
@ -172,7 +184,7 @@ impl Engine {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
if self.debugger.is_some() { if self.debugger.is_some() {
match global.debugger.status() { match global.debugger.status {
crate::eval::DebuggerStatus::FunctionExit(n) if n >= level => { crate::eval::DebuggerStatus::FunctionExit(n) if n >= level => {
let node = crate::ast::Stmt::Noop(pos); let node = crate::ast::Stmt::Noop(pos);
let node = (&node).into(); let node = (&node).into();