diff --git a/.gitignore b/.gitignore index d2538ea13..77c1ef44e 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ doc/rhai.json .idea/ .idea .idea/* +src/eval/chaining.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 0449bfa9f..8794d2c2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ Enhancements * Array/BLOB/string iterators are defined also within the `BasicIteratorPackage` in addition to the regular array/BLOB/string packages. * `LexError::Runtime` is added for use with `Engine::on_parse_token`. * Shared values under `sync` are now handled more elegantly -- instead of deadlocking and hanging indefinitely, it spins for a number of tries (waiting one second between each), then errors out. +* `parse_json` is also available without the `metadata` or `serde` feature -- it uses `Engine::parse_json` to parse the JSON text. Version 1.17.2 diff --git a/src/api/call_fn.rs b/src/api/call_fn.rs index 2d477caaa..fd94391d4 100644 --- a/src/api/call_fn.rs +++ b/src/api/call_fn.rs @@ -275,7 +275,7 @@ impl Engine { if self.is_debugger_registered() { global.debugger_mut().status = crate::eval::DebuggerStatus::Terminate; let node = &crate::ast::Stmt::Noop(Position::NONE); - self.run_debugger(global, caches, scope, this_ptr, node)?; + self.dbg(global, caches, scope, this_ptr, node)?; } #[cfg(not(feature = "no_module"))] diff --git a/src/api/eval.rs b/src/api/eval.rs index d5d20e968..5ce11042c 100644 --- a/src/api/eval.rs +++ b/src/api/eval.rs @@ -251,7 +251,7 @@ impl Engine { if self.is_debugger_registered() { global.debugger_mut().status = crate::eval::DebuggerStatus::Terminate; let node = &crate::ast::Stmt::Noop(Position::NONE); - self.run_debugger(global, caches, scope, None, node)?; + self.dbg(global, caches, scope, None, node)?; } Ok(r) diff --git a/src/api/events.rs b/src/api/events.rs index 983550e2e..3f426ffe0 100644 --- a/src/api/events.rs +++ b/src/api/events.rs @@ -348,13 +348,55 @@ impl Engine { /// /// ## Raising errors /// - /// Return `Err(...)` if there is an error, usually [`EvalAltResult::ErrorPropertyNotFound`][crate::EvalAltResult::ErrorPropertyNotFound]. + /// Return `Err(...)` if there is an error, usually + /// [`EvalAltResult::ErrorPropertyNotFound`][crate::EvalAltResult::ErrorPropertyNotFound]. + /// + /// # Example + /// + /// ``` + /// # fn main() -> Result<(), Box> { + /// # use rhai::{Engine, Dynamic, EvalAltResult, Position}; + /// let mut engine = Engine::new(); + /// + /// engine.on_invalid_array_index(|arr, index, _| match index + /// { + /// -100 => { + /// // The array can be modified in place + /// arr.push((42_i64).into()); + /// // Return a mutable reference to an element + /// let value_ref = arr.last_mut().unwrap(); + /// Ok(value_ref.into()) + /// } + /// 100 => { + /// let value = Dynamic::from(100_i64); + /// // Return a temporary value (not a reference) + /// Ok(value.into()) + /// } + /// // Return the standard out-of-bounds error + /// _ => Err(EvalAltResult::ErrorArrayBounds( + /// arr.len(), index, Position::NONE + /// ).into()), + /// }); + /// + /// let r = engine.eval::(" + /// let a = [1, 2, 3]; + /// a[-100] += 1; + /// a[3] + a[100] + /// ")?; + /// + /// assert_eq!(r, 143); + /// # Ok(()) } + /// ``` #[cfg(not(feature = "no_index"))] #[cfg(feature = "internals")] #[inline(always)] pub fn on_invalid_array_index( &mut self, - callback: impl for<'a> Fn(&'a mut crate::Array, crate::INT) -> RhaiResultOf> + callback: impl for<'a> Fn( + &'a mut crate::Array, + crate::INT, + EvalContext, + ) -> RhaiResultOf> + SendSync + 'static, ) -> &mut Self { @@ -385,12 +427,49 @@ impl Engine { /// ## Raising errors /// /// Return `Err(...)` if there is an error, usually [`EvalAltResult::ErrorPropertyNotFound`][crate::EvalAltResult::ErrorPropertyNotFound]. + /// + /// # Example + /// + /// ``` + /// # fn main() -> Result<(), Box> { + /// # use rhai::{Engine, Dynamic, EvalAltResult, Position}; + /// let mut engine = Engine::new(); + /// + /// engine.on_map_missing_property(|map, prop, _| match prop + /// { + /// "x" => { + /// // The object-map can be modified in place + /// map.insert("y".into(), (42_i64).into()); + /// // Return a mutable reference to an element + /// let value_ref = map.get_mut("y").unwrap(); + /// Ok(value_ref.into()) + /// } + /// "z" => { + /// // Return a temporary value (not a reference) + /// let value = Dynamic::from(100_i64); + /// Ok(value.into()) + /// } + /// // Return the standard property-not-found error + /// _ => Err(EvalAltResult::ErrorPropertyNotFound( + /// prop.to_string(), Position::NONE + /// ).into()), + /// }); + /// + /// let r = engine.eval::(" + /// let obj = #{ a:1, b:2 }; + /// obj.x += 1; + /// obj.y + obj.z + /// ")?; + /// + /// assert_eq!(r, 143); + /// # Ok(()) } + /// ``` #[cfg(not(feature = "no_object"))] #[cfg(feature = "internals")] #[inline(always)] pub fn on_map_missing_property( &mut self, - callback: impl for<'a> Fn(&'a mut crate::Map, &str) -> RhaiResultOf> + callback: impl for<'a> Fn(&'a mut crate::Map, &str, EvalContext) -> RhaiResultOf> + SendSync + 'static, ) -> &mut Self { diff --git a/src/api/run.rs b/src/api/run.rs index d4db671ce..faf544fbc 100644 --- a/src/api/run.rs +++ b/src/api/run.rs @@ -138,7 +138,7 @@ impl Engine { if self.is_debugger_registered() { global.debugger_mut().status = crate::eval::DebuggerStatus::Terminate; let node = &crate::ast::Stmt::Noop(crate::Position::NONE); - self.run_debugger(global, caches, scope, None, node)?; + self.dbg(global, caches, scope, None, node)?; } Ok(()) diff --git a/src/eval/chaining.rs b/src/eval/chaining.rs index b700fc43c..7e1815cb7 100644 --- a/src/eval/chaining.rs +++ b/src/eval/chaining.rs @@ -109,6 +109,8 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, + _scope: &mut Scope, + _this_ptr: Option<&mut Dynamic>, target: &'t mut Dynamic, idx: &mut Dynamic, idx_pos: Position, @@ -135,7 +137,10 @@ impl Engine { #[cfg(not(feature = "no_index"))] #[cfg(feature = "internals")] if let Some(ref cb) = self.invalid_array_index { - return cb(arr, index).map_err(|err| err.fill_position(idx_pos)); + let context = + super::EvalContext::new(self, global, caches, _scope, _this_ptr); + return cb(arr, index, context) + .map_err(|err| err.fill_position(idx_pos)); } return Err(err); } @@ -175,7 +180,10 @@ impl Engine { #[cfg(feature = "internals")] if let Some(ref cb) = self.missing_map_property { if !map.contains_key(index.as_str()) { - return cb(map, index.as_str()).map_err(|err| err.fill_position(idx_pos)); + let context = + super::EvalContext::new(self, global, caches, _scope, _this_ptr); + return cb(map, index.as_str(), context) + .map_err(|err| err.fill_position(idx_pos)); } } @@ -406,26 +414,21 @@ impl Engine { )?, } - #[cfg(feature = "debugging")] - let scope2 = &mut Scope::new(); - #[cfg(not(feature = "debugging"))] - let scope2 = (); - match (lhs, new_val) { // this.??? or this[???] (Expr::ThisPtr(var_pos), new_val) => { self.track_operation(global, *var_pos)?; #[cfg(feature = "debugging")] - self.run_debugger(global, caches, scope, this_ptr.as_deref_mut(), lhs)?; + self.dbg(global, caches, scope, this_ptr.as_deref_mut(), lhs)?; this_ptr.map_or_else( || Err(ERR::ErrorUnboundThis(*var_pos).into()), |this_ptr| { let target = &mut this_ptr.into(); - + let scope = Some(scope); self.eval_dot_index_chain_raw( - global, caches, scope2, None, lhs, expr, target, rhs, idx_values, + global, caches, scope, None, lhs, expr, target, rhs, idx_values, new_val, ) }, @@ -436,12 +439,11 @@ impl Engine { self.track_operation(global, *var_pos)?; #[cfg(feature = "debugging")] - self.run_debugger(global, caches, scope, this_ptr.as_deref_mut(), lhs)?; + self.dbg(global, caches, scope, this_ptr.as_deref_mut(), lhs)?; let target = &mut self.search_namespace(global, caches, scope, this_ptr, lhs)?; - self.eval_dot_index_chain_raw( - global, caches, scope2, None, lhs, expr, target, rhs, idx_values, new_val, + global, caches, None, None, lhs, expr, target, rhs, idx_values, new_val, ) } // {expr}.??? = ??? or {expr}[???] = ??? @@ -452,9 +454,9 @@ impl Engine { .eval_expr(global, caches, scope, this_ptr.as_deref_mut(), lhs_expr)? .flatten(); let item_ptr = &mut value.into(); - + let scope = Some(scope); self.eval_dot_index_chain_raw( - global, caches, scope2, this_ptr, lhs_expr, expr, item_ptr, rhs, idx_values, + global, caches, scope, this_ptr, lhs_expr, expr, item_ptr, rhs, idx_values, None, ) } @@ -558,9 +560,8 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - #[cfg(feature = "debugging")] _scope: &mut Scope, - #[cfg(not(feature = "debugging"))] _scope: (), - this_ptr: Option<&mut Dynamic>, + scope: Option<&mut Scope>, + mut this_ptr: Option<&mut Dynamic>, root: &Expr, parent: &Expr, target: &mut Target, @@ -568,13 +569,22 @@ impl Engine { idx_values: &mut FnArgsVec, new_val: Option<(Dynamic, &OpAssignment)>, ) -> RhaiResultOf<(Dynamic, bool)> { + let mut b; + let mut s = scope; + + macro_rules! x { + ($var:ident, $base:ident) => {{ + if $var.is_none() { + $base = Scope::new(); + $var = Some(&mut $base); + } + $var.as_deref_mut().unwrap() + }}; + } + let is_ref_mut = target.is_ref(); let op_pos = parent.position(); - #[cfg(feature = "debugging")] - #[allow(unused_mut)] - let mut this_ptr = this_ptr; - match ChainType::from(parent) { #[cfg(not(feature = "no_index"))] ChainType::Indexing => { @@ -591,7 +601,7 @@ impl Engine { if !parent.options().intersects(ASTFlags::BREAK) => { #[cfg(feature = "debugging")] - self.run_debugger(global, caches, _scope, this_ptr.as_deref_mut(), parent)?; + self.dbg(global, caches, x!(s, b), this_ptr.as_deref_mut(), parent)?; let idx_val = &mut idx_values.pop().unwrap(); let mut idx_val_for_setter = idx_val.clone(); @@ -610,14 +620,17 @@ impl Engine { obj }; + let tp = this_ptr.as_deref_mut(); + let new_scope = x!(s, b); let mut item = self.get_indexed_mut( - global, caches, obj, idx_val, idx_pos, op_pos, false, true, + global, caches, new_scope, tp, obj, idx_val, idx_pos, op_pos, + false, true, )?; let is_item_temp_val = item.is_temp_value(); let item_ptr = &mut item; match self.eval_dot_index_chain_raw( - global, caches, _scope, this_ptr, root, rhs, item_ptr, &x.rhs, + global, caches, s, this_ptr, root, rhs, item_ptr, &x.rhs, idx_values, new_val, ) { Ok((result, true)) if is_item_temp_val => { @@ -649,7 +662,7 @@ impl Engine { // xxx[rhs] op= new_val (_, Some((new_val, op_info))) => { #[cfg(feature = "debugging")] - self.run_debugger(global, caches, _scope, this_ptr, parent)?; + self.dbg(global, caches, x!(s, b), this_ptr.as_deref_mut(), parent)?; let obj = target.as_mut(); @@ -663,12 +676,12 @@ impl Engine { obj }; + let new_scope = x!(s, b); let idx_val = &mut idx_values.pop().unwrap(); let idx = &mut idx_val.clone(); - - let try_setter = match self - .get_indexed_mut(global, caches, obj, idx, pos, op_pos, true, false) - { + let try_setter = match self.get_indexed_mut( + global, caches, new_scope, this_ptr, obj, idx, pos, op_pos, true, false, + ) { // Indexed value is not a temp value - update directly Ok(ref mut item_ptr) => { self.eval_op_assignment( @@ -717,7 +730,7 @@ impl Engine { // xxx[rhs] (_, None) => { #[cfg(feature = "debugging")] - self.run_debugger(global, caches, _scope, this_ptr, parent)?; + self.dbg(global, caches, x!(s, b), this_ptr.as_deref_mut(), parent)?; let obj = target.as_mut(); @@ -731,10 +744,14 @@ impl Engine { obj }; + let new_scope = x!(s, b); let idx_val = &mut idx_values.pop().unwrap(); - self.get_indexed_mut(global, caches, obj, idx_val, pos, op_pos, false, true) - .map(|v| (v.take_or_clone(), false)) + self.get_indexed_mut( + global, caches, new_scope, this_ptr, obj, idx_val, pos, op_pos, false, + true, + ) + .map(|v| (v.take_or_clone(), false)) } } } @@ -760,8 +777,7 @@ impl Engine { ); #[cfg(feature = "debugging")] - let reset = - self.run_debugger_with_reset(global, caches, _scope, this_ptr, rhs)?; + let reset = self.dbg_reset(global, caches, x!(s, b), this_ptr, rhs)?; #[cfg(feature = "debugging")] defer! { global if Some(reset) => move |g| g.debugger_mut().reset_status(reset) } @@ -782,7 +798,7 @@ impl Engine { // {xxx:map}.id op= ??? (Expr::Property(x, pos), Some((new_val, op_info)), true) => { #[cfg(feature = "debugging")] - self.run_debugger(global, caches, _scope, this_ptr, rhs)?; + self.dbg(global, caches, x!(s, b), this_ptr.as_deref_mut(), rhs)?; let index = &mut x.2.clone().into(); { @@ -798,8 +814,11 @@ impl Engine { obj }; + let new_scope = x!(s, b); + let item = &mut self.get_indexed_mut( - global, caches, obj, index, *pos, op_pos, true, false, + global, caches, new_scope, this_ptr, obj, index, *pos, op_pos, + true, false, )?; self.eval_op_assignment(global, caches, op_info, root, item, new_val)?; } @@ -809,7 +828,7 @@ impl Engine { // {xxx:map}.id (Expr::Property(x, pos), None, true) => { #[cfg(feature = "debugging")] - self.run_debugger(global, caches, _scope, this_ptr, rhs)?; + self.dbg(global, caches, x!(s, b), this_ptr.as_deref_mut(), rhs)?; let obj = target.as_mut(); @@ -824,15 +843,18 @@ impl Engine { }; let index = &mut x.2.clone().into(); + let new_scope = x!(s, b); + let item = self.get_indexed_mut( - global, caches, obj, index, *pos, op_pos, false, false, + global, caches, new_scope, this_ptr, obj, index, *pos, op_pos, false, + false, )?; Ok((item.take_or_clone(), false)) } // xxx.id op= ??? (Expr::Property(x, pos), Some((mut new_val, op_info)), false) => { #[cfg(feature = "debugging")] - self.run_debugger(global, caches, _scope, this_ptr, rhs)?; + self.dbg(global, caches, x!(s, b), this_ptr, rhs)?; let ((getter, hash_get), (setter, hash_set), name) = &**x; @@ -899,7 +921,7 @@ impl Engine { // xxx.id (Expr::Property(x, pos), None, false) => { #[cfg(feature = "debugging")] - self.run_debugger(global, caches, _scope, this_ptr, rhs)?; + self.dbg(global, caches, x!(s, b), this_ptr, rhs)?; let ((getter, hash_get), _, name) = &**x; let args = &mut [target.as_mut()]; @@ -929,15 +951,14 @@ impl Engine { // {xxx:map}.sub_lhs[expr] | {xxx:map}.sub_lhs.expr (Expr::Index(x, ..) | Expr::Dot(x, ..), new_val, true) => { let _node = &x.lhs; - let mut _this_ptr = this_ptr; - let _tp = _this_ptr.as_deref_mut(); + let mut _tp = this_ptr.as_deref_mut(); #[cfg(not(feature = "no_closure"))] let mut target_guard; let item = &mut match x.lhs { Expr::Property(ref p, pos) => { #[cfg(feature = "debugging")] - self.run_debugger(global, caches, _scope, _tp, _node)?; + self.dbg(global, caches, x!(s, b), _tp.as_deref_mut(), _node)?; let obj = target.as_mut(); @@ -949,9 +970,12 @@ impl Engine { obj }; + let new_scope = x!(s, b); let index = &mut p.2.clone().into(); + self.get_indexed_mut( - global, caches, obj, index, pos, op_pos, false, true, + global, caches, new_scope, _tp, obj, index, pos, op_pos, false, + true, )? } // {xxx:map}.fn_name(arg_expr_list)[expr] | {xxx:map}.fn_name(arg_expr_list).expr @@ -963,8 +987,7 @@ impl Engine { ); #[cfg(feature = "debugging")] - let reset = self - .run_debugger_with_reset(global, caches, _scope, _tp, _node)?; + let reset = self.dbg_reset(global, caches, x!(s, b), _tp, _node)?; #[cfg(feature = "debugging")] defer! { global if Some(reset) => move |g| g.debugger_mut().reset_status(reset) } @@ -989,7 +1012,7 @@ impl Engine { }; self.eval_dot_index_chain_raw( - global, caches, _scope, _this_ptr, root, rhs, item, &x.rhs, idx_values, + global, caches, s, this_ptr, root, rhs, item, &x.rhs, idx_values, new_val, ) } @@ -1003,7 +1026,7 @@ impl Engine { // xxx.prop[expr] | xxx.prop.expr Expr::Property(ref p, pos) => { #[cfg(feature = "debugging")] - self.run_debugger(global, caches, _scope, _tp, _node)?; + self.dbg(global, caches, x!(s, b), _tp, _node)?; let ((getter, hash_get), (setter, hash_set), name) = &**p; let args = &mut [target.as_mut()]; @@ -1036,7 +1059,7 @@ impl Engine { let val = &mut (&mut val).into(); let (result, may_be_changed) = self.eval_dot_index_chain_raw( - global, caches, _scope, _this_ptr, root, rhs, val, &x.rhs, + global, caches, s, _this_ptr, root, rhs, val, &x.rhs, idx_values, new_val, )?; @@ -1086,9 +1109,8 @@ impl Engine { let val = { #[cfg(feature = "debugging")] - let reset = self.run_debugger_with_reset( - global, caches, _scope, _tp, _node, - )?; + let reset = + self.dbg_reset(global, caches, x!(s, b), _tp, _node)?; #[cfg(feature = "debugging")] defer! { global if Some(reset) => move |g| g.debugger_mut().reset_status(reset) } @@ -1111,7 +1133,7 @@ impl Engine { let val = &mut val.into(); self.eval_dot_index_chain_raw( - global, caches, _scope, _this_ptr, root, rhs, val, &x.rhs, + global, caches, s, _this_ptr, root, rhs, val, &x.rhs, idx_values, new_val, ) } diff --git a/src/eval/debugger.rs b/src/eval/debugger.rs index 409a3f773..ad34bbf55 100644 --- a/src/eval/debugger.rs +++ b/src/eval/debugger.rs @@ -398,7 +398,7 @@ impl Debugger { impl Engine { /// Run the debugger callback if there is a debugging interface registered. #[inline(always)] - pub(crate) fn run_debugger<'a>( + pub(crate) fn dbg<'a>( &self, global: &mut GlobalRuntimeState, caches: &mut Caches, @@ -407,9 +407,7 @@ impl Engine { node: impl Into>, ) -> RhaiResultOf<()> { if self.is_debugger_registered() { - if let Some(cmd) = - self.run_debugger_with_reset_raw(global, caches, scope, this_ptr, node)? - { + if let Some(cmd) = self.dbg_reset_raw(global, caches, scope, this_ptr, node)? { global.debugger_mut().status = cmd; } } @@ -423,7 +421,7 @@ impl Engine { /// /// It is up to the [`Engine`] to reactivate the debugger. #[inline(always)] - pub(crate) fn run_debugger_with_reset<'a>( + pub(crate) fn dbg_reset<'a>( &self, global: &mut GlobalRuntimeState, caches: &mut Caches, @@ -432,7 +430,7 @@ impl Engine { node: impl Into>, ) -> RhaiResultOf> { if self.is_debugger_registered() { - self.run_debugger_with_reset_raw(global, caches, scope, this_ptr, node) + self.dbg_reset_raw(global, caches, scope, this_ptr, node) } else { Ok(None) } @@ -444,7 +442,7 @@ impl Engine { /// /// It is up to the [`Engine`] to reactivate the debugger. #[inline] - pub(crate) fn run_debugger_with_reset_raw<'a>( + pub(crate) fn dbg_reset_raw<'a>( &self, global: &mut GlobalRuntimeState, caches: &mut Caches, @@ -479,7 +477,7 @@ impl Engine { }, }; - self.run_debugger_raw(global, caches, scope, this_ptr, node, event) + self.dbg_raw(global, caches, scope, this_ptr, node, event) } None => Ok(None), } @@ -491,7 +489,7 @@ impl Engine { /// /// It is up to the [`Engine`] to reactivate the debugger. #[inline] - pub(crate) fn run_debugger_raw( + pub(crate) fn dbg_raw( &self, global: &mut GlobalRuntimeState, caches: &mut Caches, diff --git a/src/eval/expr.rs b/src/eval/expr.rs index 515536e45..d6291b39f 100644 --- a/src/eval/expr.rs +++ b/src/eval/expr.rs @@ -227,8 +227,7 @@ impl Engine { self.track_operation(global, expr.position())?; #[cfg(feature = "debugging")] - let reset = - self.run_debugger_with_reset(global, caches, scope, this_ptr.as_deref_mut(), expr)?; + let reset = self.dbg_reset(global, caches, scope, this_ptr.as_deref_mut(), expr)?; #[cfg(feature = "debugging")] defer! { global if Some(reset) => move |g| g.debugger_mut().reset_status(reset) } diff --git a/src/eval/stmt.rs b/src/eval/stmt.rs index 496ed1a0d..874cccb58 100644 --- a/src/eval/stmt.rs +++ b/src/eval/stmt.rs @@ -266,8 +266,7 @@ impl Engine { self.track_operation(global, stmt.position())?; #[cfg(feature = "debugging")] - let reset = - self.run_debugger_with_reset(global, caches, scope, this_ptr.as_deref_mut(), stmt)?; + let reset = self.dbg_reset(global, caches, scope, this_ptr.as_deref_mut(), stmt)?; #[cfg(feature = "debugging")] defer! { global if Some(reset) => move |g| g.debugger_mut().reset_status(reset) } diff --git a/src/eval/target.rs b/src/eval/target.rs index 0317a2a2d..6bff09c33 100644 --- a/src/eval/target.rs +++ b/src/eval/target.rs @@ -85,6 +85,22 @@ pub fn calc_index( /// /// This type is typically used to hold a mutable reference to the target of an indexing or property /// access operation. +/// +/// # Example +/// +/// ``` +/// # #[cfg(feature = "internals")] { +/// # use rhai::{Dynamic, Target}; +/// // Normal `Dynamic` value +/// let mut value = Dynamic::from(42_i64); +/// let target: Target = value.into(); +/// +/// // Mutable reference to a `Dynamic` value +/// let mut value = Dynamic::from(42_i64); +/// let value_ref = &mut value; +/// let target: Target = value.into(); +/// # } +/// ``` #[derive(Debug)] #[must_use] pub enum Target<'a> { diff --git a/src/func/call.rs b/src/func/call.rs index 2f6ac5470..5a6d693c0 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -436,7 +436,7 @@ impl Engine { Err(ref err) => DebuggerEvent::FunctionExitWithError(err), }; - match self.run_debugger_raw(global, caches, scope, None, node, event) { + match self.dbg_raw(global, caches, scope, None, node, event) { Ok(..) => (), Err(err) => _result = Err(err), } @@ -699,7 +699,7 @@ impl Engine { self.track_operation(global, arg_expr.start_position())?; #[cfg(feature = "debugging")] - self.run_debugger(global, caches, scope, this_ptr, arg_expr)?; + self.dbg(global, caches, scope, this_ptr, arg_expr)?; return Ok((value, arg_expr.start_position())); } @@ -1322,14 +1322,12 @@ impl Engine { // convert to method-call style in order to leverage potential &mut first argument // and avoid cloning the value. match first_arg { - Some(_first_expr @ Expr::ThisPtr(pos)) - if curry.is_empty() && has_non_shared_this_ptr => - { + Some(_first @ Expr::ThisPtr(pos)) if curry.is_empty() && has_non_shared_this_ptr => { // Turn it into a method call only if the object is not shared self.track_operation(global, *pos)?; #[cfg(feature = "debugging")] - self.run_debugger(global, caches, scope, this_ptr.as_deref_mut(), _first_expr)?; + self.dbg(global, caches, scope, this_ptr.as_deref_mut(), _first)?; // func(x, ...) -> x.func(...) for expr in args_expr { @@ -1341,11 +1339,11 @@ impl Engine { is_ref_mut = true; args.push(this_ptr.unwrap()); } - Some(first_expr @ Expr::Variable(.., pos)) if curry.is_empty() => { + Some(first @ Expr::Variable(.., pos)) if curry.is_empty() => { self.track_operation(global, *pos)?; #[cfg(feature = "debugging")] - self.run_debugger(global, caches, scope, this_ptr.as_deref_mut(), first_expr)?; + self.dbg(global, caches, scope, this_ptr.as_deref_mut(), first)?; // func(x, ...) -> x.func(...) for expr in args_expr { @@ -1354,8 +1352,7 @@ impl Engine { arg_values.push(value.flatten()); } - let mut target = - self.search_namespace(global, caches, scope, this_ptr, first_expr)?; + let mut target = self.search_namespace(global, caches, scope, this_ptr, first)?; if target.as_ref().is_read_only() { target = target.into_owned(); @@ -1416,11 +1413,11 @@ impl Engine { // If so, convert to method-call style in order to leverage potential // &mut first argument and avoid cloning the value. match args_expr.first() { - Some(_first_expr @ Expr::ThisPtr(pos)) if has_non_shared_this_ptr => { + Some(_first @ Expr::ThisPtr(pos)) if has_non_shared_this_ptr => { self.track_operation(global, *pos)?; #[cfg(feature = "debugging")] - self.run_debugger(global, caches, scope, this_ptr.as_deref_mut(), _first_expr)?; + self.dbg(global, caches, scope, this_ptr.as_deref_mut(), _first)?; // The first value is a placeholder (for later if it needs to be cloned) arg_values.push(Dynamic::UNIT); @@ -1437,11 +1434,11 @@ impl Engine { args.push(this_ptr.unwrap()); args.extend(rest.iter_mut()); } - Some(first_expr @ Expr::Variable(.., pos)) => { + Some(first @ Expr::Variable(.., pos)) => { self.track_operation(global, *pos)?; #[cfg(feature = "debugging")] - self.run_debugger(global, caches, scope, this_ptr.as_deref_mut(), first_expr)?; + self.dbg(global, caches, scope, this_ptr.as_deref_mut(), first)?; // The first value is a placeholder (for later if it needs to be cloned) arg_values.push(Dynamic::UNIT); @@ -1452,7 +1449,7 @@ impl Engine { arg_values.push(value.flatten()); } - let target = self.search_namespace(global, caches, scope, this_ptr, first_expr)?; + let target = self.search_namespace(global, caches, scope, this_ptr, first)?; if target.is_shared() || target.is_temp_value() { arg_values[0] = target.take_or_clone().flatten(); diff --git a/src/func/native.rs b/src/func/native.rs index 068ec3cb0..365953c2d 100644 --- a/src/func/native.rs +++ b/src/func/native.rs @@ -637,14 +637,17 @@ pub type OnDebugCallback = dyn Fn(&str, Option<&str>, Position) + Send + Sync; #[cfg(not(feature = "sync"))] #[cfg(not(feature = "no_index"))] #[cfg(feature = "internals")] -pub type OnInvalidArrayIndexCallback = - dyn for<'a> Fn(&'a mut crate::Array, crate::INT) -> RhaiResultOf>; +pub type OnInvalidArrayIndexCallback = dyn for<'a> Fn( + &'a mut crate::Array, + crate::INT, + EvalContext, +) -> RhaiResultOf>; /// Callback function when a property accessed is not found in a [`Map`][crate::Map]. /// Exported under the `internals` feature only. #[cfg(feature = "sync")] #[cfg(not(feature = "no_index"))] #[cfg(feature = "internals")] -pub type OnInvalidArrayIndexCallback = dyn for<'a> Fn(&'a mut crate::Array, crate::INT) -> RhaiResultOf> +pub type OnInvalidArrayIndexCallback = dyn for<'a> Fn(&'a mut crate::Array, crate::INT, EvalContext) -> RhaiResultOf> + Send + Sync; @@ -654,14 +657,15 @@ pub type OnInvalidArrayIndexCallback = dyn for<'a> Fn(&'a mut crate::Array, crat #[cfg(not(feature = "no_object"))] #[cfg(feature = "internals")] pub type OnMissingMapPropertyCallback = - dyn for<'a> Fn(&'a mut crate::Map, &str) -> RhaiResultOf>; + dyn for<'a> Fn(&'a mut crate::Map, &str, EvalContext) -> RhaiResultOf>; /// Callback function when a property accessed is not found in a [`Map`][crate::Map]. /// Exported under the `internals` feature only. #[cfg(feature = "sync")] #[cfg(not(feature = "no_object"))] #[cfg(feature = "internals")] -pub type OnMissingMapPropertyCallback = - dyn for<'a> Fn(&'a mut crate::Map, &str) -> RhaiResultOf> + Send + Sync; +pub type OnMissingMapPropertyCallback = dyn for<'a> Fn(&'a mut crate::Map, &str, EvalContext) -> RhaiResultOf> + + Send + + Sync; /// Callback function for mapping tokens during parsing. #[cfg(not(feature = "sync"))] diff --git a/src/func/script.rs b/src/func/script.rs index fec54ab58..abb4b70e2 100644 --- a/src/func/script.rs +++ b/src/func/script.rs @@ -114,7 +114,7 @@ impl Engine { #[cfg(feature = "debugging")] if self.is_debugger_registered() { let node = crate::ast::Stmt::Noop(fn_def.body.position()); - self.run_debugger(global, caches, scope, this_ptr.as_deref_mut(), &node)?; + self.dbg(global, caches, scope, this_ptr.as_deref_mut(), &node)?; } // Evaluate the function @@ -171,7 +171,7 @@ impl Engine { Ok(ref r) => crate::eval::DebuggerEvent::FunctionExitWithValue(r), Err(ref err) => crate::eval::DebuggerEvent::FunctionExitWithError(err), }; - match self.run_debugger_raw(global, caches, scope, this_ptr, node, event) { + match self.dbg_raw(global, caches, scope, this_ptr, node, event) { Ok(_) => (), Err(err) => _result = Err(err), } diff --git a/src/packages/lang_core.rs b/src/packages/lang_core.rs index 99637c2c9..500289c00 100644 --- a/src/packages/lang_core.rs +++ b/src/packages/lang_core.rs @@ -179,7 +179,7 @@ mod core_functions { let out = serde_json::from_str(json).map_err(|err| err.to_string().into()); #[cfg(not(feature = "metadata"))] - let out = ctx + let out = _ctx .engine() .parse_json(json, true) .map(|map_object| Dynamic::from(map_object)); diff --git a/tests/arrays.rs b/tests/arrays.rs index d0c5ea05a..7b58baab6 100644 --- a/tests/arrays.rs +++ b/tests/arrays.rs @@ -506,7 +506,7 @@ fn test_arrays_elvis() { fn test_array_invalid_index_callback() { let mut engine = Engine::new(); - engine.on_invalid_array_index(|arr, index| match index { + engine.on_invalid_array_index(|arr, index, _| match index { -100 => { arr.push((42 as INT).into()); Ok(arr.last_mut().unwrap().into()) diff --git a/tests/maps.rs b/tests/maps.rs index bd6728d3e..e2391841b 100644 --- a/tests/maps.rs +++ b/tests/maps.rs @@ -261,7 +261,7 @@ fn test_map_oop() { fn test_map_missing_property_callback() { let mut engine = Engine::new(); - engine.on_map_missing_property(|map, prop| match prop { + engine.on_map_missing_property(|map, prop, _| match prop { "x" => { map.insert("y".into(), (42 as INT).into()); Ok(map.get_mut("y").unwrap().into()) diff --git a/tests/parse_json.rs b/tests/parse_json.rs index 7d1aeb97c..911c39282 100644 --- a/tests/parse_json.rs +++ b/tests/parse_json.rs @@ -1,4 +1,7 @@ -use rhai::{Engine, ParseErrorType, Scope, INT}; +use rhai::{Dynamic, Engine, EvalAltResult, LexError, ParseErrorType, Position, Scope, INT}; + +#[cfg(not(feature = "no_object"))] +use rhai::Map; #[cfg(not(feature = "metadata"))] mod without_metadata { @@ -13,7 +16,7 @@ mod without_metadata { let mut scope = Scope::new(); let map = engine - .eval_with_scope::( + .eval_with_scope::( &mut scope, r#" parse_json("{\ @@ -37,20 +40,21 @@ mod without_metadata { assert_eq!(map["age"].as_int().expect("age should exist"), 43); assert_eq!(map["phones"].clone().into_typed_array::().expect("phones should exist"), ["+44 1234567", "+44 2345678"]); - let address = map["address"].read_lock::().expect("address should exist"); + let address = map["address"].read_lock::().expect("address should exist"); assert_eq!(address["city"].clone().into_immutable_string().expect("address.city should exist"), "London"); assert_eq!(address["street"].clone().into_immutable_string().expect("address.street should exist"), "10 Downing Street"); } #[test] #[cfg(feature = "no_index")] + #[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_function"))] fn test_parse_json_err_no_index() { let engine = Engine::new(); let mut scope = Scope::new(); let err = engine - .eval_with_scope::( + .eval_with_scope::( &mut scope, r#" parse_json("{\ @@ -63,9 +67,9 @@ mod without_metadata { ) .unwrap_err(); - assert!(matches!(err.as_ref(), rhai::EvalAltResult::ErrorParsing( + assert!(matches!(err.as_ref(), EvalAltResult::ErrorParsing( ParseErrorType::BadInput(LexError::UnexpectedInput(token)), pos) - if token == "[" && *pos == rhai::Position::new(1, 7))); + if token == "[" && *pos == Position::new(1, 7))); } #[test] @@ -76,7 +80,7 @@ mod without_metadata { let mut scope = Scope::new(); let err = engine - .eval_with_scope::( + .eval_with_scope::( &mut scope, r#" parse_json("{\ @@ -89,8 +93,8 @@ mod without_metadata { ) .unwrap_err(); - assert!(matches!(err.as_ref(), rhai::EvalAltResult::ErrorFunctionNotFound(msg, pos) - if msg == "parse_json (&str | ImmutableString | String)" && *pos == rhai::Position::new(2, 13))); + assert!(matches!(err.as_ref(), EvalAltResult::ErrorFunctionNotFound(msg, pos) + if msg == "parse_json (&str | ImmutableString | String)" && *pos == Position::new(2, 13))); } } @@ -107,7 +111,7 @@ mod with_metadata { let mut scope = Scope::new(); let map = engine - .eval_with_scope::( + .eval_with_scope::( &mut scope, r#" parse_json("{\ @@ -131,20 +135,21 @@ mod with_metadata { assert_eq!(map["age"].as_int().expect("age should exist"), 43); assert_eq!(map["phones"].clone().into_typed_array::().expect("phones should exist"), ["+44 1234567", "+44 2345678"]); - let address = map["address"].read_lock::().expect("address should exist"); + let address = map["address"].read_lock::().expect("address should exist"); assert_eq!(address["city"].clone().into_immutable_string().expect("address.city should exist"), "London"); assert_eq!(address["street"].clone().into_immutable_string().expect("address.street should exist"), "10 Downing Street"); } #[test] #[cfg(feature = "no_index")] + #[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_function"))] fn test_parse_json_err_no_index() { let engine = Engine::new(); let mut scope = Scope::new(); let err = engine - .eval_with_scope::( + .eval_with_scope::( &mut scope, r#" parse_json("{\ @@ -157,9 +162,8 @@ mod with_metadata { ) .unwrap_err(); - assert!(matches!(err.as_ref(), rhai::EvalAltResult::ErrorParsing( - ParseErrorType::BadInput(LexError::UnexpectedInput(token)), pos) - if token == "[" && *pos == rhai::Position::new(1, 7))); + assert!(matches!(err.as_ref(), EvalAltResult::ErrorRuntime(msg, pos) + if msg.is_string() && *pos == Position::new(2, 17))); } #[test] @@ -170,7 +174,7 @@ mod with_metadata { let mut scope = Scope::new(); let err = engine - .eval_with_scope::( + .eval_with_scope::( &mut scope, r#" parse_json("{\ @@ -183,7 +187,7 @@ mod with_metadata { ) .unwrap_err(); - assert!(matches!(err.as_ref(), rhai::EvalAltResult::ErrorFunctionNotFound(msg, pos) - if msg == "parse_json (&str | ImmutableString | String)" && *pos == rhai::Position::new(2, 13))); + assert!(matches!(err.as_ref(), EvalAltResult::ErrorFunctionNotFound(msg, pos) + if msg == "parse_json (&str | ImmutableString | String)" && *pos == Position::new(2, 17))); } }