diff --git a/docs/scarpet/language/FunctionsAndControlFlow.md b/docs/scarpet/language/FunctionsAndControlFlow.md index 28a03fb0..8b4d50a3 100644 --- a/docs/scarpet/language/FunctionsAndControlFlow.md +++ b/docs/scarpet/language/FunctionsAndControlFlow.md @@ -234,13 +234,17 @@ returns everywhere, but it would often lead to a messy code. It terminates entire program passing `expr` as the result of the program execution, or null if omitted. -### `try(expr, id_filter?, catch_expr(_, _msg)?)` +### `try(expr, id_filter?, catch_expr(_, _msg)?, id_filter2?, catch_expr2(_, _msg), ...)` `try` function evaluates expression, and continues further unless an exception is thrown anywhere inside `expr`, it being produced by `throw` or a catchable exception being thrown by Carpet. In that case the `catch_expr` is evaluated with `_` set to the id of the exception and `_msg` set to the exception message. If an `id_filter` is present, only exceptions -with an id equal to that value will be caught, and any other exception will continue up the stack. It is recommended to filter -the exceptions to catch to be able to distinguish from an exception that is known that may happen from one that shouldn't. +with an id equal to that value will be caught, and any other exception will continue up the stack. You can specify multiple filters +and their respective `catch_expr` to be able to catch different exceptions within the same code. When an exception occurs, the script +will try to find an equality with every provided filter in order. Therefore, even if the caught exception matches multiple filters, only +the first matching block will be executed. It is recommended to filter the exceptions to catch to be able to distinguish from an exception +that is known that may happen from one that shouldn't. + This mechanic accepts skipping catch expression - then try returns `null`. This mechanism allows to terminate large portion of a convoluted call stack and continue program execution. diff --git a/src/main/java/carpet/script/language/ControlFlow.java b/src/main/java/carpet/script/language/ControlFlow.java index 076a29eb..cbf5bebd 100644 --- a/src/main/java/carpet/script/language/ControlFlow.java +++ b/src/main/java/carpet/script/language/ControlFlow.java @@ -76,20 +76,34 @@ public class ControlFlow { throw ret; if (lv.size() == 1) return (c_, t_) -> Value.NULL; + // This is outside since it is also used in try(expr,catch_expr). LazyValue __ = c.getVariable("_"); c.setVariable("_", (__c, __t) -> ret.exception.getValue().reboundedTo("_")); LazyValue __msg = c.getVariable("_msg"); c.setVariable("_msg", (__c, __t) -> StringValue.of(ret.message).reboundedTo("_msg")); - Value val; - if (lv.size() == 3) + Value val = null; // This is always assigned, just the compiler doesn't know + if (lv.size() >= 3) { - if (!ret.exception.isInstance(lv.get(1).evalValue(c))) + if (lv.size() % 2 == 0) + throw new InternalExpressionException("Multi-catch block needs a catch expression for every filter"); + int pointer = 1; + boolean handled = false; + while (pointer < lv.size() -1) { - c.setVariable("_", __); + if (ret.exception.isInstance(lv.get(pointer).evalValue(c))) + { + val = lv.get(pointer + 1).evalValue(c, t); + handled = true; + break; + } + pointer += 2; + } + if (!handled) + { + c.setVariable("_", __); c.setVariable("_msg", __msg); throw ret; } - val = lv.get(2).evalValue(c, t); } else { @@ -97,7 +111,8 @@ public class ControlFlow { } c.setVariable("_",__); c.setVariable("_msg", __msg); - return (c_, t_) -> val; + Value retval = val; + return (c_, t_) -> retval; } }); }