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

112 lines
5.4 KiB
Java

package io.gitlab.jfronny.respackopts.gson;
import io.gitlab.jfronny.commons.serialize.MalformedDataException;
import io.gitlab.jfronny.commons.serialize.SerializeReader;
import io.gitlab.jfronny.commons.serialize.SerializeWriter;
import io.gitlab.jfronny.commons.serialize.databind.api.SerializerFor;
import io.gitlab.jfronny.commons.serialize.databind.api.TypeAdapter;
import io.gitlab.jfronny.muscript.ast.context.ExprUtils;
import io.gitlab.jfronny.muscript.parser.lexer.Token;
import io.gitlab.jfronny.muscript.ast.*;
import io.gitlab.jfronny.muscript.ast.bool.*;
import io.gitlab.jfronny.muscript.ast.dynamic.*;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import java.util.*;
@SerializerFor(targets = BoolExpr.class)
public class BoolExprDeserializer extends TypeAdapter<BoolExpr> {
public static final BoolExprDeserializer INSTANCE = new BoolExprDeserializer();
@Override
public <TEx extends Exception, Reader extends SerializeReader<TEx, Reader>> BoolExpr deserialize(Reader reader) throws TEx, MalformedDataException {
if (AttachmentHolder.getAttachedVersion() > 7) {
return ExprUtils.asBool(ExprDeserializer.INSTANCE.deserialize(reader));
}
// Legacy JSON syntax
if (reader.peek() == io.gitlab.jfronny.commons.serialize.Token.BEGIN_OBJECT) {
reader.beginObject();
if (reader.hasNext()) {
String key = reader.nextName();
BoolExpr expr = switch (key.toLowerCase(Locale.ROOT)) {
case "and", "add", "&" -> merge(reader, Token.And);
case "==", "=", "equal", "eq" -> merge(reader, Token.EqualEqual);
case "not", "nor", "!" -> new Not(CodeLocation.NONE, merge(reader, Token.Or));
case "or", "|" -> merge(reader, Token.Or);
case "^", "xor" -> merge(reader, Token.BangEqual);
default -> throw new MalformedDataException("Unknown condition type: " + key);
};
reader.endObject();
return expr;
} else {
reader.endObject();
throw new MalformedDataException("Empty condition object");
}
} else if (reader.peek() == io.gitlab.jfronny.commons.serialize.Token.BEGIN_ARRAY) {
return merge(reader, Token.And);
} else if (reader.peek() == io.gitlab.jfronny.commons.serialize.Token.STRING) {
String name = reader.nextString();
if (name.toLowerCase(Locale.ROOT).equals("true"))
return Expr.literal(CodeLocation.NONE, true);
if (name.toLowerCase(Locale.ROOT).equals("false"))
return Expr.literal(CodeLocation.NONE, false);
return rpoBooleanCondition(name);
} else if (reader.peek() == io.gitlab.jfronny.commons.serialize.Token.BOOLEAN) {
return Expr.literal(CodeLocation.NONE, reader.nextBoolean());
} else {
throw new MalformedDataException("Invalid data type for condition");
}
}
private <TEx extends Exception, Reader extends SerializeReader<TEx, Reader>> BoolExpr merge(Reader source, Token token) throws TEx, MalformedDataException {
if (token == Token.BangEqual)
return new Not(CodeLocation.NONE, merge(source, Token.EqualEqual));
List<BoolExpr> expressions = new ArrayList<>();
if (source.peek() == io.gitlab.jfronny.commons.serialize.Token.BEGIN_ARRAY) {
source.beginArray();
while (source.hasNext()) {
expressions.add(deserialize(source));
}
source.endArray();
} else {
expressions.add(deserialize(source));
}
BoolExpr current = expressions.getFirst();
for (BoolExpr expr : expressions.subList(1, expressions.size())) {
current = switch (token) {
case EqualEqual -> new Equals(CodeLocation.NONE, current, expr);
case And -> new And(CodeLocation.NONE, current, expr);
case Or -> new Or(CodeLocation.NONE, current, expr);
default -> throw new IllegalArgumentException();
};
}
return current;
}
private BoolExpr rpoBooleanCondition(String name) throws MalformedDataException {
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 ExprUtils.asBool(new Call(CodeLocation.NONE, new Variable(CodeLocation.NONE, "version"), List.of(
new Call.Argument(ExprUtils.asDynamic(Expr.literal(mod)), false),
new Call.Argument(ExprUtils.asDynamic(Expr.literal(predicate)), false)
)));
}
DynamicExpr e = null;
String[] arr = name.split("[:.]");
for (int i = 0; i < arr.length; i++) {
if (i == 0) e = new Variable(CodeLocation.NONE, arr[i]);
else e = new Get(CodeLocation.NONE, e, Expr.literal(arr[i]));
}
if (e == null) throw new MalformedDataException("Invalid RPO condition: \"" + name + "\"");
return ExprUtils.asBool(e);
}
@Override
public <TEx extends Exception, Writer extends SerializeWriter<TEx, Writer>> void serialize(BoolExpr boolExpr, Writer writer) throws TEx, MalformedDataException {
ExprDeserializer.INSTANCE.serialize(boolExpr, writer);
}
}