feat(muscript): add StandardLib to muscript-data-additional

This commit is contained in:
Johannes Frohnmeyer 2024-04-07 15:36:19 +02:00
parent f1e51f98e3
commit 570264ecbc
Signed by: Johannes
GPG Key ID: E76429612C2929F4
7 changed files with 657 additions and 0 deletions

View File

@ -0,0 +1,19 @@
package io.gitlab.jfronny.muscript.data.additional.context;
import io.gitlab.jfronny.muscript.ast.context.Script;
import io.gitlab.jfronny.muscript.data.dynamic.DCallable;
import java.util.ServiceLoader;
public interface IExprBinder {
IExprBinder INSTANCE = ServiceLoader.load(IExprBinder.class)
.findFirst()
.orElseGet(() -> new IExprBinder() {
@Override
public DCallable bind(Script script, Scope scope) {
throw new UnsupportedOperationException();
}
});
DCallable bind(Script script, Scope scope);
}

View File

@ -0,0 +1,127 @@
package io.gitlab.jfronny.muscript.data.additional.context;
import io.gitlab.jfronny.commons.data.ImmCollection;
import io.gitlab.jfronny.muscript.ast.context.IScope;
import io.gitlab.jfronny.muscript.data.additional.DFinal;
import io.gitlab.jfronny.muscript.data.dynamic.DList;
import io.gitlab.jfronny.muscript.data.dynamic.DObject;
import io.gitlab.jfronny.muscript.data.dynamic.Dynamic;
import io.gitlab.jfronny.muscript.data.dynamic.context.DynamicSerializer;
import io.gitlab.jfronny.muscript.data.dynamic.type.DType;
import io.gitlab.jfronny.muscript.data.dynamic.type.DTypeList;
import io.gitlab.jfronny.muscript.data.dynamic.type.DTypeObject;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
public class Scope implements DObject, IScope {
private final @Nullable Scope source;
private final Map<String, Dynamic> override = new HashMap<>();
public Scope() {
this(null);
}
public Scope(@Nullable DObject source) {
if (source == null) {
this.source = null;
} else if (source instanceof Scope src) {
this.source = src;
} else {
this.source = new Scope();
source.getValue().forEach(this::set);
}
}
public Scope(@Nullable Scope source) {
this.source = source;
}
public static Scope of(DObject source) {
return source instanceof Scope scope ? scope: new Scope(source);
}
@Override
public Map<String, Dynamic> getValue() {
if (source == null) return ImmCollection.of(override);
var map = new HashMap<>(source.getValue());
map.putAll(override);
return ImmCollection.of(map);
}
/**
* @deprecated Using the convenience methods is recommended wherever possible.
*/
@Deprecated(forRemoval = false)
public Scope set(String key, Dynamic value) {
if (key.startsWith("$")) {
if (!setGlobal(key, value)) override.put(key, value);
} else {
override.put(key, value);
}
return this;
}
private boolean setGlobal(String key, Dynamic value) {
if (override.containsKey(key)) {
override.put(key, value);
return true;
} else if (source != null) {
return source.setGlobal(key, value);
} else {
return false;
}
}
public Scope set(String key, boolean value) {
return set(key, DFinal.of(value));
}
public Scope set(String key, double value) {
return set(key, DFinal.of(value));
}
public Scope set(String key, String value) {
return set(key, DFinal.of(value));
}
public Scope set(String key, Map<String, ? extends Dynamic> value) {
return set(key, DFinal.of(value));
}
public Scope set(String key, DTypeObject signature, Map<String, ? extends Dynamic> value) {
return set(key, DFinal.of(signature, value));
}
public Scope set(String key, List<? extends Dynamic> value) {
return set(key, DFinal.of(value));
}
public Scope set(String key, DTypeList signature, List<? extends Dynamic> value) {
return set(key, DFinal.of(signature, value));
}
public Scope set(String key, Function<DList, ? extends Dynamic> value) {
return set(key, DFinal.of(value, () -> key, key));
}
public Scope set(String key, DType signature, Function<DList, ? extends Dynamic> value) {
return set(key, DFinal.of(signature, value, () -> key, key));
}
public Scope fork() {
return new Scope(this);
}
public DObject getOverrides() {
return DFinal.of(override);
}
@Override
public String toString() {
return DynamicSerializer.INSTANCE.serialize(this);
}
}

