perf: extract side effects of top-level expressions
ci/woodpecker/push/woodpecker Pipeline failed Details

This commit is contained in:
Johannes Frohnmeyer 2023-09-21 14:10:41 +02:00
parent e62d93f145
commit 79d862da6c
Signed by: Johannes
GPG Key ID: E76429612C2929F4
43 changed files with 475 additions and 21 deletions

View File

@ -9,6 +9,8 @@ import io.gitlab.jfronny.muscript.data.dynamic.DObject;
import io.gitlab.jfronny.muscript.data.dynamic.Dynamic;
import io.gitlab.jfronny.muscript.error.TypeMismatchException;
import java.util.stream.Stream;
@CanThrow
public abstract sealed class Expr<T> extends Decompilable
permits BoolExpr, DynamicExpr, NullLiteral, NumberExpr, StringExpr {
@ -46,6 +48,8 @@ public abstract sealed class Expr<T> extends Decompilable
public abstract DynamicExpr asDynamicExpr();
public abstract Stream<Expr<?>> extractSideEffects();
public boolean isNull() {
return this instanceof NullLiteral;
}

View File

@ -8,6 +8,7 @@ import io.gitlab.jfronny.muscript.ast.literal.DynamicLiteral;
import io.gitlab.jfronny.muscript.error.LocationalException;
import java.io.IOException;
import java.util.stream.Stream;
@CanThrow
public final class NullLiteral extends Expr<Object> {
@ -40,6 +41,11 @@ public final class NullLiteral extends Expr<Object> {
return new DynamicLiteral<>(location, new DNull());
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return Stream.empty();
}
@Override
public NumberExpr asNumberExpr() {
throw new LocationalException(location, "Attempted to convert null to a number");

View File

@ -7,6 +7,7 @@ import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.ast.literal.BoolLiteral;
import java.io.IOException;
import java.util.stream.Stream;
public class And extends BoolExpr {
private final BoolExpr left;
@ -32,6 +33,11 @@ public class And extends BoolExpr {
return new And(location, left, right);
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return Stream.concat(left.extractSideEffects(), right.extractSideEffects());
}
@Override
public void decompile(ExprWriter writer) throws IOException {
parenthesize(left, writer, false);

View File

@ -10,6 +10,7 @@ import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.ast.literal.BoolLiteral;
import java.io.IOException;
import java.util.stream.Stream;
public class Not extends BoolExpr {
public final BoolExpr inner;
@ -32,6 +33,11 @@ public class Not extends BoolExpr {
return new Not(location, inner);
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return inner.extractSideEffects();
}
@Override
public void decompile(ExprWriter writer) throws IOException {
if (inner instanceof Equal eq) {

View File

@ -7,6 +7,7 @@ import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.ast.literal.BoolLiteral;
import java.io.IOException;
import java.util.stream.Stream;
public class Or extends BoolExpr {
private final BoolExpr left;
@ -32,6 +33,11 @@ public class Or extends BoolExpr {
return new Or(location, left, right);
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return Stream.concat(left.extractSideEffects(), right.extractSideEffects());
}
@Override
public void decompile(ExprWriter writer) throws IOException {
parenthesize(left, writer, false);

View File

@ -8,6 +8,7 @@ import io.gitlab.jfronny.muscript.data.dynamic.Dynamic;
import java.io.IOException;
import java.util.Objects;
import java.util.stream.Stream;
public class Equal extends BoolExpr {
public final Expr<?> left;
@ -37,6 +38,11 @@ public class Equal extends BoolExpr {
return new Equal(location, left, right);
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return Stream.concat(left.extractSideEffects(), right.extractSideEffects());
}
@Override
public void decompile(ExprWriter writer) throws IOException {
parenthesize(left, writer, false);

View File

@ -7,6 +7,7 @@ import io.gitlab.jfronny.muscript.ast.literal.NumberLiteral;
import io.gitlab.jfronny.muscript.ast.math.*;
import java.io.IOException;
import java.util.stream.Stream;
public class Greater extends BoolExpr {
public final NumberExpr left;
@ -43,6 +44,11 @@ public class Greater extends BoolExpr {
return new Greater(location, left, right);
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return Stream.concat(left.extractSideEffects(), right.extractSideEffects());
}
@Override
public void decompile(ExprWriter writer) throws IOException {
if (left instanceof NumberLiteral && !(right instanceof NumberLiteral)) {

View File

@ -1,12 +1,16 @@
package io.gitlab.jfronny.muscript.ast.conditional;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.ast.bool.Not;
import io.gitlab.jfronny.muscript.ast.dynamic.ExprGroup;
import io.gitlab.jfronny.muscript.compiler.*;
import io.gitlab.jfronny.muscript.data.Scope;
import io.gitlab.jfronny.muscript.ast.BoolExpr;
import io.gitlab.jfronny.muscript.ast.literal.BoolLiteral;
import java.io.IOException;
import java.util.List;
import java.util.stream.Stream;
public class BoolConditional extends BoolExpr {
public final BoolExpr condition;
@ -36,6 +40,11 @@ public class BoolConditional extends BoolExpr {
return new BoolConditional(location, condition, trueExpr, falseExpr);
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return UnresolvedConditional.extractSideEffects(location, condition, trueExpr, falseExpr);
}
@Override
public void decompile(ExprWriter writer) throws IOException {
parenthesize(condition, writer, true);

View File

@ -1,6 +1,8 @@
package io.gitlab.jfronny.muscript.ast.conditional;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.ast.bool.Not;
import io.gitlab.jfronny.muscript.ast.dynamic.ExprGroup;
import io.gitlab.jfronny.muscript.compiler.*;
import io.gitlab.jfronny.muscript.data.Scope;
import io.gitlab.jfronny.muscript.data.dynamic.Dynamic;
@ -9,6 +11,8 @@ import io.gitlab.jfronny.muscript.ast.DynamicExpr;
import io.gitlab.jfronny.muscript.ast.literal.BoolLiteral;
import java.io.IOException;
import java.util.List;
import java.util.stream.Stream;
public class DynamicConditional extends DynamicExpr {
public final BoolExpr condition;
@ -38,6 +42,11 @@ public class DynamicConditional extends DynamicExpr {
return new DynamicConditional(location, condition, trueExpr, falseExpr);
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return UnresolvedConditional.extractSideEffects(location, condition, trueExpr, falseExpr);
}
@Override
public void decompile(ExprWriter writer) throws IOException {
parenthesize(condition, writer, true);

View File

@ -1,5 +1,6 @@
package io.gitlab.jfronny.muscript.ast.conditional;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.ast.bool.Not;
import io.gitlab.jfronny.muscript.compiler.*;
import io.gitlab.jfronny.muscript.data.Scope;
@ -8,6 +9,7 @@ import io.gitlab.jfronny.muscript.ast.NumberExpr;
import io.gitlab.jfronny.muscript.ast.literal.BoolLiteral;
import java.io.IOException;
import java.util.stream.Stream;
public class NumberConditional extends NumberExpr {
public final BoolExpr condition;
@ -37,6 +39,11 @@ public class NumberConditional extends NumberExpr {
return new NumberConditional(location, condition, trueExpr, falseExpr);
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return UnresolvedConditional.extractSideEffects(location, condition, trueExpr, falseExpr);
}
@Override
public void decompile(ExprWriter writer) throws IOException {
parenthesize(condition, writer, true);

View File

@ -1,5 +1,6 @@
package io.gitlab.jfronny.muscript.ast.conditional;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.ast.bool.Not;
import io.gitlab.jfronny.muscript.compiler.*;
import io.gitlab.jfronny.muscript.data.Scope;
@ -8,6 +9,7 @@ import io.gitlab.jfronny.muscript.ast.StringExpr;
import io.gitlab.jfronny.muscript.ast.literal.BoolLiteral;
import java.io.IOException;
import java.util.stream.Stream;
public class StringConditional extends StringExpr {
public final BoolExpr condition;
@ -37,6 +39,11 @@ public class StringConditional extends StringExpr {
return new StringConditional(location, condition, trueExpr, falseExpr);
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return UnresolvedConditional.extractSideEffects(location, condition, trueExpr, falseExpr);
}
@Override
public void decompile(ExprWriter writer) throws IOException {
parenthesize(condition, writer, true);

View File

@ -1,6 +1,7 @@
package io.gitlab.jfronny.muscript.ast.conditional;
import io.gitlab.jfronny.muscript.ast.bool.Not;
import io.gitlab.jfronny.muscript.ast.dynamic.ExprGroup;
import io.gitlab.jfronny.muscript.compiler.*;
import io.gitlab.jfronny.muscript.data.Scope;
import io.gitlab.jfronny.muscript.data.dynamic.DNull;
@ -10,6 +11,8 @@ import io.gitlab.jfronny.muscript.annotations.CanThrow;
import io.gitlab.jfronny.muscript.ast.literal.BoolLiteral;
import java.io.IOException;
import java.util.List;
import java.util.stream.Stream;
@CanThrow
public class UnresolvedConditional extends DynamicExpr {
@ -63,6 +66,23 @@ public class UnresolvedConditional extends DynamicExpr {
return new DynamicConditional(location, condition, trueExpr.asDynamicExpr(), falseExpr.asDynamicExpr());
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return extractSideEffects(location, condition, trueExpr, falseExpr);
}
public static Stream<Expr<?>> extractSideEffects(CodeLocation location, BoolExpr condition, Expr<?> trueExpr, Expr<?> falseExpr) {
List<Expr<?>> trueSE = trueExpr.extractSideEffects().toList();
List<Expr<?>> falseSE = falseExpr.extractSideEffects().toList();
if (trueSE.isEmpty() && falseSE.isEmpty()) return condition.extractSideEffects();
return Stream.of(new UnresolvedConditional(
location,
condition,
ExprGroup.of(trueExpr.location, trueSE, false),
ExprGroup.of(falseExpr.location, falseSE, false)
));
}
@Override
public BoolExpr asBoolExpr() {
return new BoolConditional(location, condition, trueExpr.asBoolExpr(), falseExpr.asBoolExpr());

View File

@ -1,6 +1,7 @@
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.compiler.*;
import io.gitlab.jfronny.muscript.data.Scope;
import io.gitlab.jfronny.muscript.data.dynamic.additional.DFinal;
@ -9,6 +10,7 @@ import io.gitlab.jfronny.muscript.data.dynamic.Dynamic;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Stream;
public class Bind extends DynamicExpr {
public final DynamicExpr callable;
@ -49,4 +51,9 @@ public class Bind extends DynamicExpr {
public DynamicExpr optimize() {
return new Bind(location, callable.optimize(), parameter.optimize());
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return Stream.concat(callable.extractSideEffects(), parameter.extractSideEffects());
}
}

View File

@ -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.ast.Expr;
import io.gitlab.jfronny.muscript.compiler.*;
import io.gitlab.jfronny.muscript.data.Scope;
import io.gitlab.jfronny.muscript.data.dynamic.*;
@ -60,9 +61,25 @@ public class Call extends DynamicExpr {
args.add(new Arg(bind.parameter, false));
}
for (Arg arg : this.args) args.add(arg.optimize());
if (left instanceof Closure closure) {
return new ExprGroup(
closure.location,
closure.stream().toList(),
new ExprGroup.PackedArgs(
args,
closure.boundArgs,
closure.variadic
)
);
}
return new Call(location, left, args);
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return Stream.of(this);
}
@Override
public void decompile(ExprWriter writer) throws IOException {
parenthesize(left, writer, false);

View File

@ -14,10 +14,10 @@ import java.util.stream.IntStream;
import java.util.stream.Stream;
public class Closure extends DynamicExpr {
private final List<String> boundArgs;
public final List<String> boundArgs;
private final List<Expr<?>> steps;
private final DynamicExpr fin;
private final boolean variadic;
public final boolean variadic;
public Closure(CodeLocation location, List<String> boundArgs, List<Expr<?>> expressions, boolean variadic) {
this(location, boundArgs, expressions.subList(0, expressions.size() - 1), expressions.get(expressions.size() - 1).asDynamicExpr(), variadic);
@ -34,6 +34,7 @@ public class Closure extends DynamicExpr {
@Override
public DCallable get(Scope dataRoot) {
return DFinal.of(args -> {
// Compare with ExprGroup.get()
int ac = args.size();
int ae = boundArgs.size();
if (variadic) ae--;
@ -55,8 +56,22 @@ public class Closure extends DynamicExpr {
@Override
public DynamicExpr optimize() {
// Eliminating side effect free steps might be possible, but would be too much work imo
return new Closure(location, boundArgs, steps.stream().<Expr<?>>map(Expr::optimize).toList(), fin.optimize(), variadic);
return new Closure(
location,
boundArgs,
steps.stream()
.map(Expr::optimize)
.flatMap(Expr::extractSideEffects)
.<Expr<?>>map(Expr::optimize)
.toList(),
fin.optimize(),
variadic
);
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return Stream.empty();
}
@Override

View File

@ -9,6 +9,7 @@ import io.gitlab.jfronny.muscript.data.dynamic.*;
import io.gitlab.jfronny.muscript.data.dynamic.additional.DFinal;
import java.io.IOException;
import java.util.stream.Stream;
public class DynamicCoerce extends DynamicExpr {
public final Expr<?> inner;
@ -44,6 +45,11 @@ public class DynamicCoerce extends DynamicExpr {
return new DynamicCoerce(location, inner);
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return inner.extractSideEffects();
}
@Override
public void decompile(ExprWriter writer) throws IOException {
inner.decompile(writer);

View File

@ -0,0 +1,122 @@
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.ast.NullLiteral;
import io.gitlab.jfronny.muscript.compiler.CodeLocation;
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
import io.gitlab.jfronny.muscript.compiler.Order;
import io.gitlab.jfronny.muscript.data.Scope;
import io.gitlab.jfronny.muscript.data.dynamic.Dynamic;
import io.gitlab.jfronny.muscript.error.LocationalException;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class ExprGroup extends DynamicExpr {
private final List<Expr<?>> steps;
private final DynamicExpr fin;
private final @Nullable PackedArgs packedArgs;
private final boolean fork;
public ExprGroup(CodeLocation location, List<Expr<?>> expressions) {
this(location, expressions, null);
}
public ExprGroup(CodeLocation location, List<Expr<?>> expressions, @Nullable PackedArgs packedArgs) {
this(location, expressions, packedArgs, true);
}
public ExprGroup(CodeLocation location, List<Expr<?>> expressions, @Nullable PackedArgs packedArgs, boolean fork) {
super(Order.Primary, location);
this.steps = expressions.subList(0, expressions.size() - 1);
this.fin = expressions.get(expressions.size() - 1).asDynamicExpr();
this.packedArgs = packedArgs;
this.fork = fork;
}
public static Expr<?> of(CodeLocation location, List<Expr<?>> expressions) {
return of(location, expressions, true);
}
public static Expr<?> of(CodeLocation location, List<Expr<?>> expressions, boolean fork) {
if (expressions.isEmpty()) return new NullLiteral(location);
if (!fork && expressions.size() == 1) return expressions.get(0);
return new ExprGroup(location, expressions, null, fork);
}
@Override
public Dynamic get(Scope dataRoot) {
Scope fork = this.fork ? dataRoot.fork() : dataRoot;
if (packedArgs != null) {
List<Dynamic> from = new LinkedList<>();
for (Call.Arg arg : packedArgs.from) {
Dynamic data = arg.expr().get(dataRoot);
if (arg.variadic()) from.addAll(data.asList().getValue());
else from.add(data);
}
List<String> to = packedArgs.to;
// Compare with Closure.get()
int ac = from.size();
int ae = to.size();
if (packedArgs.variadic) ae--;
if (ac < ae) throw new LocationalException(location, "Invoked with too few arguments (expected " + ae + " but got " + ac + ")");
if (!packedArgs.variadic && ac > ae) throw new LocationalException(location, "Invoked with too many arguments (expected " + ae + " but got " + ac + ")");
for (int i = 0; i < ae; i++) fork.set(to.get(i), from.get(i));
if (packedArgs.variadic) {
fork.set(to.get(to.size() - 1), IntStream.range(ae, ac)
.mapToObj(from::get)
.toList());
}
}
for (Expr<?> step : steps) {
step.get(fork);
}
return fin.get(fork);
}
@Override
public DynamicExpr optimize() {
return of(
location,
Stream.concat(
steps.stream()
.map(Expr::optimize)
.flatMap(Expr::extractSideEffects)
.map(Expr::optimize),
Stream.of(fin.optimize())
).toList()
).asDynamicExpr();
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return Stream.of(of(location, stream().flatMap(Expr::extractSideEffects).toList()));
}
@Override
public void decompile(ExprWriter writer) throws IOException {
new Call(
location,
new Closure(
location,
packedArgs == null
? List.of()
: packedArgs.to,
stream().toList(),
false
),
packedArgs == null ? List.of() : packedArgs.from
).decompile(writer);
}
public Stream<Expr<?>> stream() {
return Stream.concat(steps.stream(), Stream.of(fin));
}
public record PackedArgs(List<Call.Arg> from, List<String> to, boolean variadic) {}
}

View File

@ -12,6 +12,7 @@ import io.gitlab.jfronny.muscript.error.LocationalException;
import io.gitlab.jfronny.muscript.error.TypeMismatchException;
import java.io.IOException;
import java.util.stream.Stream;
@CanThrow
@UncheckedDynamic
@ -53,6 +54,11 @@ public class Get extends DynamicExpr {
return new Get(location, left, name);
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return Stream.concat(left.extractSideEffects(), name.extractSideEffects());
}
@Override
public void decompile(ExprWriter writer) throws IOException {
parenthesize(left, writer, false);

View File

@ -0,0 +1,47 @@
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.compiler.CodeLocation;
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
import io.gitlab.jfronny.muscript.compiler.Order;
import io.gitlab.jfronny.muscript.data.Scope;
import io.gitlab.jfronny.muscript.data.dynamic.Dynamic;
import io.gitlab.jfronny.muscript.data.dynamic.additional.DFinal;
import java.io.IOException;
import java.util.List;
import java.util.stream.Stream;
public class ListOf extends DynamicExpr {
private final List<DynamicExpr> elements;
protected ListOf(CodeLocation location, List<DynamicExpr> elements) {
super(Order.Primary, location);
this.elements = elements;
}
@Override
public Dynamic get(Scope dataRoot) {
return DFinal.of(elements.stream().map(s -> s.get(dataRoot)).toList());
}
@Override
public DynamicExpr optimize() {
return new ListOf(location, elements.stream().map(DynamicExpr::optimize).toList());
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return elements.stream().flatMap(Expr::extractSideEffects);
}
@Override
public void decompile(ExprWriter writer) throws IOException {
new Call(
location,
new Variable(location, "listOf"),
elements.stream().map(s -> new Call.Arg(s, false)).toList()
);
}
}

View File

@ -1,6 +1,7 @@
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.ast.literal.DynamicLiteral;
import io.gitlab.jfronny.muscript.compiler.*;
import io.gitlab.jfronny.muscript.data.Scope;
@ -10,6 +11,7 @@ import io.gitlab.jfronny.muscript.data.dynamic.additional.DFinal;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Stream;
public class ObjectLiteral extends DynamicExpr {
public final Map<String, DynamicExpr> content;
@ -41,6 +43,11 @@ public class ObjectLiteral extends DynamicExpr {
return new ObjectLiteral(location, content);
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return content.values().stream().flatMap(Expr::extractSideEffects);
}
@Override
public void decompile(ExprWriter writer) throws IOException {
writer.increaseIndent().append("{\n");

View File

@ -1,5 +1,6 @@
package io.gitlab.jfronny.muscript.ast.dynamic;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.compiler.*;
import io.gitlab.jfronny.muscript.data.Scope;
import io.gitlab.jfronny.muscript.data.dynamic.Dynamic;
@ -9,6 +10,7 @@ import io.gitlab.jfronny.muscript.annotations.UncheckedDynamic;
import io.gitlab.jfronny.muscript.error.LocationalException;
import java.io.IOException;
import java.util.stream.Stream;
@CanThrow
@UncheckedDynamic
@ -32,6 +34,11 @@ public class Variable extends DynamicExpr {
return this;
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return Stream.empty();
}
@Override
public void decompile(ExprWriter writer) throws IOException {
writer.appendLiteral(name);

View File

@ -1,11 +1,13 @@
package io.gitlab.jfronny.muscript.ast.dynamic.assign;
import io.gitlab.jfronny.muscript.ast.BoolExpr;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.compiler.*;
import io.gitlab.jfronny.muscript.data.Scope;
import io.gitlab.jfronny.muscript.error.LocationalException;
import java.io.IOException;
import java.util.stream.Stream;
public class BoolAssign extends BoolExpr {
private final String name;
@ -30,6 +32,11 @@ public class BoolAssign extends BoolExpr {
return new BoolAssign(location, name, value.optimize());
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return Stream.of(this);
}
@Override
public void decompile(ExprWriter writer) throws IOException {
writer.appendLiteral(name).append(" = ");

View File

@ -8,6 +8,7 @@ import io.gitlab.jfronny.muscript.data.dynamic.Dynamic;
import io.gitlab.jfronny.muscript.error.LocationalException;
import java.io.IOException;
import java.util.stream.Stream;
public class DynamicAssign extends DynamicExpr {
private final String name;
@ -53,6 +54,11 @@ public class DynamicAssign extends DynamicExpr {
return new NumberAssign(location, name, value.asNumberExpr());
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return Stream.of(this);
}
@Override
public boolean equals(Object obj) {
return obj instanceof DynamicAssign assign

View File

@ -1,11 +1,13 @@
package io.gitlab.jfronny.muscript.ast.dynamic.assign;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.ast.NumberExpr;
import io.gitlab.jfronny.muscript.compiler.*;
import io.gitlab.jfronny.muscript.data.Scope;
import io.gitlab.jfronny.muscript.error.LocationalException;
import java.io.IOException;
import java.util.stream.Stream;
public class NumberAssign extends NumberExpr {
private final String name;
@ -30,6 +32,11 @@ public class NumberAssign extends NumberExpr {
return new NumberAssign(location, name, value.optimize());
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return Stream.of(this);
}
@Override
public void decompile(ExprWriter writer) throws IOException {
writer.appendLiteral(name).append(" = ");

View File

@ -1,11 +1,13 @@
package io.gitlab.jfronny.muscript.ast.dynamic.assign;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.ast.StringExpr;
import io.gitlab.jfronny.muscript.compiler.*;
import io.gitlab.jfronny.muscript.data.Scope;
import io.gitlab.jfronny.muscript.error.LocationalException;
import java.io.IOException;
import java.util.stream.Stream;
public class StringAssign extends StringExpr {
private final String name;
@ -30,6 +32,11 @@ public class StringAssign extends StringExpr {
return new StringAssign(location, name, value.optimize());
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return Stream.of(this);
}
@Override
public void decompile(ExprWriter writer) throws IOException {
writer.appendLiteral(name).append(" = ");

View File

@ -1,5 +1,6 @@
package io.gitlab.jfronny.muscript.ast.dynamic.unpack;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.compiler.CodeLocation;
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
import io.gitlab.jfronny.muscript.data.Scope;
@ -13,6 +14,7 @@ import io.gitlab.jfronny.muscript.ast.dynamic.DynamicCoerce;
import io.gitlab.jfronny.muscript.error.LocationalException;
import java.io.IOException;
import java.util.stream.Stream;
@CanThrow
@UncheckedDynamic
@ -42,6 +44,11 @@ public class BoolUnpack extends BoolExpr {
return new BoolUnpack(location, inner);
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return inner.extractSideEffects();
}
@Override
public void decompile(ExprWriter writer) throws IOException {
inner.decompile(writer);

View File

@ -1,5 +1,6 @@
package io.gitlab.jfronny.muscript.ast.dynamic.unpack;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.compiler.CodeLocation;
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
import io.gitlab.jfronny.muscript.data.Scope;
@ -13,6 +14,7 @@ import io.gitlab.jfronny.muscript.ast.dynamic.DynamicCoerce;
import io.gitlab.jfronny.muscript.error.LocationalException;
import java.io.IOException;
import java.util.stream.Stream;
@CanThrow
@UncheckedDynamic
@ -42,6 +44,11 @@ public class NumberUnpack extends NumberExpr {
return new NumberUnpack(location, inner.optimize());
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return inner.extractSideEffects();
}
@Override
public void decompile(ExprWriter writer) throws IOException {
inner.decompile(writer);

View File

@ -1,5 +1,6 @@
package io.gitlab.jfronny.muscript.ast.dynamic.unpack;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.compiler.CodeLocation;
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
import io.gitlab.jfronny.muscript.data.Scope;
@ -13,6 +14,7 @@ import io.gitlab.jfronny.muscript.ast.dynamic.DynamicCoerce;
import io.gitlab.jfronny.muscript.error.LocationalException;
import java.io.IOException;
import java.util.stream.Stream;
@CanThrow
@UncheckedDynamic
@ -42,6 +44,11 @@ public class StringUnpack extends StringExpr {
return new StringUnpack(location, inner);
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return inner.extractSideEffects();
}
@Override
public void decompile(ExprWriter writer) throws IOException {
inner.decompile(writer);

View File

@ -1,10 +1,12 @@
package io.gitlab.jfronny.muscript.ast.literal;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.compiler.*;
import io.gitlab.jfronny.muscript.data.Scope;
import io.gitlab.jfronny.muscript.ast.BoolExpr;
import java.io.IOException;
import java.util.stream.Stream;
public final class BoolLiteral extends BoolExpr {
public final boolean value;
@ -24,6 +26,11 @@ public final class BoolLiteral extends BoolExpr {
return this;
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return Stream.empty();
}
@Override
public void decompile(ExprWriter writer) throws IOException {
writer.append(value ? "true" : "false");

View File

@ -1,11 +1,13 @@
package io.gitlab.jfronny.muscript.ast.literal;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.compiler.*;
import io.gitlab.jfronny.muscript.data.Scope;
import io.gitlab.jfronny.muscript.data.dynamic.Dynamic;
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
import java.io.IOException;
import java.util.stream.Stream;
public final class DynamicLiteral<T> extends DynamicExpr {
public final Dynamic value;
@ -25,6 +27,11 @@ public final class DynamicLiteral<T> extends DynamicExpr {
return this;
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return Stream.empty();
}
@Override
public void decompile(ExprWriter writer) throws IOException {
value.serialize(writer);

View File

@ -1,11 +1,13 @@
package io.gitlab.jfronny.muscript.ast.literal;
import io.gitlab.jfronny.commons.StringFormatter;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.compiler.*;
import io.gitlab.jfronny.muscript.data.Scope;
import io.gitlab.jfronny.muscript.ast.NumberExpr;
import java.io.IOException;
import java.util.stream.Stream;
public final class NumberLiteral extends NumberExpr {
public final double value;
@ -25,6 +27,11 @@ public final class NumberLiteral extends NumberExpr {
return this;
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return Stream.empty();
}
@Override
public void decompile(ExprWriter writer) throws IOException {
writer.append(StringFormatter.toString(value));

View File

@ -1,10 +1,12 @@
package io.gitlab.jfronny.muscript.ast.literal;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.ast.StringExpr;
import io.gitlab.jfronny.muscript.compiler.*;
import io.gitlab.jfronny.muscript.data.Scope;
import java.io.IOException;
import java.util.stream.Stream;
public final class StringLiteral extends StringExpr {
public final String value;
@ -24,6 +26,11 @@ public final class StringLiteral extends StringExpr {
return this;
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return Stream.empty();
}
@Override
public void decompile(ExprWriter writer) throws IOException {
writer.append(enquote(value));

View File

@ -7,6 +7,7 @@ import io.gitlab.jfronny.muscript.ast.NumberExpr;
import io.gitlab.jfronny.muscript.ast.literal.NumberLiteral;
import java.io.IOException;
import java.util.stream.Stream;
public class Divide extends NumberExpr {
public final NumberExpr dividend;
@ -34,6 +35,11 @@ public class Divide extends NumberExpr {
return new Divide(location, dividend, divisor);
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return Stream.concat(dividend.extractSideEffects(), divisor.extractSideEffects());
}
@Override
public void decompile(ExprWriter writer) throws IOException {
parenthesize(dividend, writer, false);

View File

@ -7,6 +7,7 @@ import io.gitlab.jfronny.muscript.ast.NumberExpr;
import io.gitlab.jfronny.muscript.ast.literal.NumberLiteral;
import java.io.IOException;
import java.util.stream.Stream;
public class Invert extends NumberExpr {
public final NumberExpr inner;
@ -30,6 +31,11 @@ public class Invert extends NumberExpr {
return new Invert(location, inner);
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return inner.extractSideEffects();
}
@Override
public void decompile(ExprWriter writer) throws IOException {
writer.append('-');

View File

@ -7,6 +7,7 @@ import io.gitlab.jfronny.muscript.ast.NumberExpr;
import io.gitlab.jfronny.muscript.ast.literal.NumberLiteral;
import java.io.IOException;
import java.util.stream.Stream;
public class Minus extends NumberExpr {
public final NumberExpr minuend;
@ -39,6 +40,11 @@ public class Minus extends NumberExpr {
return new Minus(location, minuend, subtrahend);
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return Stream.concat(minuend.extractSideEffects(), subtrahend.extractSideEffects());
}
@Override
public void decompile(ExprWriter writer) throws IOException {
parenthesize(minuend, writer, false);

View File

@ -7,6 +7,7 @@ import io.gitlab.jfronny.muscript.ast.NumberExpr;
import io.gitlab.jfronny.muscript.ast.literal.NumberLiteral;
import java.io.IOException;
import java.util.stream.Stream;
public class Modulo extends NumberExpr {
private final NumberExpr dividend;
@ -32,6 +33,11 @@ public class Modulo extends NumberExpr {
return new Modulo(location, dividend, divisor);
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return Stream.concat(dividend.extractSideEffects(), divisor.extractSideEffects());
}
@Override
public void decompile(ExprWriter writer) throws IOException {
parenthesize(dividend, writer, false);

View File

@ -7,6 +7,7 @@ import io.gitlab.jfronny.muscript.ast.NumberExpr;
import io.gitlab.jfronny.muscript.ast.literal.NumberLiteral;
import java.io.IOException;
import java.util.stream.Stream;
public class Multiply extends NumberExpr {
public final NumberExpr multiplier;
@ -32,6 +33,11 @@ public class Multiply extends NumberExpr {
return new Multiply(location, multiplier, multiplicand);
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return Stream.concat(multiplier.extractSideEffects(), multiplicand.extractSideEffects());
}
@Override
public void decompile(ExprWriter writer) throws IOException {
parenthesize(multiplier, writer, false);

View File

@ -7,6 +7,7 @@ import io.gitlab.jfronny.muscript.ast.NumberExpr;
import io.gitlab.jfronny.muscript.ast.literal.NumberLiteral;
import java.io.IOException;
import java.util.stream.Stream;
public class Plus extends NumberExpr {
public final NumberExpr augend;
@ -36,6 +37,11 @@ public class Plus extends NumberExpr {
return new Plus(location, augend, addend);
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return Stream.concat(augend.extractSideEffects(), addend.extractSideEffects());
}
@Override
public void decompile(ExprWriter writer) throws IOException {
parenthesize(augend, writer, false);

View File

@ -7,6 +7,7 @@ import io.gitlab.jfronny.muscript.ast.NumberExpr;
import io.gitlab.jfronny.muscript.ast.literal.NumberLiteral;
import java.io.IOException;
import java.util.stream.Stream;
public class Power extends NumberExpr {
private final NumberExpr base;
@ -42,6 +43,11 @@ public class Power extends NumberExpr {
return new Power(location, base, exponent);
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return Stream.concat(base.extractSideEffects(), exponent.extractSideEffects());
}
@Override
public void decompile(ExprWriter writer) throws IOException {
parenthesize(base, writer, false);

View File

@ -7,6 +7,7 @@ import io.gitlab.jfronny.muscript.ast.StringExpr;
import io.gitlab.jfronny.muscript.ast.literal.StringLiteral;
import java.io.IOException;
import java.util.stream.Stream;
public class Concatenate extends StringExpr {
public final StringExpr left;
@ -38,6 +39,11 @@ public class Concatenate extends StringExpr {
return new Concatenate(location, left, right);
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return Stream.concat(left.extractSideEffects(), right.extractSideEffects());
}
@Override
public void decompile(ExprWriter writer) throws IOException {
parenthesize(left, writer, false);

View File

@ -8,6 +8,7 @@ import io.gitlab.jfronny.muscript.ast.*;
import io.gitlab.jfronny.muscript.ast.literal.*;
import java.io.IOException;
import java.util.stream.Stream;
public class StringCoerce extends StringExpr {
private final Expr<?> inner;
@ -33,6 +34,11 @@ public class StringCoerce extends StringExpr {
return new StringCoerce(location, inner);
}
@Override
public Stream<Expr<?>> extractSideEffects() {
return inner.extractSideEffects();
}
@Override
public void decompile(ExprWriter writer) throws IOException {
inner.decompile(writer);

View File

@ -2,6 +2,8 @@ package io.gitlab.jfronny.muscript.compiler;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
public record CodeLocation(int chStart, int chEnd, @Nullable String source, @Nullable String file) {
public static final CodeLocation NONE = new CodeLocation(-1, -1);

View File

@ -4,43 +4,38 @@ import io.gitlab.jfronny.muscript.ast.DynamicExpr;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.ast.dynamic.Call;
import io.gitlab.jfronny.muscript.ast.dynamic.Closure;
import io.gitlab.jfronny.muscript.ast.dynamic.ExprGroup;
import io.gitlab.jfronny.muscript.compiler.*;
import io.gitlab.jfronny.muscript.data.dynamic.*;
import io.gitlab.jfronny.muscript.data.dynamic.additional.DFinal;
import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;
public class Script extends Decompilable {
private final List<Expr<?>> steps;
private final DynamicExpr fin;
private final String file;
private final DynamicExpr content;
public Script(List<Expr<?>> expressions) {
this(expressions, null);
}
public Script(List<Expr<?>> expressions, String file) {
this(expressions.subList(0, expressions.size() - 1), expressions.get(expressions.size() - 1).asDynamicExpr(), file);
this(new ExprGroup(CodeLocation.NONE.withFile(file), expressions));
}
private Script(List<Expr<?>> steps, DynamicExpr fin, String file) {
private Script(DynamicExpr content) {
super(Order.Script);
this.steps = steps;
this.fin = fin;
this.file = file;
this.content = Objects.requireNonNull(content);
}
public Dynamic run(DObject scope) {
return run(new Scope(scope));
return content.get(scope);
}
public Dynamic run(Scope scope) {
for (Expr<?> expression : steps) {
expression.get(scope);
}
return fin.get(scope);
return content.get(scope);
}
public DCallable bindTo(Scope scope) {
@ -51,12 +46,11 @@ public class Script extends Decompilable {
}
public DynamicExpr asExpr() {
CodeLocation location = CodeLocation.NONE.withFile(file);
return new Call(location, new Closure(location, List.of(), stream().toList(), false), List.of());
return content;
}
public Script optimize() {
return new Script(steps.stream().<Expr<?>>map(Expr::optimize).toList(), fin.optimize(), file);
return new Script(content.optimize());
}
public Script concat(Script other) {
@ -64,7 +58,9 @@ public class Script extends Decompilable {
}
public Stream<Expr<?>> stream() {
return Stream.concat(steps.stream(), Stream.of(fin));
return content instanceof ExprGroup g
? g.stream()
: Stream.of(content);
}
@Override