Add debugging interface.
This commit is contained in:
162
src/eval/expr.rs
162
src/eval/expr.rs
@@ -242,6 +242,13 @@ impl Engine {
|
||||
}
|
||||
|
||||
/// Evaluate an expression.
|
||||
//
|
||||
// # Implementation Notes
|
||||
//
|
||||
// Do not use the `?` operator within the main body as it makes this function return early,
|
||||
// possibly by-passing important cleanup tasks at the end.
|
||||
//
|
||||
// Errors that are not recoverable, such as system errors or safety errors, can use `?`.
|
||||
pub(crate) fn eval_expr(
|
||||
&self,
|
||||
scope: &mut Scope,
|
||||
@@ -252,6 +259,10 @@ impl Engine {
|
||||
expr: &Expr,
|
||||
level: usize,
|
||||
) -> 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.
|
||||
// Popular branches are lifted out of the `match` statement into their own branches.
|
||||
|
||||
@@ -261,7 +272,13 @@ impl Engine {
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
self.inc_operations(&mut global.num_operations, expr.position())?;
|
||||
|
||||
return self.eval_fn_call_expr(scope, global, state, lib, this_ptr, x, *pos, level);
|
||||
let result =
|
||||
self.eval_fn_call_expr(scope, global, state, lib, this_ptr, x, *pos, level);
|
||||
|
||||
#[cfg(feature = "debugging")]
|
||||
global.debugger.activate(reset_debugger_command);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Then variable access.
|
||||
@@ -271,7 +288,7 @@ impl Engine {
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
self.inc_operations(&mut global.num_operations, expr.position())?;
|
||||
|
||||
return if index.is_none() && x.0.is_none() && x.2 == KEYWORD_THIS {
|
||||
let result = if index.is_none() && x.0.is_none() && x.2 == KEYWORD_THIS {
|
||||
this_ptr
|
||||
.as_deref()
|
||||
.cloned()
|
||||
@@ -280,12 +297,17 @@ impl Engine {
|
||||
self.search_namespace(scope, global, state, lib, this_ptr, expr)
|
||||
.map(|(val, _)| val.take_or_clone())
|
||||
};
|
||||
|
||||
#[cfg(feature = "debugging")]
|
||||
global.debugger.activate(reset_debugger_command);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
self.inc_operations(&mut global.num_operations, expr.position())?;
|
||||
|
||||
match expr {
|
||||
let result = match expr {
|
||||
// Constants
|
||||
Expr::DynamicConstant(x, _) => Ok(x.as_ref().clone()),
|
||||
Expr::IntegerConstant(x, _) => Ok((*x).into()),
|
||||
@@ -299,47 +321,62 @@ impl Engine {
|
||||
// `... ${...} ...`
|
||||
Expr::InterpolatedString(x, pos) => {
|
||||
let mut pos = *pos;
|
||||
let mut result: Dynamic = self.const_empty_string().into();
|
||||
let mut concat: Dynamic = self.const_empty_string().into();
|
||||
let mut result = Ok(Dynamic::UNIT);
|
||||
|
||||
for expr in x.iter() {
|
||||
let item = self.eval_expr(scope, global, state, lib, this_ptr, expr, level)?;
|
||||
let item =
|
||||
match self.eval_expr(scope, global, state, lib, this_ptr, expr, level) {
|
||||
Ok(r) => r,
|
||||
err => {
|
||||
result = err;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
self.eval_op_assignment(
|
||||
if let Err(err) = self.eval_op_assignment(
|
||||
global,
|
||||
state,
|
||||
lib,
|
||||
Some(OpAssignment::new(OP_CONCAT)),
|
||||
pos,
|
||||
&mut (&mut result).into(),
|
||||
&mut (&mut concat).into(),
|
||||
("", Position::NONE),
|
||||
item,
|
||||
)
|
||||
.map_err(|err| err.fill_position(expr.position()))?;
|
||||
) {
|
||||
result = Err(err.fill_position(expr.position()));
|
||||
break;
|
||||
}
|
||||
|
||||
pos = expr.position();
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
result.map(|_| concat)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Expr::Array(x, _) => {
|
||||
let mut arr = Dynamic::from_array(crate::Array::with_capacity(x.len()));
|
||||
let mut arr = crate::Array::with_capacity(x.len());
|
||||
let mut result = Ok(Dynamic::UNIT);
|
||||
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
let mut sizes = (0, 0, 0);
|
||||
|
||||
for item_expr in x.iter() {
|
||||
let value = self
|
||||
.eval_expr(scope, global, state, lib, this_ptr, item_expr, level)?
|
||||
.flatten();
|
||||
let value = match self
|
||||
.eval_expr(scope, global, state, lib, this_ptr, item_expr, level)
|
||||
{
|
||||
Ok(r) => r.flatten(),
|
||||
err => {
|
||||
result = err;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
let val_sizes = Self::calc_data_sizes(&value, true);
|
||||
|
||||
arr.write_lock::<crate::Array>()
|
||||
.expect("`Array`")
|
||||
.push(value);
|
||||
arr.push(value);
|
||||
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
if self.has_data_size_limit() {
|
||||
@@ -352,29 +389,33 @@ impl Engine {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(arr)
|
||||
result.map(|_| arr.into())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Expr::Map(x, _) => {
|
||||
let mut map = Dynamic::from_map(x.1.clone());
|
||||
let mut map = x.1.clone();
|
||||
let mut result = Ok(Dynamic::UNIT);
|
||||
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
let mut sizes = (0, 0, 0);
|
||||
|
||||
for (crate::ast::Ident { name, .. }, value_expr) in x.0.iter() {
|
||||
let key = name.as_str();
|
||||
let value = self
|
||||
.eval_expr(scope, global, state, lib, this_ptr, value_expr, level)?
|
||||
.flatten();
|
||||
let value = match self
|
||||
.eval_expr(scope, global, state, lib, this_ptr, value_expr, level)
|
||||
{
|
||||
Ok(r) => r.flatten(),
|
||||
err => {
|
||||
result = err;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
let val_sizes = Self::calc_data_sizes(&value, true);
|
||||
|
||||
*map.write_lock::<crate::Map>()
|
||||
.expect("`Map`")
|
||||
.get_mut(key)
|
||||
.unwrap() = value;
|
||||
*map.get_mut(key).unwrap() = value;
|
||||
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
if self.has_data_size_limit() {
|
||||
@@ -387,33 +428,53 @@ impl Engine {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(map)
|
||||
result.map(|_| map.into())
|
||||
}
|
||||
|
||||
Expr::And(x, _) => {
|
||||
Ok((self
|
||||
.eval_expr(scope, global, state, lib, this_ptr, &x.lhs, level)?
|
||||
.as_bool()
|
||||
.map_err(|typ| self.make_type_mismatch_err::<bool>(typ, x.lhs.position()))?
|
||||
&& // Short-circuit using &&
|
||||
self
|
||||
.eval_expr(scope, global, state, lib, this_ptr, &x.rhs, level)?
|
||||
.as_bool()
|
||||
.map_err(|typ| self.make_type_mismatch_err::<bool>(typ, x.rhs.position()))?)
|
||||
.into())
|
||||
let lhs = self
|
||||
.eval_expr(scope, global, state, lib, this_ptr, &x.lhs, level)
|
||||
.and_then(|v| {
|
||||
v.as_bool().map_err(|typ| {
|
||||
self.make_type_mismatch_err::<bool>(typ, x.lhs.position())
|
||||
})
|
||||
});
|
||||
|
||||
if let Ok(true) = lhs {
|
||||
self.eval_expr(scope, global, state, lib, this_ptr, &x.rhs, level)
|
||||
.and_then(|v| {
|
||||
v.as_bool()
|
||||
.map_err(|typ| {
|
||||
self.make_type_mismatch_err::<bool>(typ, x.rhs.position())
|
||||
})
|
||||
.map(Into::into)
|
||||
})
|
||||
} else {
|
||||
lhs.map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
Expr::Or(x, _) => {
|
||||
Ok((self
|
||||
.eval_expr(scope, global, state, lib, this_ptr, &x.lhs, level)?
|
||||
.as_bool()
|
||||
.map_err(|typ| self.make_type_mismatch_err::<bool>(typ, x.lhs.position()))?
|
||||
|| // Short-circuit using ||
|
||||
self
|
||||
.eval_expr(scope, global, state, lib, this_ptr, &x.rhs, level)?
|
||||
.as_bool()
|
||||
.map_err(|typ| self.make_type_mismatch_err::<bool>(typ, x.rhs.position()))?)
|
||||
.into())
|
||||
let lhs = self
|
||||
.eval_expr(scope, global, state, lib, this_ptr, &x.lhs, level)
|
||||
.and_then(|v| {
|
||||
v.as_bool().map_err(|typ| {
|
||||
self.make_type_mismatch_err::<bool>(typ, x.lhs.position())
|
||||
})
|
||||
});
|
||||
|
||||
if let Ok(false) = lhs {
|
||||
self.eval_expr(scope, global, state, lib, this_ptr, &x.rhs, level)
|
||||
.and_then(|v| {
|
||||
v.as_bool()
|
||||
.map_err(|typ| {
|
||||
self.make_type_mismatch_err::<bool>(typ, x.rhs.position())
|
||||
})
|
||||
.map(Into::into)
|
||||
})
|
||||
} else {
|
||||
lhs.map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
Expr::Custom(custom, pos) => {
|
||||
@@ -459,6 +520,11 @@ impl Engine {
|
||||
}
|
||||
|
||||
_ => unreachable!("expression cannot be evaluated: {:?}", expr),
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(feature = "debugging")]
|
||||
global.debugger.activate(reset_debugger_command);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user