diff --git a/muscript/README.md b/muscript/README.md index cc08aff..320eda9 100644 --- a/muscript/README.md +++ b/muscript/README.md @@ -71,7 +71,7 @@ one by calling `as(Bool|String|Number|Dynamic)Expr`. This process may throw a ParseException. You can call `get(Dynamic dataRoot)` on the result to execute the script on the provided data, which should be an -`ExpressionParameter` on which you called `StandardLib.addTo()` to add standard methods. +`Scope` on which you called `StandardLib.addTo()` to add standard methods. This is also where you can add custom data to be accessed by your script. The execution of a script can throw a LocationalException which may be converted to a LocationalError for printing using the source of the expression if available. @@ -95,7 +95,7 @@ try { System.err.println(e.asPrintable(source)); return; } -ExpressionParameter parameter = StandardLib.addTo(new ExpressionParameter()) +Scope scope = StandardLib.addTo(new Scope()) .set("someValue", DFinal.of(15)) .set("someOther", DFinal.of(Map.of( "subValue", DFinal.of(true) diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/StandardLib.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/StandardLib.java index c5659e2..75a6232 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/StandardLib.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/StandardLib.java @@ -1,8 +1,8 @@ package io.gitlab.jfronny.muscript; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.data.dynamic.DList; import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; -import io.gitlab.jfronny.muscript.data.ExpressionParameter; import java.text.SimpleDateFormat; import java.util.Date; @@ -16,8 +16,8 @@ public class StandardLib { public static final SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm"); public static final SimpleDateFormat dateFormat = new SimpleDateFormat("dd. MM. yyyy"); - public static ExpressionParameter addTo(ExpressionParameter parameter) { - return parameter + public static Scope addTo(Scope scope) { + return scope .set("PI", of(Math.PI)) .set("time", of(timeFormat.format(new Date()))) .set("date", of(dateFormat.format(new Date()))) diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/Expr.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/Expr.java index bcd23bf..803cf61 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/Expr.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/Expr.java @@ -1,21 +1,30 @@ package io.gitlab.jfronny.muscript.ast; -import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.annotations.CanThrow; import io.gitlab.jfronny.muscript.ast.literal.*; import io.gitlab.jfronny.muscript.ast.string.StringCoerce; import io.gitlab.jfronny.muscript.compiler.Type; +import io.gitlab.jfronny.muscript.data.dynamic.DObject; +import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; import io.gitlab.jfronny.muscript.error.TypeMismatchException; @CanThrow -public sealed abstract class Expr permits BoolExpr, DynamicExpr, NullLiteral, NumberExpr, StringExpr { +public abstract sealed class Expr permits BoolExpr, DynamicExpr, NullLiteral, NumberExpr, StringExpr { protected Expr(int chStart, int chEnd) { this.chStart = chStart; this.chEnd = chEnd; } public abstract Type getResultType(); - public abstract T get(Dynamic dataRoot); + public abstract T get(Scope dataRoot); + public T get(DObject dataRoot) { + return get(dataRoot instanceof Scope scope ? scope : new Scope(dataRoot)); + } + @Deprecated + public T get(Dynamic dataRoot) { + return get(dataRoot.asObject()); + } public abstract Expr optimize(); public final int chStart; public final int chEnd; diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/NullLiteral.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/NullLiteral.java index a6c8fba..e4282ea 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/NullLiteral.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/NullLiteral.java @@ -1,7 +1,7 @@ package io.gitlab.jfronny.muscript.ast; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.data.dynamic.DNull; -import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; import io.gitlab.jfronny.muscript.annotations.CanThrow; import io.gitlab.jfronny.muscript.ast.literal.DynamicLiteral; import io.gitlab.jfronny.muscript.compiler.Type; @@ -19,7 +19,7 @@ public final class NullLiteral extends Expr { } @Override - public Object get(Dynamic dataRoot) { + public Object get(Scope dataRoot) { return null; } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/bool/And.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/bool/And.java index 7617389..3af311f 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/bool/And.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/bool/And.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.muscript.ast.bool; -import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.ast.BoolExpr; import io.gitlab.jfronny.muscript.ast.Expr; import io.gitlab.jfronny.muscript.ast.literal.BoolLiteral; @@ -16,7 +16,7 @@ public class And extends BoolExpr { } @Override - public Boolean get(Dynamic dataRoot) { + public Boolean get(Scope dataRoot) { return left.get(dataRoot) && right.get(dataRoot); } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/bool/Not.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/bool/Not.java index 0afe2b8..f3c8db3 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/bool/Not.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/bool/Not.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.muscript.ast.bool; -import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.ast.BoolExpr; import io.gitlab.jfronny.muscript.ast.Expr; import io.gitlab.jfronny.muscript.ast.literal.BoolLiteral; @@ -14,7 +14,7 @@ public class Not extends BoolExpr { } @Override - public Boolean get(Dynamic dataRoot) { + public Boolean get(Scope dataRoot) { return !inner.get(dataRoot); } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/bool/Or.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/bool/Or.java index 1f47fe8..21cb7d7 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/bool/Or.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/bool/Or.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.muscript.ast.bool; -import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.ast.BoolExpr; import io.gitlab.jfronny.muscript.ast.Expr; import io.gitlab.jfronny.muscript.ast.literal.BoolLiteral; @@ -16,7 +16,7 @@ public class Or extends BoolExpr { } @Override - public Boolean get(Dynamic dataRoot) { + public Boolean get(Scope dataRoot) { return left.get(dataRoot) || right.get(dataRoot); } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/compare/Equal.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/compare/Equal.java index 19f7e26..b72751a 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/compare/Equal.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/compare/Equal.java @@ -1,5 +1,6 @@ package io.gitlab.jfronny.muscript.ast.compare; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; import io.gitlab.jfronny.muscript.ast.BoolExpr; import io.gitlab.jfronny.muscript.ast.Expr; @@ -17,7 +18,7 @@ public class Equal extends BoolExpr { } @Override - public Boolean get(Dynamic dataRoot) { + public Boolean get(Scope dataRoot) { return Objects.equals(unwrap(left.get(dataRoot)), unwrap(right.get(dataRoot))); } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/compare/Greater.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/compare/Greater.java index f80a538..e0055aa 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/compare/Greater.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/compare/Greater.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.muscript.ast.compare; -import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.ast.*; import io.gitlab.jfronny.muscript.ast.literal.NumberLiteral; import io.gitlab.jfronny.muscript.ast.math.*; @@ -16,7 +16,7 @@ public class Greater extends BoolExpr { } @Override - public Boolean get(Dynamic dataRoot) { + public Boolean get(Scope dataRoot) { return left.get(dataRoot) > right.get(dataRoot); } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/compare/Less.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/compare/Less.java index f7535ed..b6aec31 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/compare/Less.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/compare/Less.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.muscript.ast.compare; -import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.ast.*; import io.gitlab.jfronny.muscript.ast.literal.NumberLiteral; import io.gitlab.jfronny.muscript.ast.math.*; @@ -16,7 +16,7 @@ public class Less extends BoolExpr { } @Override - public Boolean get(Dynamic dataRoot) { + public Boolean get(Scope dataRoot) { return left.get(dataRoot) < right.get(dataRoot); } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/conditional/BoolConditional.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/conditional/BoolConditional.java index bee9574..d5bf4bd 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/conditional/BoolConditional.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/conditional/BoolConditional.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.muscript.ast.conditional; -import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.ast.BoolExpr; import io.gitlab.jfronny.muscript.ast.literal.BoolLiteral; @@ -17,7 +17,7 @@ public class BoolConditional extends BoolExpr { } @Override - public Boolean get(Dynamic dataRoot) { + public Boolean get(Scope dataRoot) { return condition.get(dataRoot) ? trueExpr.get(dataRoot) : falseExpr.get(dataRoot); } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/conditional/DynamicConditional.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/conditional/DynamicConditional.java index 90b3b43..1cd2f81 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/conditional/DynamicConditional.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/conditional/DynamicConditional.java @@ -1,5 +1,6 @@ package io.gitlab.jfronny.muscript.ast.conditional; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; import io.gitlab.jfronny.muscript.ast.BoolExpr; import io.gitlab.jfronny.muscript.ast.DynamicExpr; @@ -18,7 +19,7 @@ public class DynamicConditional extends DynamicExpr { } @Override - public Dynamic get(Dynamic dataRoot) { + public Dynamic get(Scope dataRoot) { return condition.get(dataRoot) ? trueExpr.get(dataRoot) : falseExpr.get(dataRoot); } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/conditional/NumberConditional.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/conditional/NumberConditional.java index 7ce6a1b..d1c183d 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/conditional/NumberConditional.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/conditional/NumberConditional.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.muscript.ast.conditional; -import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.ast.BoolExpr; import io.gitlab.jfronny.muscript.ast.NumberExpr; import io.gitlab.jfronny.muscript.ast.literal.BoolLiteral; @@ -18,7 +18,7 @@ public class NumberConditional extends NumberExpr { } @Override - public Double get(Dynamic dataRoot) { + public Double get(Scope dataRoot) { return condition.get(dataRoot) ? trueExpr.get(dataRoot) : falseExpr.get(dataRoot); } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/conditional/StringConditional.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/conditional/StringConditional.java index ec7a25c..8aa7a41 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/conditional/StringConditional.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/conditional/StringConditional.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.muscript.ast.conditional; -import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.ast.BoolExpr; import io.gitlab.jfronny.muscript.ast.StringExpr; import io.gitlab.jfronny.muscript.ast.literal.BoolLiteral; @@ -18,7 +18,7 @@ public class StringConditional extends StringExpr { } @Override - public String get(Dynamic dataRoot) { + public String get(Scope dataRoot) { return condition.get(dataRoot) ? trueExpr.get(dataRoot) : falseExpr.get(dataRoot); } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/conditional/UnresolvedConditional.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/conditional/UnresolvedConditional.java index e5d9ef1..15e8969 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/conditional/UnresolvedConditional.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/conditional/UnresolvedConditional.java @@ -1,5 +1,6 @@ package io.gitlab.jfronny.muscript.ast.conditional; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; import io.gitlab.jfronny.muscript.ast.*; import io.gitlab.jfronny.muscript.annotations.CanThrow; @@ -35,7 +36,7 @@ public class UnresolvedConditional extends DynamicExpr { } @Override - public Dynamic get(Dynamic dataRoot) { + public Dynamic get(Scope dataRoot) { throw new UnsupportedOperationException("Conditional was kept unresolved. This is not supported!"); } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/Assign.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/Assign.java new file mode 100644 index 0000000..d965438 --- /dev/null +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/Assign.java @@ -0,0 +1,35 @@ +package io.gitlab.jfronny.muscript.ast.dynamic; + +import io.gitlab.jfronny.muscript.ast.DynamicExpr; +import io.gitlab.jfronny.muscript.data.Scope; +import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; + +public class Assign extends DynamicExpr { + private final String name; + private final DynamicExpr value; + + public Assign(int chStart, int chEnd, String name, DynamicExpr value) { + super(chStart, chEnd); + this.name = name; + this.value = value; + } + + @Override + public Dynamic get(Scope dataRoot) { + Dynamic data = value.get(dataRoot); + dataRoot.set(name, data); + return data; + } + + @Override + public DynamicExpr optimize() { + return new Assign(chStart, chEnd, name, value.optimize()); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof Assign assign + && name.equals(assign.name) + && value.equals(assign.value); + } +} diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/Call.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/Call.java index 72bd305..6350225 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/Call.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/Call.java @@ -3,6 +3,7 @@ package io.gitlab.jfronny.muscript.ast.dynamic; import io.gitlab.jfronny.muscript.ast.DynamicExpr; import io.gitlab.jfronny.muscript.annotations.CanThrow; import io.gitlab.jfronny.muscript.annotations.UncheckedDynamic; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.data.dynamic.*; import java.util.ArrayList; @@ -21,7 +22,7 @@ public class Call extends DynamicExpr { } @Override - public Dynamic get(Dynamic dataRoot) { + public Dynamic get(Scope dataRoot) { try { return left.get(dataRoot).asCallable().getValue().apply(DFinal.of(args.stream().map(e -> e.get(dataRoot)).toArray(Dynamic[]::new))); } catch (DynamicTypeConversionException e) { diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/Closure.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/Closure.java new file mode 100644 index 0000000..9fca886 --- /dev/null +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/Closure.java @@ -0,0 +1,53 @@ +package io.gitlab.jfronny.muscript.ast.dynamic; + +import io.gitlab.jfronny.muscript.ast.DynamicExpr; +import io.gitlab.jfronny.muscript.ast.Expr; +import io.gitlab.jfronny.muscript.data.Scope; +import io.gitlab.jfronny.muscript.data.dynamic.*; +import io.gitlab.jfronny.muscript.error.LocationalException; + +import java.util.List; + +public class Closure extends DynamicExpr { + private final List boundArgs; + private final List> steps; + private final DynamicExpr fin; + + public Closure(int chStart, int chEnd, List boundArgs, List> expressions) { + this(chStart, chEnd, boundArgs, expressions.subList(0, expressions.size() - 1), expressions.get(expressions.size() - 1).asDynamicExpr()); + } + + private Closure(int chStart, int chEnd, List boundArgs, List> steps, DynamicExpr fin) { + super(chStart, chEnd); + this.boundArgs = List.copyOf(boundArgs); + this.steps = List.copyOf(steps); + this.fin = fin; + } + + @Override + public DCallable get(Scope dataRoot) { + return DFinal.of(args -> { + if (args.size() != boundArgs.size()) throw new LocationalException(chStart, chEnd, "Invoked with unexpected number of parameters"); + Scope fork = dataRoot.fork(); + for (int i = 0; i < boundArgs.size(); i++) fork.set(boundArgs.get(i), args.get(i)); + for (Expr step : steps) { + step.get(fork); + } + return fin.get(fork); + }); + } + + @Override + public DynamicExpr optimize() { + // Eliminating side effect free steps might be possible, but would be too much work imo + return new Closure(chStart, chEnd, boundArgs, steps.stream().>map(Expr::optimize).toList(), fin.optimize()); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof Closure closure + && boundArgs.equals(closure.boundArgs) + && steps.equals(closure.steps) + && fin.equals(closure.fin); + } +} diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/DynamicCoerce.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/DynamicCoerce.java index 6e24b39..714e4ef 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/DynamicCoerce.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/DynamicCoerce.java @@ -2,6 +2,7 @@ package io.gitlab.jfronny.muscript.ast.dynamic; import io.gitlab.jfronny.muscript.ast.*; import io.gitlab.jfronny.muscript.ast.dynamic.unpack.*; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.data.dynamic.*; public class DynamicCoerce extends DynamicExpr { @@ -20,7 +21,7 @@ public class DynamicCoerce extends DynamicExpr { } @Override - public Dynamic get(Dynamic dataRoot) { + public Dynamic get(Scope dataRoot) { if (inner instanceof DynamicExpr e) return e.get(dataRoot); if (inner instanceof BoolExpr e) return DFinal.of(e.get(dataRoot)); if (inner instanceof StringExpr e) return DFinal.of(e.get(dataRoot)); diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/Get.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/Get.java index ef5c3ac..e34965d 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/Get.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/Get.java @@ -5,6 +5,7 @@ import io.gitlab.jfronny.muscript.ast.Expr; import io.gitlab.jfronny.muscript.annotations.CanThrow; import io.gitlab.jfronny.muscript.annotations.UncheckedDynamic; import io.gitlab.jfronny.muscript.compiler.Type; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.data.dynamic.*; import io.gitlab.jfronny.muscript.error.TypeMismatchException; @@ -24,7 +25,7 @@ public class Get extends DynamicExpr { } @Override - public Dynamic get(Dynamic dataRoot) { + public Dynamic get(Scope dataRoot) { Dynamic left = this.left.get(dataRoot); if (left instanceof DObject o) { return o.get(name.asStringExpr().get(dataRoot)); diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/Variable.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/Variable.java index 5a8002c..e5aec38 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/Variable.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/Variable.java @@ -1,5 +1,6 @@ package io.gitlab.jfronny.muscript.ast.dynamic; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; import io.gitlab.jfronny.muscript.ast.DynamicExpr; import io.gitlab.jfronny.muscript.annotations.CanThrow; @@ -16,8 +17,12 @@ public class Variable extends DynamicExpr { this.name = name; } + public Assign assign(DynamicExpr value) { + return new Assign(chStart, chEnd, name, value); + } + @Override - public Dynamic get(Dynamic dataRoot) { + public Dynamic get(Scope dataRoot) { if (dataRoot.asObject().has(name)) return dataRoot.asObject().get(name); else if (name.contains("::")) { Dynamic res = dataRoot; diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/unpack/BoolUnpack.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/unpack/BoolUnpack.java index d290a47..4ce2456 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/unpack/BoolUnpack.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/unpack/BoolUnpack.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.muscript.ast.dynamic.unpack; -import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.data.dynamic.DynamicTypeConversionException; import io.gitlab.jfronny.muscript.ast.BoolExpr; import io.gitlab.jfronny.muscript.ast.DynamicExpr; @@ -19,7 +19,7 @@ public class BoolUnpack extends BoolExpr { } @Override - public Boolean get(Dynamic dataRoot) { + public Boolean get(Scope dataRoot) { try { return inner.get(dataRoot).asBool().getValue(); } catch (DynamicTypeConversionException e) { diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/unpack/NumberUnpack.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/unpack/NumberUnpack.java index c2e9086..ca4e160 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/unpack/NumberUnpack.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/unpack/NumberUnpack.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.muscript.ast.dynamic.unpack; -import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.data.dynamic.DynamicTypeConversionException; import io.gitlab.jfronny.muscript.ast.DynamicExpr; import io.gitlab.jfronny.muscript.ast.NumberExpr; @@ -19,7 +19,7 @@ public class NumberUnpack extends NumberExpr { } @Override - public Double get(Dynamic dataRoot) { + public Double get(Scope dataRoot) { try { return inner.get(dataRoot).asNumber().getValue(); } catch (DynamicTypeConversionException e) { diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/unpack/StringUnpack.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/unpack/StringUnpack.java index 50ed54a..b438ba2 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/unpack/StringUnpack.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/unpack/StringUnpack.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.muscript.ast.dynamic.unpack; -import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.data.dynamic.DynamicTypeConversionException; import io.gitlab.jfronny.muscript.ast.DynamicExpr; import io.gitlab.jfronny.muscript.ast.StringExpr; @@ -19,7 +19,7 @@ public class StringUnpack extends StringExpr { } @Override - public String get(Dynamic dataRoot) { + public String get(Scope dataRoot) { try { return inner.get(dataRoot).asString().getValue(); } catch (DynamicTypeConversionException e) { diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/literal/BoolLiteral.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/literal/BoolLiteral.java index 156ad95..263100a 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/literal/BoolLiteral.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/literal/BoolLiteral.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.muscript.ast.literal; -import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.ast.BoolExpr; public final class BoolLiteral extends BoolExpr { @@ -12,7 +12,7 @@ public final class BoolLiteral extends BoolExpr { } @Override - public Boolean get(Dynamic dataRoot) { + public Boolean get(Scope dataRoot) { return value; } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/literal/DynamicLiteral.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/literal/DynamicLiteral.java index 7b4c020..08702ac 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/literal/DynamicLiteral.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/literal/DynamicLiteral.java @@ -1,5 +1,6 @@ package io.gitlab.jfronny.muscript.ast.literal; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; import io.gitlab.jfronny.muscript.ast.DynamicExpr; @@ -12,7 +13,7 @@ public final class DynamicLiteral extends DynamicExpr { } @Override - public Dynamic get(Dynamic dataRoot) { + public Dynamic get(Scope dataRoot) { return value; } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/literal/NumberLiteral.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/literal/NumberLiteral.java index b4b9430..331d1af 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/literal/NumberLiteral.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/literal/NumberLiteral.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.muscript.ast.literal; -import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.ast.NumberExpr; public final class NumberLiteral extends NumberExpr { @@ -12,7 +12,7 @@ public final class NumberLiteral extends NumberExpr { } @Override - public Double get(Dynamic dataRoot) { + public Double get(Scope dataRoot) { return value; } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/literal/StringLiteral.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/literal/StringLiteral.java index e11820e..121e075 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/literal/StringLiteral.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/literal/StringLiteral.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.muscript.ast.literal; -import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.ast.StringExpr; public final class StringLiteral extends StringExpr { @@ -12,7 +12,7 @@ public final class StringLiteral extends StringExpr { } @Override - public String get(Dynamic dataRoot) { + public String get(Scope dataRoot) { return value; } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Divide.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Divide.java index e2bb53a..85eee7d 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Divide.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Divide.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.muscript.ast.math; -import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.ast.Expr; import io.gitlab.jfronny.muscript.ast.NumberExpr; import io.gitlab.jfronny.muscript.ast.literal.NumberLiteral; @@ -16,7 +16,7 @@ public class Divide extends NumberExpr { } @Override - public Double get(Dynamic dataRoot) { + public Double get(Scope dataRoot) { return dividend.get(dataRoot) / divisor.get(dataRoot); } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Invert.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Invert.java index c6e295c..af29620 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Invert.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Invert.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.muscript.ast.math; -import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.ast.Expr; import io.gitlab.jfronny.muscript.ast.NumberExpr; import io.gitlab.jfronny.muscript.ast.literal.NumberLiteral; @@ -14,7 +14,7 @@ public class Invert extends NumberExpr { } @Override - public Double get(Dynamic dataRoot) { + public Double get(Scope dataRoot) { return -inner.get(dataRoot); } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Minus.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Minus.java index cc84a30..bc38205 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Minus.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Minus.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.muscript.ast.math; -import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.ast.Expr; import io.gitlab.jfronny.muscript.ast.NumberExpr; import io.gitlab.jfronny.muscript.ast.literal.NumberLiteral; @@ -16,7 +16,7 @@ public class Minus extends NumberExpr { } @Override - public Double get(Dynamic dataRoot) { + public Double get(Scope dataRoot) { return minuend.get(dataRoot) - subtrahend.get(dataRoot); } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Modulo.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Modulo.java index be2314e..1bf8e0a 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Modulo.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Modulo.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.muscript.ast.math; -import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.ast.Expr; import io.gitlab.jfronny.muscript.ast.NumberExpr; import io.gitlab.jfronny.muscript.ast.literal.NumberLiteral; @@ -16,7 +16,7 @@ public class Modulo extends NumberExpr { } @Override - public Double get(Dynamic dataRoot) { + public Double get(Scope dataRoot) { return dividend.get(dataRoot) % divisor.get(dataRoot); } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Multiply.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Multiply.java index 9ff988b..663462a 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Multiply.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Multiply.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.muscript.ast.math; -import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.ast.Expr; import io.gitlab.jfronny.muscript.ast.NumberExpr; import io.gitlab.jfronny.muscript.ast.literal.NumberLiteral; @@ -16,7 +16,7 @@ public class Multiply extends NumberExpr { } @Override - public Double get(Dynamic dataRoot) { + public Double get(Scope dataRoot) { return multiplier.get(dataRoot) * multiplicand.get(dataRoot); } @@ -26,7 +26,7 @@ public class Multiply extends NumberExpr { NumberExpr multiplicand = this.multiplicand.optimize(); if (multiplier instanceof NumberLiteral litEr && multiplicand instanceof NumberLiteral litAnd) return Expr.literal(chStart, chEnd, litEr.value * litAnd.value); - return new Modulo(chStart, chEnd, multiplier, multiplicand); + return new Multiply(chStart, chEnd, multiplier, multiplicand); } @Override diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Plus.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Plus.java index 16f65b5..21a3bff 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Plus.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Plus.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.muscript.ast.math; -import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.ast.Expr; import io.gitlab.jfronny.muscript.ast.NumberExpr; import io.gitlab.jfronny.muscript.ast.literal.NumberLiteral; @@ -16,7 +16,7 @@ public class Plus extends NumberExpr { } @Override - public Double get(Dynamic dataRoot) { + public Double get(Scope dataRoot) { return augend.get(dataRoot) + addend.get(dataRoot); } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Power.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Power.java index c04f950..08387c2 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Power.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/math/Power.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.muscript.ast.math; -import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.ast.Expr; import io.gitlab.jfronny.muscript.ast.NumberExpr; import io.gitlab.jfronny.muscript.ast.literal.NumberLiteral; @@ -16,7 +16,7 @@ public class Power extends NumberExpr { } @Override - public Double get(Dynamic dataRoot) { + public Double get(Scope dataRoot) { return Math.pow(base.get(dataRoot), exponent.get(dataRoot)); } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/string/Concatenate.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/string/Concatenate.java index a7de488..3647fb4 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/string/Concatenate.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/string/Concatenate.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.muscript.ast.string; -import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.ast.Expr; import io.gitlab.jfronny.muscript.ast.StringExpr; import io.gitlab.jfronny.muscript.ast.literal.StringLiteral; @@ -16,7 +16,7 @@ public class Concatenate extends StringExpr { } @Override - public String get(Dynamic dataRoot) { + public String get(Scope dataRoot) { return left.get(dataRoot) + right.get(dataRoot); } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/string/StringCoerce.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/string/StringCoerce.java index 21c2dad..de023ae 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/string/StringCoerce.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/string/StringCoerce.java @@ -1,7 +1,7 @@ package io.gitlab.jfronny.muscript.ast.string; import io.gitlab.jfronny.commons.StringFormatter; -import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; +import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.ast.*; import io.gitlab.jfronny.muscript.ast.literal.*; @@ -14,7 +14,7 @@ public class StringCoerce extends StringExpr { } @Override - public String get(Dynamic dataRoot) { + public String get(Scope dataRoot) { return StringFormatter.toString(inner.get(dataRoot)); } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Lexer.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Lexer.java index 0ce3a9b..986451b 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Lexer.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Lexer.java @@ -48,12 +48,15 @@ public class Lexer { case '=' -> { if (match('=')) createToken(Token.EqualEqual); - else unexpected(); + else createToken(Token.Assign); } case '!' -> createToken(match('=') ? Token.BangEqual : Token.Bang); case '+' -> createToken(Token.Plus); - case '-' -> createToken(Token.Minus); + case '-' -> { + if (match('>')) createToken(Token.Arrow); + else createToken(Token.Minus); + } case '*' -> createToken(Token.Star); case '/' -> createToken(Token.Slash); case '%' -> createToken(Token.Percentage); @@ -72,6 +75,8 @@ public class Lexer { case ')' -> createToken(Token.RightParen); case '[' -> createToken(Token.LeftBracket); case ']' -> createToken(Token.RightBracket); + case '{' -> createToken(Token.LeftBrace); + case '}' -> createToken(Token.RightBrace); default -> unexpected(); } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Parser.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Parser.java index 17b9af5..b14d896 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Parser.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Parser.java @@ -7,10 +7,11 @@ import io.gitlab.jfronny.muscript.ast.conditional.UnresolvedConditional; import io.gitlab.jfronny.muscript.ast.dynamic.*; import io.gitlab.jfronny.muscript.ast.math.*; import io.gitlab.jfronny.muscript.ast.string.Concatenate; +import io.gitlab.jfronny.muscript.data.Script; import io.gitlab.jfronny.muscript.error.*; -import java.util.ArrayList; -import java.util.List; +import java.text.ParseException; +import java.util.*; public class Parser { private final Lexer lexer; @@ -22,6 +23,10 @@ public class Parser { return new Parser(new Lexer(source)).parse().optimize(); } + public static Script parseScript(String source) { + return new Parser(new Lexer(source)).parseScript().optimize(); + } + public Parser(Lexer lexer) { this.lexer = lexer; } @@ -35,15 +40,31 @@ public class Parser { public Expr parse() { advance(); Expr expr = expression(); - if (!lexer.token.equals(Token.EOF)) + if (!isAtEnd()) throw new ParseException(LocationalError.create(lexer.source, lexer.start, lexer.current - 1, "Unexpected element after end of expression")); return expr; } + /** + * Generate a script instance. + * Multiple instructions will be executed in sequence and the result of the last one will be returned. + * + * @return the resulting expression + */ + public Script parseScript() { + advance(); + List> expressions = new LinkedList<>(); + while (!isAtEnd()) { + expressions.add(expression()); + } + if (expressions.isEmpty()) throw new ParseException(LocationalError.create(lexer.source, lexer.start, lexer.current - 1, "Missing any elements in closure")); + return new Script(expressions); + } + // Expressions private Expr expression() { try { - return conditional(); + return assignment(); } catch (RuntimeException e) { if (e instanceof ParseException) throw e; else if (e instanceof LocationalException le) { @@ -52,6 +73,20 @@ public class Parser { } } + private Expr assignment() { + Expr expr = conditional(); + + if (match(Token.Assign)) { + if (expr instanceof Variable variable) { + expr = variable.assign(expression().asDynamicExpr()); + } else { + throw error("Attempted to assign non-variable. This is not supported!", expr); + } + } + + return expr; + } + private Expr conditional() { Expr expr = and(); @@ -258,6 +293,24 @@ public class Parser { return expr; } + if (match(Token.LeftBrace)) { + int start = previous.start; + List boundArgs = new LinkedList<>(); + boolean first = true; + while (!match(Token.Arrow)) { + if (!first) consume(Token.Comma, "Closure parameters MUST be comma-seperated"); + first = false; + consume(Token.Identifier, "Closure arguments MUST be identifiers"); + boundArgs.add(previous.lexeme); + } + List> expressions = new LinkedList<>(); + while (!match(Token.RightBrace)) { + expressions.add(expression()); + } + int end = previous.start; + return new Closure(start, end, boundArgs, expressions); + } + throw error("Expected expression."); } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Token.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Token.java index 27a2b2c..22919e3 100644 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Token.java +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/compiler/Token.java @@ -7,6 +7,7 @@ public enum Token { True, False, And, Or, + Assign, EqualEqual, BangEqual, Concat, @@ -23,5 +24,8 @@ public enum Token { LeftParen, RightParen, LeftBracket, RightBracket, + LeftBrace, RightBrace, + Arrow, + Error, EOF } diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/data/ExpressionParameter.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/data/ExpressionParameter.java deleted file mode 100644 index c58264d..0000000 --- a/muscript/src/main/java/io/gitlab/jfronny/muscript/data/ExpressionParameter.java +++ /dev/null @@ -1,23 +0,0 @@ -package io.gitlab.jfronny.muscript.data; - -import io.gitlab.jfronny.muscript.data.dynamic.DObject; -import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; - -import java.util.HashMap; -import java.util.Map; - -public record ExpressionParameter(Map> value) implements DObject { - public ExpressionParameter() { - this(new HashMap<>()); - } - - @Override - public Map> getValue() { - return value; - } - - public ExpressionParameter set(String key, Dynamic value) { - this.value.put(key, value); - return this; - } -} diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/data/Scope.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/data/Scope.java new file mode 100644 index 0000000..ecc7d0e --- /dev/null +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/data/Scope.java @@ -0,0 +1,36 @@ +package io.gitlab.jfronny.muscript.data; + +import io.gitlab.jfronny.commons.data.ImmCollection; +import io.gitlab.jfronny.muscript.data.dynamic.*; + +import java.util.HashMap; +import java.util.Map; + +public class Scope implements DObject { + private final DObject source; + private final Map> override = new HashMap<>(); + + public Scope() { + this(DFinal.of(Map.of())); + } + + public Scope(DObject source) { + this.source = source; + } + + @Override + public Map> getValue() { + var map = new HashMap<>(source.getValue()); + map.putAll(override); + return ImmCollection.of(map); + } + + public Scope set(String key, Dynamic value) { + override.put(key, value); + return this; + } + + public Scope fork() { + return new Scope(this); + } +} diff --git a/muscript/src/main/java/io/gitlab/jfronny/muscript/data/Script.java b/muscript/src/main/java/io/gitlab/jfronny/muscript/data/Script.java new file mode 100644 index 0000000..95eab69 --- /dev/null +++ b/muscript/src/main/java/io/gitlab/jfronny/muscript/data/Script.java @@ -0,0 +1,43 @@ +package io.gitlab.jfronny.muscript.data; + +import io.gitlab.jfronny.muscript.ast.DynamicExpr; +import io.gitlab.jfronny.muscript.ast.Expr; +import io.gitlab.jfronny.muscript.data.dynamic.*; + +import java.util.List; + +public class Script { + private final List> steps; + private final DynamicExpr fin; + + public Script(List> expressions) { + this(expressions.subList(0, expressions.size() - 1), expressions.get(expressions.size() - 1).asDynamicExpr()); + } + + private Script(List> steps, DynamicExpr fin) { + this.steps = steps; + this.fin = fin; + } + + public Dynamic run(DObject scope) { + return run(new Scope(scope)); + } + + public Dynamic run(Scope scope) { + for (Expr expression : steps) { + expression.get(scope); + } + return fin.get(scope); + } + + public DCallable bindTo(Scope scope) { + return DFinal.of(args -> { + scope.set("args", args); + return run(scope); + }); + } + + public Script optimize() { + return new Script(steps.stream().>map(Expr::optimize).toList(), fin.optimize()); + } +} diff --git a/muscript/src/test/java/io/gitlab/jfronny/muscript/test/AssignTest.java b/muscript/src/test/java/io/gitlab/jfronny/muscript/test/AssignTest.java new file mode 100644 index 0000000..e55be50 --- /dev/null +++ b/muscript/src/test/java/io/gitlab/jfronny/muscript/test/AssignTest.java @@ -0,0 +1,22 @@ +package io.gitlab.jfronny.muscript.test; + +import io.gitlab.jfronny.muscript.ast.StringExpr; +import io.gitlab.jfronny.muscript.ast.dynamic.Assign; +import io.gitlab.jfronny.muscript.ast.literal.StringLiteral; +import io.gitlab.jfronny.muscript.compiler.Parser; +import io.gitlab.jfronny.muscript.data.Scope; +import io.gitlab.jfronny.muscript.test.util.UnforkableScope; +import org.junit.jupiter.api.*; + +import static org.junit.jupiter.api.Assertions.*; + +class AssignTest { + @Test + void testAssignSimple() { + StringExpr expr = Parser.parse("someval = 'test'").asStringExpr(); + assertEquals(new Assign(0, 6, "someval", new StringLiteral(10, 15, "test").asDynamicExpr()).asStringExpr(), expr); + Scope scope = new UnforkableScope(); + assertEquals("test", expr.get(scope)); + assertEquals("test", scope.getValue().get("someval").asString().getValue()); + } +} diff --git a/muscript/src/test/java/io/gitlab/jfronny/muscript/test/BooleanTest.java b/muscript/src/test/java/io/gitlab/jfronny/muscript/test/BooleanTest.java index 88b9b7e..0b5b1cc 100644 --- a/muscript/src/test/java/io/gitlab/jfronny/muscript/test/BooleanTest.java +++ b/muscript/src/test/java/io/gitlab/jfronny/muscript/test/BooleanTest.java @@ -2,7 +2,7 @@ package io.gitlab.jfronny.muscript.test; import org.junit.jupiter.api.*; -import static io.gitlab.jfronny.muscript.test.MuTestUtil.*; +import static io.gitlab.jfronny.muscript.test.util.MuTestUtil.*; import static org.junit.jupiter.api.Assertions.*; class BooleanTest { diff --git a/muscript/src/test/java/io/gitlab/jfronny/muscript/test/CallableTest.java b/muscript/src/test/java/io/gitlab/jfronny/muscript/test/CallableTest.java index 84a56aa..1974236 100644 --- a/muscript/src/test/java/io/gitlab/jfronny/muscript/test/CallableTest.java +++ b/muscript/src/test/java/io/gitlab/jfronny/muscript/test/CallableTest.java @@ -2,7 +2,7 @@ package io.gitlab.jfronny.muscript.test; import org.junit.jupiter.api.*; -import static io.gitlab.jfronny.muscript.test.MuTestUtil.*; +import static io.gitlab.jfronny.muscript.test.util.MuTestUtil.*; import static org.junit.jupiter.api.Assertions.*; class CallableTest { diff --git a/muscript/src/test/java/io/gitlab/jfronny/muscript/test/ClosureTest.java b/muscript/src/test/java/io/gitlab/jfronny/muscript/test/ClosureTest.java new file mode 100644 index 0000000..ff3198f --- /dev/null +++ b/muscript/src/test/java/io/gitlab/jfronny/muscript/test/ClosureTest.java @@ -0,0 +1,22 @@ +package io.gitlab.jfronny.muscript.test; + +import io.gitlab.jfronny.muscript.compiler.Parser; +import org.junit.jupiter.api.*; + +import static io.gitlab.jfronny.muscript.test.util.MuTestUtil.*; +import static org.junit.jupiter.api.Assertions.*; + +class ClosureTest { + @Test + void testScript() { + assertEquals(8, Parser.parseScript("function(2, 1) function(2, 2) function(2, 3)").run(makeArgs()).asNumber().getValue()); + } + + @Test + void testClosure() { + assertEquals(2, number("{->2}()")); + assertEquals(2, number("{n->n}(2)")); + assertEquals(2, number("{n->n()}({->2})")); + assertEquals(2, number("{->num = 2 num = num * 2 num = num - 2}()")); + } +} diff --git a/muscript/src/test/java/io/gitlab/jfronny/muscript/test/CombinationTest.java b/muscript/src/test/java/io/gitlab/jfronny/muscript/test/CombinationTest.java index d4f0fc8..6e5021d 100644 --- a/muscript/src/test/java/io/gitlab/jfronny/muscript/test/CombinationTest.java +++ b/muscript/src/test/java/io/gitlab/jfronny/muscript/test/CombinationTest.java @@ -2,7 +2,7 @@ package io.gitlab.jfronny.muscript.test; import org.junit.jupiter.api.*; -import static io.gitlab.jfronny.muscript.test.MuTestUtil.*; +import static io.gitlab.jfronny.muscript.test.util.MuTestUtil.*; import static org.junit.jupiter.api.Assertions.*; class CombinationTest { diff --git a/muscript/src/test/java/io/gitlab/jfronny/muscript/test/ListTest.java b/muscript/src/test/java/io/gitlab/jfronny/muscript/test/ListTest.java index 6115f27..fc7cdbd 100644 --- a/muscript/src/test/java/io/gitlab/jfronny/muscript/test/ListTest.java +++ b/muscript/src/test/java/io/gitlab/jfronny/muscript/test/ListTest.java @@ -2,7 +2,7 @@ package io.gitlab.jfronny.muscript.test; import org.junit.jupiter.api.*; -import static io.gitlab.jfronny.muscript.test.MuTestUtil.*; +import static io.gitlab.jfronny.muscript.test.util.MuTestUtil.*; import static org.junit.jupiter.api.Assertions.*; class ListTest { diff --git a/muscript/src/test/java/io/gitlab/jfronny/muscript/test/LocationalErrorTest.java b/muscript/src/test/java/io/gitlab/jfronny/muscript/test/LocationalErrorTest.java index 6d3d0d7..26424ab 100644 --- a/muscript/src/test/java/io/gitlab/jfronny/muscript/test/LocationalErrorTest.java +++ b/muscript/src/test/java/io/gitlab/jfronny/muscript/test/LocationalErrorTest.java @@ -18,10 +18,5 @@ class LocationalErrorTest { 1 | 15 + 'yes' ^---^-- Here""", assertThrows(Parser.ParseException.class, () -> Parser.parse("15 + 'yes'")).error.toString()); - assertEquals(""" - Error at '=' (character 9): Unexpected character - 1 | string = 'Value' - ^-- Here""", - assertThrows(Parser.ParseException.class, () -> Parser.parse("string = 'Value'")).error.toString()); } } diff --git a/muscript/src/test/java/io/gitlab/jfronny/muscript/test/NumberTest.java b/muscript/src/test/java/io/gitlab/jfronny/muscript/test/NumberTest.java index 345e246..863ef9e 100644 --- a/muscript/src/test/java/io/gitlab/jfronny/muscript/test/NumberTest.java +++ b/muscript/src/test/java/io/gitlab/jfronny/muscript/test/NumberTest.java @@ -2,7 +2,7 @@ package io.gitlab.jfronny.muscript.test; import org.junit.jupiter.api.*; -import static io.gitlab.jfronny.muscript.test.MuTestUtil.*; +import static io.gitlab.jfronny.muscript.test.util.MuTestUtil.*; import static org.junit.jupiter.api.Assertions.*; class NumberTest { diff --git a/muscript/src/test/java/io/gitlab/jfronny/muscript/test/ObjectTest.java b/muscript/src/test/java/io/gitlab/jfronny/muscript/test/ObjectTest.java index 9a40347..f533878 100644 --- a/muscript/src/test/java/io/gitlab/jfronny/muscript/test/ObjectTest.java +++ b/muscript/src/test/java/io/gitlab/jfronny/muscript/test/ObjectTest.java @@ -2,7 +2,7 @@ package io.gitlab.jfronny.muscript.test; import org.junit.jupiter.api.*; -import static io.gitlab.jfronny.muscript.test.MuTestUtil.*; +import static io.gitlab.jfronny.muscript.test.util.MuTestUtil.*; import static org.junit.jupiter.api.Assertions.*; class ObjectTest { diff --git a/muscript/src/test/java/io/gitlab/jfronny/muscript/test/StringTest.java b/muscript/src/test/java/io/gitlab/jfronny/muscript/test/StringTest.java index 16c64c8..7ac155f 100644 --- a/muscript/src/test/java/io/gitlab/jfronny/muscript/test/StringTest.java +++ b/muscript/src/test/java/io/gitlab/jfronny/muscript/test/StringTest.java @@ -2,7 +2,7 @@ package io.gitlab.jfronny.muscript.test; import org.junit.jupiter.api.*; -import static io.gitlab.jfronny.muscript.test.MuTestUtil.*; +import static io.gitlab.jfronny.muscript.test.util.MuTestUtil.*; import static org.junit.jupiter.api.Assertions.*; class StringTest { diff --git a/muscript/src/test/java/io/gitlab/jfronny/muscript/test/MuTestUtil.java b/muscript/src/test/java/io/gitlab/jfronny/muscript/test/util/MuTestUtil.java similarity index 93% rename from muscript/src/test/java/io/gitlab/jfronny/muscript/test/MuTestUtil.java rename to muscript/src/test/java/io/gitlab/jfronny/muscript/test/util/MuTestUtil.java index fb002a9..6ad5ba0 100644 --- a/muscript/src/test/java/io/gitlab/jfronny/muscript/test/MuTestUtil.java +++ b/muscript/src/test/java/io/gitlab/jfronny/muscript/test/util/MuTestUtil.java @@ -1,5 +1,6 @@ -package io.gitlab.jfronny.muscript.test; +package io.gitlab.jfronny.muscript.test.util; +import io.gitlab.jfronny.muscript.data.dynamic.DObject; import io.gitlab.jfronny.muscript.data.dynamic.Dynamic; import io.gitlab.jfronny.muscript.compiler.Parser; import io.gitlab.jfronny.muscript.ast.Expr; @@ -32,7 +33,7 @@ public class MuTestUtil { return Parser.parse(source).asStringExpr().get(makeArgs()); } - public static Dynamic makeArgs() { + public static DObject makeArgs() { return of(Map.of( "boolean", of(true), "number", of(15), diff --git a/muscript/src/test/java/io/gitlab/jfronny/muscript/test/util/UnforkableScope.java b/muscript/src/test/java/io/gitlab/jfronny/muscript/test/util/UnforkableScope.java new file mode 100644 index 0000000..049f14b --- /dev/null +++ b/muscript/src/test/java/io/gitlab/jfronny/muscript/test/util/UnforkableScope.java @@ -0,0 +1,10 @@ +package io.gitlab.jfronny.muscript.test.util; + +import io.gitlab.jfronny.muscript.data.Scope; + +public class UnforkableScope extends Scope { + @Override + public Scope fork() { + return this; + } +} diff --git a/src/main/java/io/gitlab/jfronny/commons/data/ImmCollection.java b/src/main/java/io/gitlab/jfronny/commons/data/ImmCollection.java new file mode 100644 index 0000000..296a4e6 --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/commons/data/ImmCollection.java @@ -0,0 +1,35 @@ +package io.gitlab.jfronny.commons.data; + +import io.gitlab.jfronny.commons.data.immutable.*; + +import java.util.*; + +public class ImmCollection { + public static Collection of(Collection collection) { + return new ImmutableCollection<>(collection); + } + + public static List of(List list) { + return new ImmutableList<>(list); + } + + public static Set of(Set set) { + return new ImmutableSet<>(set); + } + + public static Map of(Map map) { + return new ImmutableMap<>(map); + } + + public static Iterable of(Iterable iterable) { + return new ImmutableIterable<>(iterable); + } + + public static Iterator of(Iterator iterator) { + return new ImmutableIterator<>(iterator); + } + + public static ListIterator of(ListIterator listIterator) { + return new ImmutableListIterator<>(listIterator); + } +} diff --git a/src/main/java/io/gitlab/jfronny/commons/data/immutable/ImmutableCollection.java b/src/main/java/io/gitlab/jfronny/commons/data/immutable/ImmutableCollection.java new file mode 100644 index 0000000..0ac220f --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/commons/data/immutable/ImmutableCollection.java @@ -0,0 +1,96 @@ +package io.gitlab.jfronny.commons.data.immutable; + +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.function.IntFunction; +import java.util.function.Predicate; +import java.util.stream.Stream; + +public class ImmutableCollection> extends ImmutableIterable implements Collection { + public ImmutableCollection(S delegate) { + super(delegate); + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return delegate.contains(o); + } + + @NotNull + @Override + public Object @NotNull [] toArray() { + return delegate.toArray(); + } + + @NotNull + @Override + public T1 @NotNull [] toArray(@NotNull T1 @NotNull [] t1s) { + return delegate.toArray(t1s); + } + + @Override + public T1[] toArray(IntFunction generator) { + return delegate.toArray(generator); + } + + @Override + public boolean add(T t) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean containsAll(@NotNull Collection collection) { + return delegate.containsAll(collection); + } + + @Override + public boolean addAll(@NotNull Collection collection) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeAll(@NotNull Collection collection) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeIf(Predicate filter) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean retainAll(@NotNull Collection collection) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public Stream stream() { + return delegate.stream(); + } + + @Override + public Stream parallelStream() { + return delegate.parallelStream(); + } +} diff --git a/src/main/java/io/gitlab/jfronny/commons/data/immutable/ImmutableIterable.java b/src/main/java/io/gitlab/jfronny/commons/data/immutable/ImmutableIterable.java new file mode 100644 index 0000000..2742ff3 --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/commons/data/immutable/ImmutableIterable.java @@ -0,0 +1,30 @@ +package io.gitlab.jfronny.commons.data.immutable; + +import io.gitlab.jfronny.commons.data.ImmCollection; +import org.jetbrains.annotations.NotNull; + +import java.util.Iterator; +import java.util.Spliterator; +import java.util.function.Consumer; + +public class ImmutableIterable> extends ImmutableObject implements Iterable { + public ImmutableIterable(S delegate) { + super(delegate); + } + + @NotNull + @Override + public Iterator iterator() { + return ImmCollection.of(delegate.iterator()); + } + + @Override + public void forEach(Consumer action) { + delegate.forEach(action); + } + + @Override + public Spliterator spliterator() { + return delegate.spliterator(); + } +} diff --git a/src/main/java/io/gitlab/jfronny/commons/data/immutable/ImmutableIterator.java b/src/main/java/io/gitlab/jfronny/commons/data/immutable/ImmutableIterator.java new file mode 100644 index 0000000..9d9b808 --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/commons/data/immutable/ImmutableIterator.java @@ -0,0 +1,30 @@ +package io.gitlab.jfronny.commons.data.immutable; + +import java.util.Iterator; +import java.util.function.Consumer; + +public class ImmutableIterator> extends ImmutableObject implements Iterator { + public ImmutableIterator(S delegate) { + super(delegate); + } + + @Override + public boolean hasNext() { + return delegate.hasNext(); + } + + @Override + public T next() { + return delegate.next(); + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + @Override + public void forEachRemaining(Consumer action) { + delegate.forEachRemaining(action); + } +} diff --git a/src/main/java/io/gitlab/jfronny/commons/data/immutable/ImmutableList.java b/src/main/java/io/gitlab/jfronny/commons/data/immutable/ImmutableList.java new file mode 100644 index 0000000..0cbeb85 --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/commons/data/immutable/ImmutableList.java @@ -0,0 +1,76 @@ +package io.gitlab.jfronny.commons.data.immutable; + +import io.gitlab.jfronny.commons.data.ImmCollection; +import org.jetbrains.annotations.NotNull; + +import java.util.*; +import java.util.function.UnaryOperator; + +public class ImmutableList> extends ImmutableCollection implements List { + public ImmutableList(S delegate) { + super(delegate); + } + + @Override + public boolean addAll(int i, @NotNull Collection collection) { + throw new UnsupportedOperationException(); + } + + @Override + public void replaceAll(UnaryOperator operator) { + throw new UnsupportedOperationException(); + } + + @Override + public void sort(Comparator c) { + throw new UnsupportedOperationException(); + } + + @Override + public T get(int i) { + return delegate.get(i); + } + + @Override + public T set(int i, T t) { + throw new UnsupportedOperationException(); + } + + @Override + public void add(int i, T t) { + throw new UnsupportedOperationException(); + } + + @Override + public T remove(int i) { + throw new UnsupportedOperationException(); + } + + @Override + public int indexOf(Object o) { + return delegate.indexOf(o); + } + + @Override + public int lastIndexOf(Object o) { + return delegate.lastIndexOf(o); + } + + @NotNull + @Override + public ListIterator listIterator() { + return ImmCollection.of(delegate.listIterator()); + } + + @NotNull + @Override + public ListIterator listIterator(int i) { + return ImmCollection.of(delegate.listIterator(i)); + } + + @NotNull + @Override + public List subList(int i, int i1) { + return ImmCollection.of(delegate.subList(i, i1)); + } +} diff --git a/src/main/java/io/gitlab/jfronny/commons/data/immutable/ImmutableListIterator.java b/src/main/java/io/gitlab/jfronny/commons/data/immutable/ImmutableListIterator.java new file mode 100644 index 0000000..1e3b631 --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/commons/data/immutable/ImmutableListIterator.java @@ -0,0 +1,39 @@ +package io.gitlab.jfronny.commons.data.immutable; + +import java.util.ListIterator; + +public class ImmutableListIterator> extends ImmutableIterator implements ListIterator { + public ImmutableListIterator(S delegate) { + super(delegate); + } + + @Override + public boolean hasPrevious() { + return delegate.hasPrevious(); + } + + @Override + public T previous() { + return delegate.previous(); + } + + @Override + public int nextIndex() { + return delegate.nextIndex(); + } + + @Override + public int previousIndex() { + return delegate.previousIndex(); + } + + @Override + public void set(T t) { + throw new UnsupportedOperationException(); + } + + @Override + public void add(T t) { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/io/gitlab/jfronny/commons/data/immutable/ImmutableMap.java b/src/main/java/io/gitlab/jfronny/commons/data/immutable/ImmutableMap.java new file mode 100644 index 0000000..540072a --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/commons/data/immutable/ImmutableMap.java @@ -0,0 +1,137 @@ +package io.gitlab.jfronny.commons.data.immutable; + +import io.gitlab.jfronny.commons.data.ImmCollection; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.function.*; + +public class ImmutableMap extends ImmutableObject> implements Map { + public ImmutableMap(Map delegate) { + super(delegate); + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public boolean containsKey(Object o) { + return delegate.containsKey(o); + } + + @Override + public boolean containsValue(Object o) { + return delegate.containsValue(o); + } + + @Override + public V get(Object o) { + return delegate.get(o); + } + + @Nullable + @Override + public V put(K k, V v) { + throw new UnsupportedOperationException(); + } + + @Override + public V remove(Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public void putAll(@NotNull Map map) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @NotNull + @Override + public Set keySet() { + return ImmCollection.of(delegate.keySet()); + } + + @NotNull + @Override + public Collection values() { + return ImmCollection.of(delegate.values()); + } + + @NotNull + @Override + public Set> entrySet() { + return ImmCollection.of(delegate.entrySet()); + } + + @Override + public V getOrDefault(Object key, V defaultValue) { + return delegate.getOrDefault(key, defaultValue); + } + + @Override + public void forEach(BiConsumer action) { + delegate.forEach(action); + } + + @Override + public void replaceAll(BiFunction function) { + throw new UnsupportedOperationException(); + } + + @Nullable + @Override + public V putIfAbsent(K key, V value) { + if (containsKey(key)) return get(key); + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(Object key, Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean replace(K key, V oldValue, V newValue) { + throw new UnsupportedOperationException(); + } + + @Nullable + @Override + public V replace(K key, V value) { + throw new UnsupportedOperationException(); + } + + @Override + public V computeIfAbsent(K key, @NotNull Function mappingFunction) { + if (containsKey(key)) return get(key); + throw new UnsupportedOperationException(); + } + + @Override + public V computeIfPresent(K key, @NotNull BiFunction remappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public V compute(K key, @NotNull BiFunction remappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public V merge(K key, @NotNull V value, @NotNull BiFunction remappingFunction) { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/io/gitlab/jfronny/commons/data/immutable/ImmutableObject.java b/src/main/java/io/gitlab/jfronny/commons/data/immutable/ImmutableObject.java new file mode 100644 index 0000000..cc30914 --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/commons/data/immutable/ImmutableObject.java @@ -0,0 +1,24 @@ +package io.gitlab.jfronny.commons.data.immutable; + +public class ImmutableObject { + protected final S delegate; + + public ImmutableObject(S delegate) { + this.delegate = delegate; + } + + @Override + public int hashCode() { + return delegate.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof ImmutableObject ob ? delegate.equals(ob.delegate) : delegate.equals(obj); + } + + @Override + public String toString() { + return delegate.toString(); + } +} diff --git a/src/main/java/io/gitlab/jfronny/commons/data/immutable/ImmutableSet.java b/src/main/java/io/gitlab/jfronny/commons/data/immutable/ImmutableSet.java new file mode 100644 index 0000000..96a002b --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/commons/data/immutable/ImmutableSet.java @@ -0,0 +1,15 @@ +package io.gitlab.jfronny.commons.data.immutable; + +import java.util.Set; + +public class ImmutableSet> extends ImmutableCollection implements Set { + public static class Simple extends ImmutableSet> { + public Simple(Set delegate) { + super(delegate); + } + } + + public ImmutableSet(S delegate) { + super(delegate); + } +}