Restore global state upon errors.

This commit is contained in:
Stephen Chung 2022-09-16 18:11:28 +08:00
parent 93f43790af
commit a51f741546

View File

@ -195,13 +195,14 @@ impl Engine {
/// ///
/// A [`GlobalRuntimeState`] and [`Caches`] need to be passed into the function, which can be /// A [`GlobalRuntimeState`] and [`Caches`] need to be passed into the function, which can be
/// created via [`GlobalRuntimeState::new`] and [`Caches::new`]. /// 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 /// # Arguments
/// ///
/// All the arguments are _consumed_, meaning that they're replaced by `()`. /// All the arguments are _consumed_, meaning that they're replaced by `()`. This is to avoid
/// This is to avoid unnecessarily cloning the arguments. /// unnecessarily cloning the arguments.
/// ///
/// Do not use the arguments after this call. If they are needed afterwards, clone them _before_ /// Do not use the arguments after this call. If they are needed afterwards, clone them _before_
/// calling this function. /// calling this function.
@ -246,6 +247,8 @@ impl Engine {
arg_values: &mut [Dynamic], arg_values: &mut [Dynamic],
) -> RhaiResult { ) -> RhaiResult {
let statements = ast.statements(); let statements = ast.statements();
let lib = &[ast.as_ref()];
let mut this_ptr = this_ptr;
let orig_scope_len = scope.len(); let orig_scope_len = scope.len();
@ -255,28 +258,25 @@ impl Engine {
ast.resolver().cloned(), ast.resolver().cloned(),
); );
let mut result = Ok(Dynamic::UNIT);
if eval_ast && !statements.is_empty() { 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 { if rewind_scope {
scope.rewind(orig_scope_len); scope.rewind(orig_scope_len);
} }
} }
let mut this_ptr = this_ptr; result = result.and_then(|_| {
let mut args: StaticVec<_> = arg_values.iter_mut().collect(); let mut args: StaticVec<_> = arg_values.iter_mut().collect();
// Check for data race. // Check for data race.
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
crate::func::call::ensure_no_data_race(name, &args, false)?; crate::func::call::ensure_no_data_race(name, &args, false).map(|_| Dynamic::UNIT)?;
let lib = &[ast.as_ref()]; if let Some(fn_def) = ast.shared_lib().get_script_fn(name, args.len()) {
let fn_def = ast self.call_script_fn(
.shared_lib()
.get_script_fn(name, args.len())
.ok_or_else(|| ERR::ErrorFunctionNotFound(name.into(), Position::NONE))?;
let result = self.call_script_fn(
scope, scope,
global, global,
caches, caches,
@ -287,13 +287,19 @@ impl Engine {
rewind_scope, rewind_scope,
Position::NONE, Position::NONE,
0, 0,
)?; )
} else {
Err(ERR::ErrorFunctionNotFound(name.into(), Position::NONE).into())
}
});
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
{ {
global.embedded_module_resolver = orig_embedded_module_resolver; global.embedded_module_resolver = orig_embedded_module_resolver;
} }
let result = result?;
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
if self.debugger.is_some() { if self.debugger.is_some() {
global.debugger.status = crate::eval::DebuggerStatus::Terminate; global.debugger.status = crate::eval::DebuggerStatus::Terminate;