94 lines
4.4 KiB
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();
|
|
}
|
|
}
|