Respackopts/src/main/java/io/gitlab/jfronny/respackopts/gson/BoolExprDeserializer.java

94 lines
4.4 KiB
Java

package io.gitlab.jfronny.respackopts.gson;
import io.gitlab.jfronny.gson.*;
import io.gitlab.jfronny.gson.reflect.*;
import io.gitlab.jfronny.muscript.ast.compare.Equal;
import io.gitlab.jfronny.muscript.compiler.*;
import io.gitlab.jfronny.muscript.ast.*;
import io.gitlab.jfronny.muscript.ast.bool.*;
import io.gitlab.jfronny.muscript.ast.dynamic.*;
import java.lang.reflect.Type;
import java.util.*;
public class BoolExprDeserializer implements JsonDeserializer<BoolExpr> {
private static final Type conditionListType = new TypeToken<List<BoolExpr>>(){}.getType();
@Override
public BoolExpr deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if (AttachmentHolder.getAttachedVersion() > 7) {
return context.<Expr<?>>deserialize(json, Expr.class).asBoolExpr();
}
// Legacy JSON syntax
if (json.isJsonObject()) {
JsonObject jo = json.getAsJsonObject();
if (jo.size() != 1)
throw new JsonParseException("More than one key in a condition object");
for (Map.Entry<String, JsonElement> entry : jo.entrySet()) {
return switch (entry.getKey().toLowerCase(Locale.ROOT)) {
case "and", "add", "&" -> merge(context.deserialize(entry.getValue(), conditionListType), Token.And);
case "==", "=", "equal", "eq" -> merge(context.deserialize(entry.getValue(), conditionListType), Token.EqualEqual);
case "not", "nor", "!" -> new Not(-1, -1, merge(context.deserialize(entry.getValue(), conditionListType), Token.Or));
case "or", "|" -> merge(context.deserialize(entry.getValue(), conditionListType), Token.Or);
case "^", "xor" -> merge(context.deserialize(entry.getValue(), conditionListType), Token.BangEqual);
default -> throw new JsonParseException("Unknown condition type: " + entry.getKey());
};
}
}
else if (json.isJsonArray()) {
return merge(context.deserialize(json, conditionListType), Token.And);
}
else if (json.isJsonPrimitive()) {
JsonPrimitive pr = json.getAsJsonPrimitive();
if (pr.isString()) {
String name = pr.getAsString();
if (name.toLowerCase(Locale.ROOT).equals("true"))
return Expr.literal(-1, -1, true);
if (name.toLowerCase(Locale.ROOT).equals("false"))
return Expr.literal(-1, -1, false);
return rpoBooleanCondition(name);
}
else if (pr.isBoolean()) {
return Expr.literal(-1, -1, pr.getAsBoolean());
}
}
throw new JsonParseException("Invalid data type for condition");
}
private BoolExpr merge(List<BoolExpr> expressions, Token token) {
if (token == Token.BangEqual)
return new Not(-1, -1, merge(expressions, Token.EqualEqual));
BoolExpr current = expressions.get(0);
for (BoolExpr expr : expressions.subList(1, expressions.size())) {
current = switch (token) {
case EqualEqual -> new Equal(-1, -1, current, expr);
case And -> new And(-1, -1, current, expr);
case Or -> new Or(-1, -1, current, expr);
default -> throw new IllegalArgumentException();
};
}
return current;
}
private BoolExpr rpoBooleanCondition(String name) {
if (name.startsWith("modversion:")) {
String code = name.substring("modversion:".length());
String mod = code.substring(0, code.indexOf(':'));
String predicate = code.substring(code.indexOf(':') + 1);
return new Call(-1, -1, new Variable(-1, -1, "version"), List.of(
new Call.Arg(Expr.literal(-1, -1, mod).asDynamicExpr(), false),
new Call.Arg(Expr.literal(-1, -1, predicate).asDynamicExpr(), false)
)).asBoolExpr();
}
DynamicExpr e = null;
String[] arr = name.split("[:.]");
for (int i = 0; i < arr.length; i++) {
if (i == 0) e = new Variable(-1, -1, arr[i]);
else e = new Get(-1, -1, e, Expr.literal(arr[i]));
}
if (e == null) throw new JsonParseException("Invalid RPO condition: \"" + name + "\"");
return e.asBoolExpr();
}
}