View File

@ -0,0 +1,31 @@
package io.gitlab.jfronny.muscript.data.additional.libs;
import io.gitlab.jfronny.muscript.ast.context.Script;
import io.gitlab.jfronny.muscript.core.MuScriptVersion;
import io.gitlab.jfronny.muscript.data.additional.DFinal;
import io.gitlab.jfronny.muscript.data.additional.context.IExprBinder;
import io.gitlab.jfronny.muscript.data.additional.context.Scope;
import io.gitlab.jfronny.muscript.data.dynamic.DList;
import io.gitlab.jfronny.muscript.data.dynamic.Dynamic;
import java.util.List;
import static io.gitlab.jfronny.muscript.data.dynamic.type.DSL.*;
public class IOLib {
public static Scope addTo(MuScriptVersion version, Scope scope, IOWrapper io) {
if (version.contains(MuScriptVersion.V3)) {
scope.set("readString", callable(STRING, arg("fileName", STRING)), args -> {
if (args.size() != 1) throw new SignatureDesyncException("readString");
return DFinal.of(io.readString(args.get(0).asString().getValue()));
}).set("runScript", callable(null, arg("fileName", STRING), arg("args", null, true)), args -> {
if (args.isEmpty()) throw new SignatureDesyncException("runScript");
Script script = io.parseScript(args.get(0).asString().getValue());
List<? extends Dynamic> l = args.getValue();
DList innerArgs = DFinal.of(l.subList(1, l.size()));
return IExprBinder.INSTANCE.bind(script, scope.fork()).call(innerArgs);
});
}
return scope;
}
}

View File

@ -0,0 +1,56 @@
package io.gitlab.jfronny.muscript.data.additional.libs;
import io.gitlab.jfronny.muscript.ast.context.IExprParser;
import io.gitlab.jfronny.muscript.ast.context.Script;
import io.gitlab.jfronny.muscript.core.MuScriptVersion;
import io.gitlab.jfronny.muscript.core.SourceFS;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
public interface IOWrapper {
String readString(String path);
Script parseScript(String path);
class Caching implements IOWrapper {
private final Map<String, String> cachedStrings = new HashMap<>();
private final Map<String, Script> cachedScripts = new HashMap<>();
private final IOWrapper inner;
public Caching(IOWrapper inner) {
this.inner = Objects.requireNonNull(inner);
}
@Override
public String readString(String path) {
return cachedStrings.computeIfAbsent(path, inner::readString);
}
@Override
public Script parseScript(String path) {
return cachedScripts.computeIfAbsent(path, inner::parseScript);
}
}
class SourceFSWrapper implements IOWrapper {
private final SourceFS inner;
private final MuScriptVersion version;
public SourceFSWrapper(MuScriptVersion version, SourceFS inner) {
this.inner = Objects.requireNonNull(inner);
this.version = Objects.requireNonNull(version);
}
@Override
public String readString(String path) {
return inner.read(path);
}
@Override
public Script parseScript(String path) {
return IExprParser.INSTANCE.parseMultiScript(version, path, inner);
}
}
}

View File

@ -0,0 +1,7 @@
package io.gitlab.jfronny.muscript.data.additional.libs;
public class SignatureDesyncException extends IllegalArgumentException {
public SignatureDesyncException(String method) {
super("Signature desync detected for method: " + method + " (invoked with illegal arguments but passed automatic check)");
}
}

View File

