From 427af14f1b7b62737a8500ced512f226f8ee7f61 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Wed, 28 Oct 2020 14:10:46 +0800 Subject: [PATCH] Don't wrap system errors from function calls. --- src/engine.rs | 2 +- src/fn_call.rs | 3 +++ src/result.rs | 29 ++++++++++++++++++++++++----- tests/operations.rs | 2 +- tests/stack.rs | 11 +++++++---- 5 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/engine.rs b/src/engine.rs index 3563d22e..2bc062f4 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1939,7 +1939,7 @@ impl Engine { Ok(_) => result, Err(err) => match *err { mut err @ EvalAltResult::ErrorRuntime(_, _) | mut err - if err.catchable() => + if err.is_catchable() => { let value = if let EvalAltResult::ErrorRuntime(ref x, _) = err { x.clone() diff --git a/src/fn_call.rs b/src/fn_call.rs index eb3493ad..efd563b6 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -409,6 +409,9 @@ impl Engine { ) .into() } + // System errors are passed straight-through + err if err.is_system_exception() => Err(Box::new(err)), + // Other errors are wrapped in `ErrorInFunctionCall` _ => EvalAltResult::ErrorInFunctionCall( fn_def.name.to_string(), err, diff --git a/src/result.rs b/src/result.rs index fce42842..cb43cff3 100644 --- a/src/result.rs +++ b/src/result.rs @@ -270,10 +270,10 @@ impl> From for Box { impl EvalAltResult { /// Can this error be caught? - pub fn catchable(&self) -> bool { + pub fn is_catchable(&self) -> bool { match self { Self::ErrorSystem(_, _) => false, - Self::ErrorParsing(_, _) => false, + Self::ErrorParsing(_, _) => unreachable!(), Self::ErrorFunctionNotFound(_, _) | Self::ErrorInFunctionCall(_, _, _) @@ -298,9 +298,28 @@ impl EvalAltResult { | Self::ErrorTooManyModules(_) | Self::ErrorStackOverflow(_) | Self::ErrorDataTooLarge(_, _, _, _) - | Self::ErrorTerminated(_) - | Self::LoopBreak(_, _) - | Self::Return(_, _) => false, + | Self::ErrorTerminated(_) => false, + + Self::LoopBreak(_, _) | Self::Return(_, _) => unreachable!(), + } + } + + /// Is this error a system exception? + pub fn is_system_exception(&self) -> bool { + match self { + Self::ErrorSystem(_, _) => true, + Self::ErrorParsing(_, _) => unreachable!(), + + Self::ErrorTooManyOperations(_) + | Self::ErrorTooManyModules(_) + | Self::ErrorStackOverflow(_) + | Self::ErrorDataTooLarge(_, _, _, _) => true, + + Self::ErrorTerminated(_) => true, + + Self::LoopBreak(_, _) | Self::Return(_, _) => unreachable!(), + + _ => false, } } diff --git a/tests/operations.rs b/tests/operations.rs index 9ccef6b6..dae539f0 100644 --- a/tests/operations.rs +++ b/tests/operations.rs @@ -72,7 +72,7 @@ fn test_max_operations_functions() -> Result<(), Box> { fn inc(x) { x + 1 } let x = 0; - while x < 30 { + while x < 28 { print(x); x = inc(x); } diff --git a/tests/stack.rs b/tests/stack.rs index b161e192..3319a55c 100644 --- a/tests/stack.rs +++ b/tests/stack.rs @@ -18,12 +18,15 @@ fn test_stack_overflow_fn_calls() -> Result<(), Box> { #[cfg(not(feature = "unchecked"))] assert!(matches!( - *engine.eval::<()>( - r" + *engine + .eval::<()>( + r" fn foo(n) { if n == 0 { 0 } else { n + foo(n-1) } } foo(1000) - ").expect_err("should error"), - EvalAltResult::ErrorInFunctionCall(name, _, _) if name.starts_with("foo > foo > foo") + " + ) + .expect_err("should error"), + EvalAltResult::ErrorStackOverflow(_) )); Ok(())