Don't wrap system errors from function calls.

This commit is contained in:
Stephen Chung 2020-10-28 14:10:46 +08:00
parent 30e11f137b
commit 427af14f1b
5 changed files with 36 additions and 11 deletions

View File

@ -1939,7 +1939,7 @@ impl Engine {
Ok(_) => result, Ok(_) => result,
Err(err) => match *err { Err(err) => match *err {
mut err @ EvalAltResult::ErrorRuntime(_, _) | mut err mut err @ EvalAltResult::ErrorRuntime(_, _) | mut err
if err.catchable() => if err.is_catchable() =>
{ {
let value = if let EvalAltResult::ErrorRuntime(ref x, _) = err { let value = if let EvalAltResult::ErrorRuntime(ref x, _) = err {
x.clone() x.clone()

View File

@ -409,6 +409,9 @@ impl Engine {
) )
.into() .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( _ => EvalAltResult::ErrorInFunctionCall(
fn_def.name.to_string(), fn_def.name.to_string(),
err, err,

View File

@ -270,10 +270,10 @@ impl<T: AsRef<str>> From<T> for Box<EvalAltResult> {
impl EvalAltResult { impl EvalAltResult {
/// Can this error be caught? /// Can this error be caught?
pub fn catchable(&self) -> bool { pub fn is_catchable(&self) -> bool {
match self { match self {
Self::ErrorSystem(_, _) => false, Self::ErrorSystem(_, _) => false,
Self::ErrorParsing(_, _) => false, Self::ErrorParsing(_, _) => unreachable!(),
Self::ErrorFunctionNotFound(_, _) Self::ErrorFunctionNotFound(_, _)
| Self::ErrorInFunctionCall(_, _, _) | Self::ErrorInFunctionCall(_, _, _)
@ -298,9 +298,28 @@ impl EvalAltResult {
| Self::ErrorTooManyModules(_) | Self::ErrorTooManyModules(_)
| Self::ErrorStackOverflow(_) | Self::ErrorStackOverflow(_)
| Self::ErrorDataTooLarge(_, _, _, _) | Self::ErrorDataTooLarge(_, _, _, _)
| Self::ErrorTerminated(_) | Self::ErrorTerminated(_) => false,
| Self::LoopBreak(_, _)
| Self::Return(_, _) => 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,
} }
} }

View File

@ -72,7 +72,7 @@ fn test_max_operations_functions() -> Result<(), Box<EvalAltResult>> {
fn inc(x) { x + 1 } fn inc(x) { x + 1 }
let x = 0; let x = 0;
while x < 30 { while x < 28 {
print(x); print(x);
x = inc(x); x = inc(x);
} }

View File

@ -18,12 +18,15 @@ fn test_stack_overflow_fn_calls() -> Result<(), Box<EvalAltResult>> {
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
assert!(matches!( assert!(matches!(
*engine.eval::<()>( *engine
.eval::<()>(
r" r"
fn foo(n) { if n == 0 { 0 } else { n + foo(n-1) } } fn foo(n) { if n == 0 { 0 } else { n + foo(n-1) } }
foo(1000) foo(1000)
").expect_err("should error"), "
EvalAltResult::ErrorInFunctionCall(name, _, _) if name.starts_with("foo > foo > foo") )
.expect_err("should error"),
EvalAltResult::ErrorStackOverflow(_)
)); ));
Ok(()) Ok(())