@ -0,0 +1,416 @@
package io.gitlab.jfronny.muscript.data.additional.libs;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.ast.dynamic.Call;
import io.gitlab.jfronny.muscript.ast.dynamic.Variable;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.LocationalException;
import io.gitlab.jfronny.muscript.core.MuScriptVersion;
import io.gitlab.jfronny.muscript.data.additional.*;
import io.gitlab.jfronny.muscript.data.additional.context.Scope;
import io.gitlab.jfronny.muscript.data.dynamic.*;
import io.gitlab.jfronny.muscript.data.dynamic.type.DType;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import static io.gitlab.jfronny.muscript.ast.context.ExprUtils.asDynamic;
import static io.gitlab.jfronny.muscript.data.additional.DFinal.of;
import static io.gitlab.jfronny.muscript.data.dynamic.type.DSL.*;
public class StandardLib {
private static final Random rnd = new Random();
public static Scope createScope(MuScriptVersion version) {
return addTo(version, new Scope());
}
public static Scope addTo(MuScriptVersion version, Scope scope) {
if (version.contains(MuScriptVersion.V1)) {
scope
.set("PI", Math.PI)
.set("E", Math.E)
.set("date", new DCallableObject(Map.of(
"today", new DDate(LocalDate::now)
), object(DDate.SIGNATURE), of(callable(DDate.SIGNATURE, arg("epochDay", NUMBER))
.and(callable(DDate.SIGNATURE, arg("year", NUMBER), arg("month", NUMBER), arg("day", NUMBER))),
args -> {
// Constructor
if (args.size() == 1) return new DDate(() -> LocalDate.ofEpochDay(args.get(0).asNumber().getValue().longValue()));
if (args.size() != 3) throw new SignatureDesyncException("date");
int a0 = args.get(0).asNumber().getValue().intValue();
int a1 = args.get(1).asNumber().getValue().intValue();
int a2 = args.get(2).asNumber().getValue().intValue();
return new DDate(() -> LocalDate.of(a0, a1, a2));
}, "date")))
.set("time", new DCallableObject(Map.of(
"now", new DTime(LocalTime::now)
), object(DTime.SIGNATURE), of(callable(DTime.SIGNATURE, arg("secondOfDay", NUMBER))
.and(callable(DTime.SIGNATURE, arg("hour", NUMBER), arg("minute", NUMBER), arg("second", NUMBER))),
args -> {
// Constructor
if (args.size() == 1) return new DTime(() -> LocalTime.ofSecondOfDay(args.get(0).asNumber().getValue().intValue()));
if (args.size() != 3) throw new SignatureDesyncException("time");
int a0 = args.get(0).asNumber().getValue().intValue();
int a1 = args.get(1).asNumber().getValue().intValue();
int a2 = args.get(2).asNumber().getValue().intValue();
return new DTime(() -> LocalTime.of(a0, a1, a2));
}, "time")))
.set("round", round, StandardLib::round)
.set("floor", floor, StandardLib::floor)
.set("ceil", ceil, StandardLib::ceil)
.set("abs", abs, StandardLib::abs)
.set("random", random, StandardLib::random)
.set("toUpper", toUpper, StandardLib::toUpper)
.set("toLower", toLower, StandardLib::toLower)
.set("contains", contains, StandardLib::contains)
.set("replace", replace, StandardLib::replace);
}
if (version.contains(MuScriptVersion.V2)) {
scope
.set("listOf", listOf, StandardLib::listOf)
.set("len", len, StandardLib::len)
.set("isEmpty", isEmpty, StandardLib::isEmpty)
.set("concat", concat, StandardLib::concat)
.set("filter", filter, StandardLib::filter)
.set("allMatch", allMatch, StandardLib::allMatch)
.set("anyMatch", anyMatch, StandardLib::anyMatch)
.set("map", map, StandardLib::map)
.set("flatMap", flatMap, StandardLib::flatMap)
.set("fold", fold, StandardLib::fold)
.set("forEach", forEach, StandardLib::forEach)
.set("toObject", toObject, StandardLib::toObject)
.set("callableObject", callableObject, StandardLib::callableObject)
.set("enum", enum_, StandardLib::enum_)
.set("keys", keys, StandardLib::keys)
.set("values", values, StandardLib::values)
.set("fail", fail, StandardLib::fail)
.set("try", try_, StandardLib::try_);
}
return scope;
}
public static Map<String, String> printSignatures(MuScriptVersion version) {
return createScope(version).getValue().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, s -> s.getValue().getSignature().toString()));
}
public static void main(String[] args) {
System.out.println(printSignatures(MuScriptVersion.DEFAULT).entrySet().stream().map(s -> s.getKey() + ": " + s.getValue()).collect(Collectors.joining("\n")));
}
// Numbers
private static final DType round = callable(NUMBER, arg("number", NUMBER))
.and(callable(NUMBER, arg("number", NUMBER), arg("decimalPlace", NUMBER)));
public static DNumber round(DList args) {
return switch (args.size()) {
case 1 -> of(Math.round(args.get(0).asNumber().getValue()));
case 2 -> {
double x = Math.pow(10, (int) (double) args.get(1).asNumber().getValue());
yield of(Math.round(args.get(0).asNumber().getValue() * x) / x);
}
default -> throw new SignatureDesyncException("round");
};
}
private static final DType floor = callable(NUMBER, arg("number", NUMBER));
public static DNumber floor(DList args) {
if (args.size() != 1) throw new SignatureDesyncException("floor");
return of(Math.floor(args.get(0).asNumber().getValue()));
}
private static final DType ceil = callable(NUMBER, arg("number", NUMBER));
public static DNumber ceil(DList args) {
if (args.size() != 1) throw new SignatureDesyncException("ceil");
return of(Math.ceil(args.get(0).asNumber().getValue()));
}
private static final DType abs = callable(NUMBER, arg("number", NUMBER));
public static DNumber abs(DList args) {
if (args.size() != 1) throw new SignatureDesyncException("abs");
return of(Math.abs(args.get(0).asNumber().getValue()));
}
private static final DType random = callable(NUMBER)
.and(callable(NUMBER, arg("min", NUMBER), arg("max", NUMBER)))
.and(callable(generic(0), arg("in", list(generic(0)))))
.and(callable(object(generic(0)), arg("in", object(generic(0)))));
public static Dynamic random(DList args) {
return switch (args.size()) {
case 0 -> of(rnd.nextDouble());
case 2 -> {
double min = args.get(0).asNumber().getValue();
double max = args.get(1).asNumber().getValue();
yield of(min + (max - min) * rnd.nextDouble());
}
case 1 -> {
if (args.get(0).isList()) {
List<? extends Dynamic> list = args.get(0).asList().getValue();
yield list.get(rnd.nextInt(list.size()));
} else if (args.get(0).isObject()) {
var list = List.copyOf(args.get(0).asObject().getValue().entrySet());
yield objectRepresentation(list.get(rnd.nextInt(list.size())));
} else throw new SignatureDesyncException("random");
}
default -> throw new SignatureDesyncException("random");
};
}
// Strings
private static final DType toUpper = callable(STRING, arg("from", STRING));
public static DString toUpper(DList args) {
if (args.size() != 1) throw new SignatureDesyncException("toUpper");
return of(args.get(0).asString().getValue().toUpperCase());
}
private static final DType toLower = callable(STRING, arg("from", STRING));
public static DString toLower(DList args) {
if (args.size() != 1) throw new SignatureDesyncException("toLower");
return of(args.get(0).asString().getValue().toLowerCase());
}
private static final DType contains = callable(BOOL, arg("search", list(generic(0))), arg("entry", generic(0)))
.and(callable(BOOL, arg("search", object(null)), arg("key", STRING)))
.and(callable(BOOL, arg("search", STRING), arg("substring", STRING)));
public static DBool contains(DList args) {
if (args.size() != 2) throw new SignatureDesyncException("contains");
Dynamic arg0 = args.get(0);
Dynamic arg1 = args.get(1);
boolean contained = false;
contained |= arg0.isList() && arg0.asList().getValue().contains(arg1);
contained |= arg0.isObject() && arg0.asObject().getValue().containsKey(arg1.asString().getValue());
contained |= arg0.isString() && arg0.asString().getValue().contains(arg1.asString().getValue());
return of(contained);
}
private static final DType replace = callable(STRING, arg("in", STRING), arg("target", STRING), arg("replacement", STRING));
public static DString replace(DList args) {
if (args.size() != 3) throw new SignatureDesyncException("replace");
return of(args.get(0).asString().getValue().replace(args.get(1).asString().getValue(), args.get(2).asString().getValue()));
}
// Lists
private static final DType listOf = callable(list(generic(0)), arg("entries", generic(0), true));
public static DList listOf(DList args) {
return args;
}
private static final DType len = callable(NUMBER, arg("of", STRING.or(object(null)).or(list(null))));
public static DNumber len(DList args) {
if (args.size() != 1) throw new SignatureDesyncException("len");
Dynamic arg0 = args.get(0);
if (arg0.isString()) return of(arg0.asString().getValue().length());
if (arg0.isObject()) return of(arg0.asObject().getValue().size());
if (arg0.isList()) return of(arg0.asList().size());
throw new SignatureDesyncException("len");
}
private static final DType isEmpty = callable(BOOL, arg("collection", object(null).or(list(null)).or(STRING)));
public static DBool isEmpty(DList args) {
if (args.size() != 1) throw new SignatureDesyncException("isEmpty");
Dynamic arg0 = args.get(0);
if (arg0.isObject()) return of(arg0.asObject().getValue().isEmpty());
if (arg0.isList()) return of(arg0.asList().isEmpty());
if (arg0.isString()) return of(arg0.asString().getValue().isEmpty());
throw new SignatureDesyncException("isEmpty");
}
private static final DType concat = callable(list(generic(0)), arg("lists", list(generic(0)), true))
.and(callable(object(generic(0)), arg("objects", generic(0), true)));
public static Dynamic concat(DList args) {
if (args.isEmpty()) return DEmpty.INSTANCE;
if (args.get(0).isList()) return of(args.getValue().stream().flatMap(s -> s.asList().getValue().stream()).toList());
if (args.get(0).isObject()) return of(args.getValue().stream().flatMap(s -> s.asObject().getValue().entrySet().stream()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
throw new SignatureDesyncException("concat");
}
private static final DType filter = callable(list(generic(0)), arg("list", list(generic(0))), arg("predicate", callable(BOOL, arg("current", generic(0)))))
.and(callable(object(generic(0)), arg("object", object(generic(0))), arg("predicate", callable(BOOL, arg("key", STRING), arg("value", generic(0))))));
public static Dynamic filter(DList args) {
if (args.size() != 2) throw new SignatureDesyncException("filter");
DCallable dc = args.get(1).asCallable();
if (args.get(0).isList()) return of(args.get(0).asList().getValue().stream().filter(a -> dc.call(a).asBool().getValue()).toList());
if (args.get(0).isObject()) return of(args.get(0).asObject().getValue().entrySet().stream().filter(entry -> dc.call(of(entry.getKey()), entry.getValue()).asBool().getValue()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
throw new SignatureDesyncException("filter");
}
private static final DType allMatch = callable(BOOL, arg("list", list(generic(0))), arg("predicate", callable(BOOL, arg("current", generic(0)))))
.and(callable(BOOL, arg("object", object(generic(0))), arg("predicate", callable(BOOL, arg("key", STRING), arg("value", STRING)))));
public static DBool allMatch(DList args) {
if (args.size() != 2) throw new SignatureDesyncException("allMatch");
DCallable dc = args.get(1).asCallable();
if (args.get(0).isList()) return of(args.get(0).asList().getValue().stream().allMatch(a -> dc.call(a).asBool().getValue()));
if (args.get(0).isObject()) return of(args.get(0).asObject().getValue().entrySet().stream().allMatch(a -> dc.call(of(a.getKey()), a.getValue()).asBool().getValue()));
throw new SignatureDesyncException("allMatch");
}
private static final DType anyMatch = callable(BOOL, arg("list", list(generic(0))), arg("predicate", callable(BOOL, arg("current", generic(0)))))
.and(callable(BOOL, arg("object", object(generic(0))), arg("predicate", callable(BOOL, arg("key", STRING), arg("value", STRING)))));
public static DBool anyMatch(DList args) {
if (args.size() != 2) throw new SignatureDesyncException("anyMatch");
DCallable dc = args.get(1).asCallable();
if (args.get(0).isList()) return of(args.get(0).asList().getValue().stream().anyMatch(a -> dc.call(a).asBool().getValue()));
if (args.get(0).isObject()) return of(args.get(0).asObject().getValue().entrySet().stream().anyMatch(a -> dc.call(of(a.getKey()), a.getValue()).asBool().getValue()));
throw new SignatureDesyncException("anyMatch");
}
private static final DType map = callable(list(generic(1)), arg("list", list(generic(0))), arg("mapper", callable(generic(1), arg("value", generic(0)))))
.and(callable(object(generic(1)), arg("object", object(generic(0))), arg("mapper", callable(generic(1), arg("key", STRING), arg("value", generic(0))))));
public static Dynamic map(DList args) {
if (args.size() != 2) throw new SignatureDesyncException("map");
DCallable dc = args.get(1).asCallable();
if (args.get(0).isList()) return of(args.get(0).asList().getValue().stream().map(dc::call).toList());
if (args.get(0).isObject()) return of(args.get(0).asObject().getValue().entrySet().stream().map(e -> new Entry(e.getKey(), dc.call(of(e.getKey()), e.getValue()))).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
throw new SignatureDesyncException("map");
}
private static final DType flatMap = callable(list(generic(1)), arg("list", list(generic(0))), arg("mapper", callable(list(generic(1)), arg("value", generic(0)))))
.and(callable(object(generic(1)), arg("object", object(generic(0))), arg("mapper", callable(object(generic(1)), arg("key", STRING), arg("value", generic(0))))));
public static Dynamic flatMap(DList args) {
if (args.size() != 2) throw new SignatureDesyncException("flatMap");
DCallable dc = args.get(1).asCallable();
if (args.get(0).isList()) return of(args.get(0).asList().getValue().stream().flatMap(a -> dc.call(a).asList().getValue().stream()).toList());
if (args.get(0).isObject()) return of(args.get(0).asObject().getValue().entrySet().stream().flatMap(e -> dc.call(of(e.getKey()), e.getValue()).asObject().getValue().entrySet().stream()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
throw new SignatureDesyncException("flatMap");
}
private static final DType fold = callable(generic(1), arg("list", list(generic(0))), arg("identity", generic(1)), arg("accumulator", callable(generic(1), arg("previous", generic(1)), arg("current", generic(0)))));
public static Dynamic fold(DList args) {
if (args.size() != 3) throw new SignatureDesyncException("fold");
return args.get(0).asList().getValue().stream().<Dynamic>map(Function.identity()).reduce(args.get(1), args.get(2).asCallable()::call);
}
private static final DType forEach = callable(generic(1), arg("list", list(generic(0))), arg("operation", callable(generic(1), arg("item", generic(0)))));
public static Dynamic forEach(DList args) {
if (args.size() != 2) throw new SignatureDesyncException("forEach");
Dynamic result = new DNull();
DCallable dc = args.get(1).asCallable();
for (Dynamic dynamic : args.get(0).asList().getValue()) {
result = dc.call(dynamic);
}
return result;
}
private static final DType toObject = callable(object(generic(1)), arg("list", list(generic(0))), arg("keyMapper", callable(STRING, arg("item", generic(0)))), arg("valueMapper", callable(generic(1), arg("item", generic(0)))));
public static DObject toObject(DList args) {
if (args.size() != 3) throw new SignatureDesyncException("toObject");
DCallable keyMapper = args.get(1).asCallable();
DCallable valueMapper = args.get(2).asCallable();
return of(args.get(0)
.asList()
.getValue()
.stream()
.collect(Collectors.<Dynamic, String, Dynamic, LinkedHashMap<String, Dynamic>>toMap(
a -> keyMapper.call(a).asString().getValue(),
valueMapper::call,
(a, b) -> b,
LinkedHashMap::new
)));
}
// Objects
private static final DType callableObject = callable(object(generic(0)).and(callable(null, (DType) null)), arg("object", object(generic(0))), arg("callable", callable(null, (DType) null)));
public static DCallableObject callableObject(DList args) {
if (args.size() != 2) throw new SignatureDesyncException("callableObject");
return new DCallableObject(args.get(0).asObject().getValue(), args.get(1).asCallable());
}
private static final DType enumRepr = object(generic(0)).and(list(generic(0))).and(STRING);
private static final DType enum_ = callable(enumRepr, arg("content", object(generic(0))))
.and(callable(enumRepr.and(NUMBER), arg("content", object(generic(0))), arg("selectedKey", STRING)));
public static DEnum enum_(DList args) {
if (args.size() == 1) return new DEnum(args.get(0).asObject().getValue());
else if (args.size() == 2) return new DEnum(args.get(0).asObject().getValue(), args.get(1).asString().getValue());
else throw new SignatureDesyncException("enum");
}
private static final DType keys = callable(list(STRING), arg("object", object(null)));
public static DList keys(DList args) {
if (args.size() != 1) throw new SignatureDesyncException("keys");
return of(args.get(0).asObject().getValue().keySet().stream().map(DFinal::of).toList());
}
private static final DType values = callable(list(generic(0)), arg("object", object(generic(0))));
public static DList values(DList args) {
if (args.size() != 1) throw new SignatureDesyncException("values");
return of(args.get(0).asObject().getValue().values().stream().toList());
}
private static final DType try_ = callable(object(null), arg("block", callable(null, arg("args", null, true))), arg("args", null, true));
public static DObject try_(DList args) {
if (args.isEmpty()) throw new SignatureDesyncException("try");
var callable = args.get(0).asCallable();
var l = args.getValue();
var innerArgs = of(l.subList(1, l.size()));
Supplier<Expr> serializedCatch = () ->
new Call(CodeLocation.NONE,
new Variable(CodeLocation.NONE, "call"),
args.getValue().stream().map(a -> new Call.Argument(asDynamic(DataExprMapper.map(a)), false)).toList()
);
try {
var result = callable.call(innerArgs);
return of(Map.of(
"result", result,
"catch", of("catch", param -> {
if (param.size() != 1) throw new SignatureDesyncException("catch");
param.get(0).asCallable();
return of(Map.of("result", result));
}, serializedCatch)
));
} catch (LocationalException le) {
return of(Map.of(
"result", new DNull(),
"catch", of("catch", param -> {
if (param.size() != 1) throw new SignatureDesyncException("catch");
var result = param.get(0).asCallable().call(of(Map.of(
"message", of(le.getMessage())
)));
return of(Map.of("result", result));
}, serializedCatch)
));
}
}
private static final DType fail = callable(null, arg("message", STRING))
.and(callable(null));
public static DNull fail(DList args) {
if (args.size() > 1) throw new SignatureDesyncException("fail");
throw new RuntimeException(args.isEmpty() ? "Failed" : args.get(0).asString().getValue());
}
// Util
public static DObject objectRepresentation(Map.Entry<String, ? extends Dynamic> entry) {
return objectRepresentation(entry.getKey(), entry.getValue());
}
public static DObject objectRepresentation(String key, Dynamic value) {
return of(Map.of("key", of(key), "value", value));
}
record Entry(String key, Dynamic value) implements Map.Entry<String, Dynamic> {
@Override
public String getKey() {
return key;
}
@Override
public Dynamic getValue() {
return value;
}
@Override
public Dynamic setValue(Dynamic value) {
throw new UnsupportedOperationException();
}
}
}

View File

@ -1,5 +1,6 @@
module io.gitlab.jfronny.commons.muscript.data.additional {
uses io.gitlab.jfronny.muscript.data.additional.DataExprMapper.Mapping;
uses io.gitlab.jfronny.muscript.data.additional.context.IExprBinder;
requires io.gitlab.jfronny.commons;
requires static org.jetbrains.annotations;
requires io.gitlab.jfronny.commons.muscript.data;