From a51f741546690ec1e574bcd46f738559a7e01336 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 16 Sep 2022 18:11:28 +0800 Subject: [PATCH] Restore global state upon errors. --- src/api/call_fn.rs | 62 +++++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/src/api/call_fn.rs b/src/api/call_fn.rs index 611ede44..ac1fb7f3 100644 --- a/src/api/call_fn.rs +++ b/src/api/call_fn.rs @@ -195,13 +195,14 @@ impl Engine { /// /// A [`GlobalRuntimeState`] and [`Caches`] need to be passed into the function, which can be /// created via [`GlobalRuntimeState::new`] and [`Caches::new`]. - /// This makes repeatedly calling particular functions more efficient as the functions resolution cache - /// is kept intact. + /// + /// This makes repeatedly calling particular functions more efficient as the functions + /// resolution cache is kept intact. /// /// # Arguments /// - /// All the arguments are _consumed_, meaning that they're replaced by `()`. - /// This is to avoid unnecessarily cloning the arguments. + /// All the arguments are _consumed_, meaning that they're replaced by `()`. This is to avoid + /// unnecessarily cloning the arguments. /// /// Do not use the arguments after this call. If they are needed afterwards, clone them _before_ /// calling this function. @@ -246,6 +247,8 @@ impl Engine { arg_values: &mut [Dynamic], ) -> RhaiResult { let statements = ast.statements(); + let lib = &[ast.as_ref()]; + let mut this_ptr = this_ptr; let orig_scope_len = scope.len(); @@ -255,45 +258,48 @@ impl Engine { ast.resolver().cloned(), ); + let mut result = Ok(Dynamic::UNIT); + if eval_ast && !statements.is_empty() { - self.eval_global_statements(scope, global, caches, statements, &[ast.as_ref()], 0)?; + result = self.eval_global_statements(scope, global, caches, statements, lib, 0); if rewind_scope { scope.rewind(orig_scope_len); } } - let mut this_ptr = this_ptr; - let mut args: StaticVec<_> = arg_values.iter_mut().collect(); + result = result.and_then(|_| { + let mut args: StaticVec<_> = arg_values.iter_mut().collect(); - // Check for data race. - #[cfg(not(feature = "no_closure"))] - crate::func::call::ensure_no_data_race(name, &args, false)?; + // Check for data race. + #[cfg(not(feature = "no_closure"))] + crate::func::call::ensure_no_data_race(name, &args, false).map(|_| Dynamic::UNIT)?; - let lib = &[ast.as_ref()]; - let fn_def = ast - .shared_lib() - .get_script_fn(name, args.len()) - .ok_or_else(|| ERR::ErrorFunctionNotFound(name.into(), Position::NONE))?; - - let result = self.call_script_fn( - scope, - global, - caches, - lib, - &mut this_ptr, - fn_def, - &mut args, - rewind_scope, - Position::NONE, - 0, - )?; + if let Some(fn_def) = ast.shared_lib().get_script_fn(name, args.len()) { + self.call_script_fn( + scope, + global, + caches, + lib, + &mut this_ptr, + fn_def, + &mut args, + rewind_scope, + Position::NONE, + 0, + ) + } else { + Err(ERR::ErrorFunctionNotFound(name.into(), Position::NONE).into()) + } + }); #[cfg(not(feature = "no_module"))] { global.embedded_module_resolver = orig_embedded_module_resolver; } + let result = result?; + #[cfg(feature = "debugging")] if self.debugger.is_some() { global.debugger.status = crate::eval::DebuggerStatus::Terminate;