124 lines
4.3 KiB
Java
124 lines
4.3 KiB
Java
package io.gitlab.jfronny.muscript.data.dynamic;
|
|
|
|
import io.gitlab.jfronny.commons.StringFormatter;
|
|
import io.gitlab.jfronny.muscript.compiler.MuScriptVersion;
|
|
import io.gitlab.jfronny.muscript.data.dynamic.type.*;
|
|
import io.gitlab.jfronny.muscript.libs.StandardLib;
|
|
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
|
|
import io.gitlab.jfronny.muscript.ast.Expr;
|
|
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
|
import io.gitlab.jfronny.muscript.compiler.Parser;
|
|
import io.gitlab.jfronny.muscript.data.dynamic.additional.*;
|
|
import io.gitlab.jfronny.muscript.data.dynamic.lens.DStringLens;
|
|
import org.jetbrains.annotations.NotNull;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
import java.io.IOException;
|
|
import java.util.*;
|
|
|
|
/**
|
|
* Represents a value of an unknown type
|
|
* Override toString(StringBuilder) to support custom serialization (note: the serialized form is ran with muScript to generate the tree)
|
|
*/
|
|
public sealed interface Dynamic permits DBool, DCallable, DList, DNull, DNumber, DObject, DString, DynamicBase {
|
|
/**
|
|
* Deserialize simply dynamic values. DOES NOT SUPPORT CALLABLES!
|
|
* Use Parser.parse() if you truly need to deserialize them, but be aware that that might enable DOS attacks
|
|
*/
|
|
static Dynamic deserialize(String source) {
|
|
DynamicExpr expr = Parser.parse(MuScriptVersion.DEFAULT, source).asDynamicExpr();
|
|
if (!DirectPreconditionVisitor.visit(expr)) throw new IllegalArgumentException("This expression does not directly express a dynamic and may not be loaded this way");
|
|
return expr.get(StandardLib.createScope(MuScriptVersion.DEFAULT));
|
|
}
|
|
|
|
static String serialize(Dynamic dynamic) {
|
|
StringBuilder sb = new StringBuilder();
|
|
try (ExprWriter ew = new ExprWriter(sb, true)) {
|
|
dynamic.serialize(ew);
|
|
} catch (IOException e) {
|
|
throw new RuntimeException("Could not stringify", e);
|
|
}
|
|
return sb.toString();
|
|
}
|
|
|
|
static boolean isNull(Dynamic dynamic) {
|
|
return dynamic == null || dynamic instanceof DNull;
|
|
}
|
|
|
|
static @NotNull Dynamic fromNullable(@Nullable Dynamic dynamic) {
|
|
return dynamic == null ? new DNull() : dynamic;
|
|
}
|
|
|
|
default void serialize(ExprWriter writer) throws IOException {
|
|
toExpr().decompile(writer);
|
|
}
|
|
|
|
Expr<?> toExpr();
|
|
Object getValue();
|
|
|
|
default boolean isBool() {
|
|
return this instanceof DBool;
|
|
}
|
|
|
|
default DBool asBool() {
|
|
if (this instanceof DBool bool) return bool;
|
|
else throw new DynamicTypeConversionException("bool", this);
|
|
}
|
|
|
|
default boolean isNumber() {
|
|
return this instanceof DNumber;
|
|
}
|
|
|
|
default DNumber asNumber() {
|
|
if (this instanceof DNumber number) return number;
|
|
else throw new DynamicTypeConversionException("number", this);
|
|
}
|
|
|
|
default boolean isString() {
|
|
return this instanceof DString;
|
|
}
|
|
|
|
default DString asString() {
|
|
if (this instanceof DString string) return string;
|
|
else return new DStringLens(this, () -> StringFormatter.toString(getValue()));
|
|
}
|
|
|
|
default boolean isObject() {
|
|
return this instanceof DObject;
|
|
}
|
|
|
|
default DObject asObject() {
|
|
if (this instanceof DObject object) return object;
|
|
else throw new DynamicTypeConversionException("object", this);
|
|
}
|
|
|
|
default boolean isList() {
|
|
return this instanceof DList;
|
|
}
|
|
|
|
default DList asList() {
|
|
if (this instanceof DList list) return list;
|
|
else throw new DynamicTypeConversionException("list", this);
|
|
}
|
|
|
|
default boolean isCallable() {
|
|
return this instanceof DCallable;
|
|
}
|
|
|
|
default DCallable asCallable() {
|
|
if (this instanceof DCallable callable) return callable;
|
|
else throw new DynamicTypeConversionException("callable", this);
|
|
}
|
|
|
|
default DType getSignature() {
|
|
Set<DType> variants = new HashSet<>();
|
|
if (isBool()) variants.add(DTypePrimitive.BOOL);
|
|
if (isNumber()) variants.add(DTypePrimitive.NUMBER);
|
|
if (isString()) variants.add(DTypePrimitive.STRING);
|
|
if (isObject()) variants.add(new DTypeObject(null));
|
|
if (isList()) variants.add(new DTypeList(null));
|
|
if (isCallable()) variants.add(new DTypeCallable(null, null));
|
|
return variants.size() == 1 ? variants.stream().findFirst().orElseThrow() : new DTypeAnd(variants);
|
|
}
|
|
}
|