Allow some exceptions to be handled

This commit is contained in:
altrisi committed 2021-02-19 19:54:41 +01:00
1 parent 7029c6b9b9
commit a155494d11
20 files changed
+283 -78

No files matched your search

+3 -4
View File
@@ -19,7 +19,6 @@ import carpet.script.exception.ExpressionException;
import carpet.script.exception.InternalExpressionException;
import carpet.script.exception.ResolvedException;
import carpet.script.exception.ReturnStatement;
import carpet.script.exception.ThrowStatement;
import carpet.script.language.Arithmetic;
import carpet.script.language.ControlFlow;
import carpet.script.language.DataStructures;
@@ -232,7 +231,7 @@ public class Expression
if (exc instanceof ExitStatement)
return exc;
if (exc instanceof InternalExpressionException)
return new ExpressionException(c, e, token, exc.getMessage(), ((InternalExpressionException) exc).stack);
return ((InternalExpressionException) exc).promote(c, e, token);
if (exc instanceof ArithmeticException)
return new ExpressionException(c, e, token, "Your math is wrong, "+exc.getMessage());
if (exc instanceof ResolvedException)
@@ -624,9 +623,9 @@ public class Expression
{
return exprProvider.get().evalValue(c, expectedType);
}
catch (ContinueStatement | BreakStatement | ReturnStatement | ThrowStatement exc)
catch (ContinueStatement | BreakStatement | ReturnStatement exc)
{
throw new ExpressionException(c, this, "Control flow functions, like continue, break, throw or return, should only be used in loops, try blocks, and functions respectively.");
throw new ExpressionException(c, this, "Control flow functions, like continue, break or return, should only be used in loops, and functions respectively.");
}
catch (ExitStatement exit)
{
+23 -6
View File
@@ -19,6 +19,7 @@ import carpet.script.argument.FunctionArgument;
import carpet.script.argument.Vector3Argument;
import carpet.script.exception.ExitStatement;
import carpet.script.exception.InternalExpressionException;
import carpet.script.exception.ThrowStatement;
import carpet.script.utils.FixedCommandSource;
import carpet.script.utils.ScarpetJsonDeserializer;
import carpet.script.utils.ShapeDispatcher;
@@ -62,6 +63,7 @@ import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import net.minecraft.util.InvalidIdentifierException;
import net.minecraft.util.crash.CrashException;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.EulerAngle;
@@ -130,7 +132,7 @@ public class Auxiliary {
Identifier soundName = new Identifier(lv.get(0).evalValue(c).getString());
Vector3Argument locator = Vector3Argument.findIn(cc, lv, 1);
if (Registry.SOUND_EVENT.get(soundName) == null)
throw new InternalExpressionException("No such sound: "+soundName.getPath());
throw new ThrowStatement("No such sound: "+soundName.getPath(), ThrowStatement.UNKNOWN_SOUND);
float volume = 1.0F;
float pitch = 1.0F;
SoundCategory mixer = SoundCategory.MASTER;
@@ -820,7 +822,15 @@ public class Auxiliary {
Value retVal;
if (fdesc.getMiddle().equals("nbt"))
{
Tag state = ((CarpetScriptHost) c.host).readFileTag(fdesc.getLeft(), fdesc.getRight());
Tag state;
try
{
state = ((CarpetScriptHost) c.host).readFileTag(fdesc.getLeft(), fdesc.getRight());
} catch (CrashException e)
{
throw new ThrowStatement("Couldn't read NBT data", ThrowStatement.NBT_READ_EXCEPTION);
}
if (state == null) return LazyValue.NULL;
retVal = new NBTSerializableValue(state);
}
@@ -833,10 +843,10 @@ public class Auxiliary {
}
catch (JsonParseException e)
{
Throwable exception = e;
Throwable exc = e;
if(e.getCause() != null)
exception = e.getCause();
throw new InternalExpressionException("Failed to read JSON file: "+exception.getMessage());
exc = e.getCause();
throw new ThrowStatement("Failed to read JSON file: "+exc.getMessage(), ThrowStatement.JSON_READ_EXCEPTION);
}
Value parsedJson = gson.fromJson(json, Value.class);
if (parsedJson == null)
@@ -924,7 +934,14 @@ public class Auxiliary {
shared = lv.get(1).evalValue(c).getBoolean();
}
}
Tag state = ((CarpetScriptHost)((CarpetContext)c).host).readFileTag(file, shared);
Tag state;
try
{
state = ((CarpetScriptHost)((CarpetContext)c).host).readFileTag(file, shared);
} catch (CrashException e)
{
throw new ThrowStatement("Failed to read App data", ThrowStatement.NBT_READ_EXCEPTION);
}
if (state == null)
return (cc, tt) -> Value.NULL;
Value retVal = new NBTSerializableValue(state);
@@ -6,6 +6,7 @@ import carpet.script.CarpetContext;
import carpet.script.Expression;
import carpet.script.LazyValue;
import carpet.script.exception.InternalExpressionException;
import carpet.script.exception.ThrowStatement;
import carpet.script.value.ListValue;
import carpet.script.value.NBTSerializableValue;
import carpet.script.value.NullValue;
@@ -119,14 +120,7 @@ public class Inventories {
}
}
List<Recipe<?>> recipes;
try
{
recipes = ((RecipeManagerInterface) cc.s.getMinecraftServer().getRecipeManager()).getAllMatching(type, new Identifier(recipeName));
}
catch (InvalidIdentifierException ignored)
{
return LazyValue.NULL;
}
recipes = ((RecipeManagerInterface) cc.s.getMinecraftServer().getRecipeManager()).getAllMatching(type, new Identifier(recipeName));
if (recipes.isEmpty())
return LazyValue.NULL;
List<Value> recipesOutput = new ArrayList<>();
@@ -197,17 +191,9 @@ public class Inventories {
{
String itemStr = lv.get(0).evalValue(c).getString();
Item item;
try
{
Identifier id = new Identifier(itemStr);
item = Registry.ITEM.get(id);
if (item == Items.AIR && !id.getPath().equalsIgnoreCase("air"))
throw new InvalidIdentifierException("boo");
}
catch (InvalidIdentifierException ignored)
{
throw new InternalExpressionException("Incorrect item: "+itemStr);
}
Identifier id = new Identifier(itemStr);
item = Registry.ITEM.getOrEmpty(id).orElseThrow(() -> new ThrowStatement("Incorrect item: "+itemStr, ThrowStatement.UNKNOWN_ITEM));
if (!item.hasRecipeRemainder()) return LazyValue.NULL;
Value ret = new StringValue(NBTSerializableValue.nameFromRegistryId(Registry.ITEM.getId(item.getRecipeRemainder())));
return (_c, _t ) -> ret;
@@ -6,6 +6,7 @@ import carpet.script.CarpetContext;
import carpet.script.Expression;
import carpet.script.LazyValue;
import carpet.script.exception.InternalExpressionException;
import carpet.script.exception.ThrowStatement;
import carpet.script.value.EntityValue;
import carpet.script.value.ListValue;
import carpet.script.value.NullValue;
@@ -131,7 +132,7 @@ public class Scoreboards {
criterion = ScoreboardCriterion.createStatCriterion(critetionName).orElse(null);
if (criterion==null)
{
throw new InternalExpressionException("Unknown scoreboard criterion: "+critetionName);
throw new ThrowStatement("Unknown scoreboard criterion: "+critetionName, ThrowStatement.UNKNOWN_CRITERION);
}
}
@@ -19,6 +19,7 @@ import carpet.script.LazyValue;
import carpet.script.argument.BlockArgument;
import carpet.script.argument.Vector3Argument;
import carpet.script.exception.InternalExpressionException;
import carpet.script.exception.ThrowStatement;
import carpet.script.utils.BiomeInfo;
import carpet.script.utils.WorldTools;
import carpet.script.value.BlockValue;
@@ -336,8 +337,8 @@ public class WorldAccess {
String poiType = lv.get(locator.offset+1).evalValue(c).getString().toLowerCase(Locale.ROOT);
if (!"any".equals(poiType))
{
PointOfInterestType type = Registry.POINT_OF_INTEREST_TYPE.get(new Identifier(poiType));
if (type == PointOfInterestType.UNEMPLOYED && !"unemployed".equals(poiType)) return LazyValue.NULL;
PointOfInterestType type = Registry.POINT_OF_INTEREST_TYPE.getOrEmpty(new Identifier(poiType))
.orElseThrow(() -> new ThrowStatement("Unknown POI type", ThrowStatement.UNKNOWN_POI_TYPE));
condition = (tt) -> tt == type;
}
if (locator.offset + 2 < lv.size())
@@ -391,9 +392,8 @@ public class WorldAccess {
return LazyValue.FALSE;
}
String poiTypeString = poi.getString().toLowerCase(Locale.ROOT);
PointOfInterestType type = Registry.POINT_OF_INTEREST_TYPE.get(new Identifier(poiTypeString));
// solving lack of null with defaulted registries
if (type == PointOfInterestType.UNEMPLOYED && !"unemployed".equals(poiTypeString)) throw new InternalExpressionException("Unknown POI type: "+poiTypeString);
PointOfInterestType type = Registry.POINT_OF_INTEREST_TYPE.getOrEmpty(new Identifier(poiTypeString))
.orElseThrow(() -> new ThrowStatement("Unknown POI type: "+poiTypeString, ThrowStatement.UNKNOWN_POI_TYPE));
int occupancy = 0;
if (locator.offset + 1 < lv.size())
{
@@ -872,9 +872,8 @@ public class WorldAccess {
{
playerBreak = true;
String itemString = val.getString();
item = Registry.ITEM.get(new Identifier(itemString));
if (item == Items.AIR && !itemString.equals("air"))
throw new InternalExpressionException("Incorrect item: " + itemString);
item = Registry.ITEM.getOrEmpty(new Identifier(itemString))
.orElseThrow(() -> new ThrowStatement("Incorrect item: " + itemString, ThrowStatement.UNKNOWN_ITEM));
}
}
CompoundTag tag = null;
@@ -1180,9 +1179,8 @@ public class WorldAccess {
throw new InternalExpressionException("'set_biome' needs a biome name as an argument");
String biomeName = lv.get(locator.offset+0).evalValue(c).getString();
// from locatebiome command code
Biome biome = cc.s.getMinecraftServer().getRegistryManager().get(Registry.BIOME_KEY).get(new Identifier(biomeName));
if (biome == null)
throw new InternalExpressionException("Unknown biome: "+biomeName);
Biome biome = cc.s.getMinecraftServer().getRegistryManager().get(Registry.BIOME_KEY).getOrEmpty(new Identifier(biomeName))
.orElseThrow(() -> new ThrowStatement("Unknown biome: "+biomeName, ThrowStatement.UNKNOWN_BIOME));
boolean doImmediateUpdate = true;
if (lv.size() > locator.offset+1)
{
@@ -1251,8 +1249,8 @@ public class WorldAccess {
if (!(requested instanceof NullValue))
{
String reqString = requested.getString();
structure = Registry.STRUCTURE_FEATURE.get(new Identifier(reqString));
if (structure == null) throw new InternalExpressionException("Unknown structure: " + reqString);
structure = Registry.STRUCTURE_FEATURE.getOrEmpty(new Identifier(reqString))
.orElseThrow(() -> new ThrowStatement("Unknown structure: " + reqString, ThrowStatement.UNKNOWN_STRUCTURE));
}
if (lv.size() > locator.offset+1)
{
@@ -1332,7 +1330,7 @@ public class WorldAccess {
throw new InternalExpressionException("'set_structure requires at least position and a structure name");
String structureName = lv.get(locator.offset).evalValue(c).getString().toLowerCase(Locale.ROOT);
ConfiguredStructureFeature<?, ?> configuredStructure = FeatureGenerator.resolveConfiguredStructure(structureName, world, pos);
if (configuredStructure == null) throw new InternalExpressionException("Unknown structure: "+structureName);
if (configuredStructure == null) throw new ThrowStatement("Unknown structure: "+structureName, ThrowStatement.UNKNOWN_STRUCTURE);
// good 'ol pointer
Value[] result = new Value[]{Value.NULL};
// technically a world modification. Even if we could let it slide, we will still park it
@@ -8,28 +8,32 @@ import carpet.script.value.FunctionValue;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
/* The expression evaluators exception class. */
public class ExpressionException extends RuntimeException implements ResolvedException
{
public final Context context;
public final List<FunctionValue> stack = new ArrayList<>();
private final Supplier<String> lazyStacktrace;
private String cachedMessage = null;
public ExpressionException(Context c, Expression e, String message)
{
super(makeMessage(c, e, null, message));
context = c;
this(c, e, null, message);
}
public ExpressionException(Context c, Expression e, Tokenizer.Token t, String message)
{
super(makeMessage(c, e, t, message));
super("Error");
lazyStacktrace = () -> makeMessage(c, e, t, message);
context = c;
}
public ExpressionException(Context c, Expression e, Tokenizer.Token t, String message, List<FunctionValue> stack)
{
super(makeMessage(c, e, t, message));
super("Error");
this.stack.addAll(stack);
lazyStacktrace = () -> makeMessage(c, e, t, message);
context = c;
}
@@ -68,4 +72,13 @@ public class ExpressionException extends RuntimeException implements ResolvedExc
}
return String.join("\n", errorMaker.apply(e, t, message));
}
@Override
public String getMessage() {
if (cachedMessage == null)
{
cachedMessage = lazyStacktrace.get();
}
return cachedMessage;
}
}
@@ -1,5 +1,8 @@
package carpet.script.exception;
import carpet.script.Context;
import carpet.script.Expression;
import carpet.script.Tokenizer;
import carpet.script.value.FunctionValue;
import java.util.ArrayList;
@@ -13,4 +16,20 @@ public class InternalExpressionException extends RuntimeException
{
super(message);
}
/**
* <p>Promotes this simple exception into one with context and extra information.
*
* <p>Provides a cleaner way of handling similar exceptions, in this case
* {@link InternalExpressionException} and {@link ThrowStatement}
* @param c Context
* @param e Expression
* @param token Token
* @return The new {@link ExpressionException} (or {@link ProcessedThrowStatement}),
* depending on the implementation.
*/
public ExpressionException promote(Context c, Expression e, Tokenizer.Token token)
{
return new ExpressionException(c, e, token, getMessage(), stack);
}
}
@@ -0,0 +1,20 @@
package carpet.script.exception;
import java.util.List;
import carpet.script.Context;
import carpet.script.Expression;
import carpet.script.Tokenizer.Token;
import carpet.script.value.FunctionValue;
import carpet.script.value.Value;
public class ProcessedThrowStatement extends ExpressionException {
public final Value exceptionName;
public final String message;
public ProcessedThrowStatement(Context c, Expression e, Token token, String message, List<FunctionValue> stack, Value exceptionName) {
super(c, e, token, "Unhandled exception: "+message, stack);
this.exceptionName = exceptionName;
this.message = message;
}
}
@@ -1,11 +1,68 @@
package carpet.script.exception;
import carpet.script.Context;
import carpet.script.Expression;
import carpet.script.Tokenizer.Token;
import carpet.script.value.StringValue;
import carpet.script.value.Value;
public class ThrowStatement extends ExitStatement
public class ThrowStatement extends InternalExpressionException
{
public static final String UNKNOWN_ITEM = "unknown_item";
public static final String UNKNOWN_BLOCK = "unknown_block";
public static final String UNKNOWN_BIOME = "unknown_biome";
public static final String UNKNOWN_SOUND = "unknown_sound";
public static final String UNKNOWN_PARTICLE = "unknown_particle";
public static final String UNKNOWN_POI_TYPE = "unknown_poi_type";
public static final String UNKNOWN_DIMENSION = "unknown_dimension";
public static final String UNKNOWN_STRUCTURE = "unknown_structure";
public static final String UNKNOWN_CRITERION = "unknown_criterion";
public static final String NBT_READ_EXCEPTION = "nbt_read_exception";
public static final String JSON_READ_EXCEPTION = "json_read_exception";
public final Value retval;
/**
* Creates a throw exception from a value.
* That value will also be used as the message.<br>
* To use when throwing from Scarpet's {@code throw}
* @param value The value to pass
*/
public ThrowStatement(Value value)
{
super(value);
super(value.getString());
retval = value;
}
/**
* Creates a throw exception from a value, and
* assigns it a specified message.<br>
* To use when throwing from Scarpet's {@code throw}
* function
* @param message The message to display if uncaught
* @param value The value to pass
*/
public ThrowStatement(String message, Value value)
{
super(message);
retval = value;
}
/**
* Creates a throw exception.<br>
* Conveniently creates a value from the {@code value} String
* to be used easily in Java code
* @param message The message to display when not handled
* @param value A String that will be converted
* to a value to pass to {@code catch}
* blocks
*/
public ThrowStatement(String message, String value)
{
super(message);
retval = new StringValue(value);
}
@Override
public ExpressionException promote(Context c, Expression e, Token token) {
return new ProcessedThrowStatement(c, e, token, getMessage(), stack, retval);
}
}
@@ -5,7 +5,9 @@ import carpet.script.Expression;
import carpet.script.LazyValue;
import carpet.script.exception.ExitStatement;
import carpet.script.exception.InternalExpressionException;
import carpet.script.exception.ProcessedThrowStatement;
import carpet.script.exception.ThrowStatement;
import carpet.script.value.StringValue;
import carpet.script.value.Value;
public class ControlFlow {
@@ -42,7 +44,20 @@ public class ControlFlow {
expression.addFunction("exit", (lv) -> { throw new ExitStatement(lv.size()==0?Value.NULL:lv.get(0)); });
expression.addFunction("throw", (lv)-> {throw new ThrowStatement(lv.size()==0?Value.NULL:lv.get(0)); });
expression.addLazyFunction("throw", -1, (c, t, lv)->
{
switch (lv.size())
{
case 0:
throw new ThrowStatement("No further information", Value.NULL);
case 1:
throw new ThrowStatement(lv.get(0).evalValue(c));
case 2:
throw new ThrowStatement(lv.get(1).evalValue(c).getString(), lv.get(0).evalValue(c));
default:
throw new InternalExpressionException("throw() can't accept more than 2 parameters");
}
});
expression.addLazyFunction("try", -1, (c, t, lv) ->
{
@@ -53,14 +68,27 @@ public class ControlFlow {
Value retval = lv.get(0).evalValue(c, t);
return (c_, t_) -> retval;
}
catch (ThrowStatement ret)
catch (ProcessedThrowStatement ret)
{
if (lv.size() == 1)
return (c_, t_) -> Value.NULL;
LazyValue __ = c.getVariable("_");
c.setVariable("_", (__c, __t) -> ret.retval.reboundedTo("_"));
Value val = lv.get(1).evalValue(c, t);
c.setVariable("_", (__c, __t) -> ret.exceptionName.reboundedTo("_"));
LazyValue __msg = c.getVariable("_msg");
c.setVariable("_msg", (__c, __t) -> StringValue.of(ret.message).reboundedTo("_msg"));
Value val;
if (lv.size() == 3)
{
if (!ret.exceptionName.equals(lv.get(1).evalValue(c)))
throw ret;
val = lv.get(2).evalValue(c, t);
}
else
{
val = lv.get(1).evalValue(c, t);
}
c.setVariable("_",__);
c.setVariable("_msg", __msg);
return (c_, t_) -> val;
}
});
@@ -4,6 +4,7 @@ import carpet.CarpetSettings;
import carpet.network.ServerNetworkHandler;
import carpet.script.CarpetContext;
import carpet.script.exception.InternalExpressionException;
import carpet.script.exception.ThrowStatement;
import carpet.script.language.Sys;
import carpet.script.value.BlockValue;
import carpet.script.value.EntityValue;
@@ -156,7 +157,7 @@ public class ShapeDispatcher
}
catch (CommandSyntaxException e)
{
throw new InternalExpressionException("No such particle: "+name);
throw new ThrowStatement("No such particle: "+name, ThrowStatement.UNKNOWN_PARTICLE);
}
particleCache.put(name, particle);
return particle;
@@ -2,6 +2,8 @@ package carpet.script.value;
import carpet.script.CarpetContext;
import carpet.script.exception.InternalExpressionException;
import carpet.script.exception.ThrowStatement;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.block.BlockState;
@@ -73,7 +75,7 @@ public class BlockValue extends Value
catch (CommandSyntaxException ignored)
{
}
throw new InternalExpressionException("Cannot parse block: "+str);
throw new ThrowStatement("Cannot parse block: "+str, ThrowStatement.UNKNOWN_BLOCK);
}
public static BlockPos locateBlockPos(CarpetContext c, int xpos, int ypos, int zpos)
@@ -215,7 +215,6 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
}
Value retVal;
boolean rethrow = false;
try
{
retVal = body.evalValue(newFrame, type); // todo not sure if we need to propagete type / consider boolean context in defined functions - answer seems ye
@@ -228,15 +227,6 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
{
retVal = returnStatement.retval;
}
catch (ThrowStatement throwStatement) // might not be really necessary
{
retVal = throwStatement.retval;
rethrow = true;
}
if (rethrow)
{
throw new ThrowStatement(retVal);
}
Value otherRetVal = retVal;
return (cc, tt) -> otherRetVal;
}
@@ -4,6 +4,7 @@ import carpet.fakes.InventoryBearerInterface;
import carpet.script.CarpetContext;
import carpet.script.LazyValue;
import carpet.script.exception.InternalExpressionException;
import carpet.script.exception.ThrowStatement;
import carpet.script.utils.EquipmentInventory;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
@@ -297,7 +298,7 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
}
catch (CommandSyntaxException e)
{
throw new InternalExpressionException("Incorrect item: "+itemString);
throw new ThrowStatement("Incorrect item: "+itemString, ThrowStatement.UNKNOWN_ITEM);
}
}
@@ -2,6 +2,7 @@ package carpet.script.value;
import carpet.fakes.BlockPredicateInterface;
import carpet.script.exception.InternalExpressionException;
import carpet.script.exception.ThrowStatement;
import carpet.utils.BlockInfo;
import net.minecraft.block.BlockState;
import net.minecraft.block.MaterialColor;
@@ -158,7 +159,7 @@ public class ValueConversions
}
}
if (dim == null)
throw new InternalExpressionException("Incorrect dimension string: "+dimString);
throw new ThrowStatement("Incorrect dimension string: "+dimString, ThrowStatement.UNKNOWN_DIMENSION);
return server.getWorld(dim);
}
}