Add multi-catch to try block

This commit is contained in:
altrisi committed 2021-02-21 01:52:55 +01:00
1 parent 86dabe0080
commit 0b86ac1a87
2 files changed
+28 -9

No files matched your search

@@ -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.
@@ -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;
}
});
}