112 lines
5.4 KiB
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);
|
|
}
|
|
}
|