diff --git a/docs/scarpet/language/FunctionsAndControlFlow.md b/docs/scarpet/language/FunctionsAndControlFlow.md index 73d5d1fc..a02c2d51 100644 --- a/docs/scarpet/language/FunctionsAndControlFlow.md +++ b/docs/scarpet/language/FunctionsAndControlFlow.md @@ -295,10 +295,12 @@ Producing: {stack: [[, inner_call, 1, 14]], locals: {_a: 0, aaa: booyah, _: 1, _y: 0, _i: 1, _x: 0, _z: 0}, token: [item_tags, 5, 23]} ``` -### `throw(value?)` `throw(type, value)` +### `throw(value?)`, `throw(type, value)`, `throw(subtype, type, value)` -Throws an exception that can be caught in a `try` block (see above). If ran without arguments, it will throw `user_exception` +Throws an exception that can be caught in a `try` block (see above). If ran without arguments, it will throw a `user_exception` passing `null` as the value to the `catch_expr`. With two arguments you can mimic any other exception type thrown in scarpet. +With 3 arguments, you can specify a custom exception acting as a `subtype` of a provided `type`, allowing to customize `try` +statements with custom exceptions. ### `if(cond, expr, cond?, expr?, ..., default?)` diff --git a/docs/scarpet/resources/editors/idea/3.txt b/docs/scarpet/resources/editors/idea/3.txt index 333d6259..fc9e16f0 100644 --- a/docs/scarpet/resources/editors/idea/3.txt +++ b/docs/scarpet/resources/editors/idea/3.txt @@ -4,6 +4,7 @@ _i _x _y _z +_trace euler false null diff --git a/docs/scarpet/resources/editors/npp/scarpet.xml b/docs/scarpet/resources/editors/npp/scarpet.xml index 5ae29a0f..b44bb643 100644 --- a/docs/scarpet/resources/editors/npp/scarpet.xml +++ b/docs/scarpet/resources/editors/npp/scarpet.xml @@ -91,7 +91,7 @@ euler pi null true false x y z p - _ _i _a _x _y _z + _ _i _a _x _y _z _trace global_ __command diff --git a/src/main/java/carpet/script/exception/ThrowStatement.java b/src/main/java/carpet/script/exception/ThrowStatement.java index f667fdbc..c61470cb 100644 --- a/src/main/java/carpet/script/exception/ThrowStatement.java +++ b/src/main/java/carpet/script/exception/ThrowStatement.java @@ -24,6 +24,13 @@ public class ThrowStatement extends InternalExpressionException this.type = type; } + public ThrowStatement(Value data, Throwables parent, String subtype) + { + super(subtype); + this.data = data; + this.type = new Throwables(subtype, parent); + } + /** * Creates a throw exception.
* Conveniently creates a value from the {@code value} String diff --git a/src/main/java/carpet/script/exception/Throwables.java b/src/main/java/carpet/script/exception/Throwables.java index 40f45b17..22857a41 100644 --- a/src/main/java/carpet/script/exception/Throwables.java +++ b/src/main/java/carpet/script/exception/Throwables.java @@ -1,9 +1,7 @@ package carpet.script.exception; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; -import java.util.Set; /** * This class contains default Scarpet catchable types, as well as their inheritance and @@ -14,7 +12,6 @@ public class Throwables { private final Throwables parent; private static final Map byId = new HashMap<>(); - private static final Map> handles = new HashMap<>(); public static final Throwables THROWN_EXCEPTION_TYPE = register("exception", null); public static final Throwables VALUE_EXCEPTION = register("value_exception", THROWN_EXCEPTION_TYPE); @@ -44,14 +41,6 @@ public class Throwables { { Throwables exc = new Throwables(id, parent); byId.put(id, exc); - Set itHandles = new HashSet<>(); - itHandles.add(exc); - while (parent!=null) - { - handles.get(parent.id).add(exc); - parent = parent.parent; - } - handles.put(id, itHandles); return exc; } @@ -61,7 +50,7 @@ public class Throwables { * Use an {@link InternalExpressionException} for that * @param id The exception's value as a {@link String} */ - protected Throwables(String id, Throwables parent) + public Throwables(String id, Throwables parent) { this.id = id; this.parent = parent; @@ -74,7 +63,6 @@ public class Throwables { return properType; } - /** * Checks whether the given filter matches an instance of this exception, by checking equality * with itself and possible parents. @@ -83,9 +71,12 @@ public class Throwables { */ public boolean isRelevantFor(String filter) { - Set relevantSet = handles.get(filter); - if (relevantSet == null) throw new InternalExpressionException("Unknown exception type: "+filter); - return relevantSet.contains(this); + return (id.equals(filter) || (parent != null && parent.isRelevantFor(filter))); + } + + public boolean isUserException() + { + return this == USER_DEFINED || parent == USER_DEFINED; } /** diff --git a/src/main/java/carpet/script/language/ControlFlow.java b/src/main/java/carpet/script/language/ControlFlow.java index 7972d582..e094309e 100644 --- a/src/main/java/carpet/script/language/ControlFlow.java +++ b/src/main/java/carpet/script/language/ControlFlow.java @@ -61,8 +61,10 @@ public class ControlFlow { throw new ThrowStatement(lv.get(0).evalValue(c), Throwables.USER_DEFINED ); case 2: throw new ThrowStatement(lv.get(1).evalValue(c), Throwables.getTypeForException(lv.get(0).evalValue(c).getString())); + case 3: + throw new ThrowStatement(lv.get(2).evalValue(c), Throwables.getTypeForException(lv.get(1).evalValue(c).getString()), lv.get(0).evalValue(c).getString()); default: - throw new InternalExpressionException("throw() can't accept more than 2 parameters"); + throw new InternalExpressionException("throw() can't accept more than 3 parameters"); } }); @@ -79,7 +81,7 @@ public class ControlFlow { { if (lv.size() == 1) { - if (ret.thrownExceptionType != Throwables.USER_DEFINED) + if (!ret.thrownExceptionType.isUserException()) throw ret; return (c_, t_) -> Value.NULL; } @@ -101,7 +103,7 @@ public class ControlFlow { NumericValue.of(f.getToken().linepos+1) )).collect(Collectors.toList())), - StringValue.of("locals"), MapValue.wrap(ret.context.variables.entrySet().stream().collect(Collectors.toMap( + StringValue.of("locals"), MapValue.wrap(ret.context.variables.entrySet().stream().filter(e -> !e.getKey().equals("_trace")).collect(Collectors.toMap( e -> StringValue.of(e.getKey()), e -> e.getValue().evalValue(ret.context) ))), @@ -114,7 +116,7 @@ public class ControlFlow { if (lv.size() == 2) { - if (ret.thrownExceptionType == Throwables.USER_DEFINED) + if (ret.thrownExceptionType.isUserException()) val = lv.get(1).evalValue(c, t); } else