mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2024-12-23 09:47:38 +00:00
Expression changes
This commit is contained in:
parent
2b29266db2
commit
de1bd22f85
@ -38,7 +38,13 @@ import java.lang.invoke.MethodHandle;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compiles and evaluates expressions.
|
* Compiles and evaluates expressions.
|
||||||
@ -80,8 +86,12 @@ public class Expression {
|
|||||||
private final List<String> providedSlots;
|
private final List<String> providedSlots;
|
||||||
private final ExpressionParser.AllStatementsContext root;
|
private final ExpressionParser.AllStatementsContext root;
|
||||||
private final SetMultimap<String, MethodHandle> functions = Functions.getFunctionMap();
|
private final SetMultimap<String, MethodHandle> functions = Functions.getFunctionMap();
|
||||||
private final CompiledExpression compiledExpression;
|
|
||||||
private ExpressionEnvironment environment;
|
private ExpressionEnvironment environment;
|
||||||
|
private final CompiledExpression compiledExpression;
|
||||||
|
|
||||||
|
public static Expression compile(String expression, String... variableNames) throws ExpressionException {
|
||||||
|
return new Expression(expression, variableNames);
|
||||||
|
}
|
||||||
|
|
||||||
private Expression(String expression, String... variableNames) throws ExpressionException {
|
private Expression(String expression, String... variableNames) throws ExpressionException {
|
||||||
slots.putSlot("e", new LocalSlot.Constant(Math.E));
|
slots.putSlot("e", new LocalSlot.Constant(Math.E));
|
||||||
@ -114,14 +124,6 @@ public class Expression {
|
|||||||
this.compiledExpression = new ExpressionCompiler().compileExpression(root, functions);
|
this.compiledExpression = new ExpressionCompiler().compileExpression(root, functions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Expression compile(String expression, String... variableNames) throws ExpressionException {
|
|
||||||
return new Expression(expression, variableNames);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Expression getInstance() {
|
|
||||||
return instance.get().peek();
|
|
||||||
}
|
|
||||||
|
|
||||||
public double evaluate(double... values) throws EvaluationException {
|
public double evaluate(double... values) throws EvaluationException {
|
||||||
return evaluate(values, WorldEdit.getInstance().getConfiguration().calculationTimeout);
|
return evaluate(values, WorldEdit.getInstance().getConfiguration().calculationTimeout);
|
||||||
}
|
}
|
||||||
@ -197,6 +199,10 @@ public class Expression {
|
|||||||
return slots;
|
return slots;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Expression getInstance() {
|
||||||
|
return instance.get().peek();
|
||||||
|
}
|
||||||
|
|
||||||
private void pushInstance() {
|
private void pushInstance() {
|
||||||
Stack<Expression> threadLocalExprStack = instance.get();
|
Stack<Expression> threadLocalExprStack = instance.get();
|
||||||
if (threadLocalExprStack == null) {
|
if (threadLocalExprStack == null) {
|
||||||
|
@ -25,7 +25,6 @@ import com.sk89q.worldedit.antlr.ExpressionParser;
|
|||||||
import com.sk89q.worldedit.internal.expression.BreakException;
|
import com.sk89q.worldedit.internal.expression.BreakException;
|
||||||
import com.sk89q.worldedit.internal.expression.EvaluationException;
|
import com.sk89q.worldedit.internal.expression.EvaluationException;
|
||||||
import com.sk89q.worldedit.internal.expression.ExecutionData;
|
import com.sk89q.worldedit.internal.expression.ExecutionData;
|
||||||
import com.sk89q.worldedit.internal.expression.ExpressionHelper;
|
|
||||||
import com.sk89q.worldedit.internal.expression.LocalSlot;
|
import com.sk89q.worldedit.internal.expression.LocalSlot;
|
||||||
import it.unimi.dsi.fastutil.doubles.Double2ObjectLinkedOpenHashMap;
|
import it.unimi.dsi.fastutil.doubles.Double2ObjectLinkedOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.doubles.Double2ObjectMap;
|
import it.unimi.dsi.fastutil.doubles.Double2ObjectMap;
|
||||||
@ -68,11 +67,39 @@ import static com.sk89q.worldedit.antlr.ExpressionLexer.RIGHT_SHIFT;
|
|||||||
import static com.sk89q.worldedit.antlr.ExpressionLexer.TIMES;
|
import static com.sk89q.worldedit.antlr.ExpressionLexer.TIMES;
|
||||||
import static com.sk89q.worldedit.antlr.ExpressionLexer.TIMES_ASSIGN;
|
import static com.sk89q.worldedit.antlr.ExpressionLexer.TIMES_ASSIGN;
|
||||||
import static com.sk89q.worldedit.internal.expression.ExpressionHelper.WRAPPED_CONSTANT;
|
import static com.sk89q.worldedit.internal.expression.ExpressionHelper.WRAPPED_CONSTANT;
|
||||||
|
import static com.sk89q.worldedit.internal.expression.ExpressionHelper.check;
|
||||||
|
import static com.sk89q.worldedit.internal.expression.ExpressionHelper.evalException;
|
||||||
|
import static com.sk89q.worldedit.internal.expression.ExpressionHelper.getArgumentHandleName;
|
||||||
|
import static com.sk89q.worldedit.internal.expression.ExpressionHelper.resolveFunction;
|
||||||
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.CALL_BINARY_OP;
|
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.CALL_BINARY_OP;
|
||||||
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.DOUBLE_TO_BOOL;
|
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.DOUBLE_TO_BOOL;
|
||||||
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.IS_NULL;
|
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.IS_NULL;
|
||||||
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.NEW_LS_CONSTANT;
|
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.NEW_LS_CONSTANT;
|
||||||
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.NULL_DOUBLE;
|
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.NULL_DOUBLE;
|
||||||
|
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.boolToDouble;
|
||||||
|
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.call;
|
||||||
|
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.constantInvoke;
|
||||||
|
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.dedupData;
|
||||||
|
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.doWhileLoop;
|
||||||
|
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.dropData;
|
||||||
|
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.forLoop;
|
||||||
|
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.getSlotValue;
|
||||||
|
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.getVariable;
|
||||||
|
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.initVariable;
|
||||||
|
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.mhGetVariable;
|
||||||
|
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.simpleForLoop;
|
||||||
|
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.standardInvoke;
|
||||||
|
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.switchStatement;
|
||||||
|
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.throwEvalException;
|
||||||
|
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.whileLoop;
|
||||||
|
import static java.lang.invoke.MethodHandles.collectArguments;
|
||||||
|
import static java.lang.invoke.MethodHandles.constant;
|
||||||
|
import static java.lang.invoke.MethodHandles.dropArguments;
|
||||||
|
import static java.lang.invoke.MethodHandles.filterArguments;
|
||||||
|
import static java.lang.invoke.MethodHandles.guardWithTest;
|
||||||
|
import static java.lang.invoke.MethodHandles.identity;
|
||||||
|
import static java.lang.invoke.MethodHandles.permuteArguments;
|
||||||
|
import static java.lang.invoke.MethodHandles.throwException;
|
||||||
import static java.lang.invoke.MethodType.methodType;
|
import static java.lang.invoke.MethodType.methodType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -97,7 +124,7 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
.filter(TerminalNode.class::isInstance)
|
.filter(TerminalNode.class::isInstance)
|
||||||
.map(TerminalNode.class::cast)
|
.map(TerminalNode.class::cast)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
ExpressionHelper.check(children.size() == 1, ctx, "Expected exactly one token, got " + children.size());
|
check(children.size() == 1, ctx, "Expected exactly one token, got " + children.size());
|
||||||
return children.get(0).getSymbol();
|
return children.get(0).getSymbol();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +137,7 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void checkHandle(MethodHandle mh, ParserRuleContext ctx) {
|
private void checkHandle(MethodHandle mh, ParserRuleContext ctx) {
|
||||||
ExpressionHelper.check(mh.type().equals(ExpressionHandles.COMPILED_EXPRESSION_SIG), ctx,
|
check(mh.type().equals(ExpressionHandles.COMPILED_EXPRESSION_SIG), ctx,
|
||||||
"Incorrect type returned from handler for " + ctx.getClass());
|
"Incorrect type returned from handler for " + ctx.getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,15 +146,15 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
// if result is null
|
// if result is null
|
||||||
IS_NULL.asType(methodType(boolean.class, Double.class)),
|
IS_NULL.asType(methodType(boolean.class, Double.class)),
|
||||||
// throw appropriate exception, dropping `result` argument
|
// throw appropriate exception, dropping `result` argument
|
||||||
MethodHandles.dropArguments(
|
dropArguments(
|
||||||
ExpressionHandles.throwEvalException(ctx, "Invalid expression for " + name), 0, Double.class
|
throwEvalException(ctx, "Invalid expression for " + name), 0, Double.class
|
||||||
),
|
),
|
||||||
// else return the argument we were passed
|
// else return the argument we were passed
|
||||||
MethodHandles.identity(Double.class)
|
identity(Double.class)
|
||||||
);
|
);
|
||||||
// now pass `result` into `guard`
|
// now pass `result` into `guard`
|
||||||
MethodHandle result = evaluate(ctx).handle;
|
MethodHandle result = evaluate(ctx).handle;
|
||||||
return MethodHandles.collectArguments(guard, 0, result);
|
return collectArguments(guard, 0, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MethodHandle evaluateForValue(ParserRuleContext ctx) {
|
private MethodHandle evaluateForValue(ParserRuleContext ctx) {
|
||||||
@ -138,7 +165,7 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
MethodHandle value = evaluateForNamedValue(boolExpression, "a boolean");
|
MethodHandle value = evaluateForNamedValue(boolExpression, "a boolean");
|
||||||
value = value.asType(value.type().unwrap());
|
value = value.asType(value.type().unwrap());
|
||||||
// Pass `value` into converter, returns (ExecutionData)boolean;
|
// Pass `value` into converter, returns (ExecutionData)boolean;
|
||||||
return MethodHandles.collectArguments(
|
return collectArguments(
|
||||||
DOUBLE_TO_BOOL, 0, value
|
DOUBLE_TO_BOOL, 0, value
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -147,7 +174,7 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
ParserRuleContext trueBranch,
|
ParserRuleContext trueBranch,
|
||||||
ParserRuleContext falseBranch) {
|
ParserRuleContext falseBranch) {
|
||||||
// easiest one of the bunch
|
// easiest one of the bunch
|
||||||
return MethodHandles.guardWithTest(
|
return guardWithTest(
|
||||||
evaluateBoolean(condition),
|
evaluateBoolean(condition),
|
||||||
trueBranch == null ? NULL_DOUBLE : evaluate(trueBranch).handle,
|
trueBranch == null ? NULL_DOUBLE : evaluate(trueBranch).handle,
|
||||||
falseBranch == null ? NULL_DOUBLE : evaluate(falseBranch).handle
|
falseBranch == null ? NULL_DOUBLE : evaluate(falseBranch).handle
|
||||||
@ -166,7 +193,7 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MethodHandle visitWhileStatement(ExpressionParser.WhileStatementContext ctx) {
|
public MethodHandle visitWhileStatement(ExpressionParser.WhileStatementContext ctx) {
|
||||||
return ExpressionHandles.whileLoop(
|
return whileLoop(
|
||||||
evaluateBoolean(ctx.condition),
|
evaluateBoolean(ctx.condition),
|
||||||
evaluate(ctx.body)
|
evaluate(ctx.body)
|
||||||
);
|
);
|
||||||
@ -174,7 +201,7 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MethodHandle visitDoStatement(ExpressionParser.DoStatementContext ctx) {
|
public MethodHandle visitDoStatement(ExpressionParser.DoStatementContext ctx) {
|
||||||
return ExpressionHandles.doWhileLoop(
|
return doWhileLoop(
|
||||||
evaluateBoolean(ctx.condition),
|
evaluateBoolean(ctx.condition),
|
||||||
evaluate(ctx.body)
|
evaluate(ctx.body)
|
||||||
);
|
);
|
||||||
@ -182,7 +209,7 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MethodHandle visitForStatement(ExpressionParser.ForStatementContext ctx) {
|
public MethodHandle visitForStatement(ExpressionParser.ForStatementContext ctx) {
|
||||||
return ExpressionHandles.forLoop(
|
return forLoop(
|
||||||
evaluate(ctx.init).handle,
|
evaluate(ctx.init).handle,
|
||||||
evaluateBoolean(ctx.condition),
|
evaluateBoolean(ctx.condition),
|
||||||
evaluate(ctx.body),
|
evaluate(ctx.body),
|
||||||
@ -192,7 +219,7 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MethodHandle visitSimpleForStatement(ExpressionParser.SimpleForStatementContext ctx) {
|
public MethodHandle visitSimpleForStatement(ExpressionParser.SimpleForStatementContext ctx) {
|
||||||
return ExpressionHandles.simpleForLoop(
|
return simpleForLoop(
|
||||||
evaluateForValue(ctx.first),
|
evaluateForValue(ctx.first),
|
||||||
evaluateForValue(ctx.last),
|
evaluateForValue(ctx.last),
|
||||||
ctx.counter,
|
ctx.counter,
|
||||||
@ -201,11 +228,9 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static final MethodHandle BREAK_STATEMENT =
|
private static final MethodHandle BREAK_STATEMENT =
|
||||||
ExpressionHandles.dropData(MethodHandles.throwException(Double.class, BreakException.class)
|
dropData(throwException(Double.class, BreakException.class).bindTo(BreakException.BREAK));
|
||||||
.bindTo(BreakException.BREAK));
|
|
||||||
private static final MethodHandle CONTINUE_STATEMENT =
|
private static final MethodHandle CONTINUE_STATEMENT =
|
||||||
ExpressionHandles.dropData(MethodHandles.throwException(Double.class, BreakException.class)
|
dropData(throwException(Double.class, BreakException.class).bindTo(BreakException.CONTINUE));
|
||||||
.bindTo(BreakException.CONTINUE));
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MethodHandle visitBreakStatement(ExpressionParser.BreakStatementContext ctx) {
|
public MethodHandle visitBreakStatement(ExpressionParser.BreakStatementContext ctx) {
|
||||||
@ -235,15 +260,15 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
ExecNode node = evaluate(body);
|
ExecNode node = evaluate(body);
|
||||||
if (label instanceof ExpressionParser.CaseContext) {
|
if (label instanceof ExpressionParser.CaseContext) {
|
||||||
ExpressionParser.CaseContext caseContext = (ExpressionParser.CaseContext) label;
|
ExpressionParser.CaseContext caseContext = (ExpressionParser.CaseContext) label;
|
||||||
double key = (double) ExpressionHandles.constantInvoke(evaluateForValue(caseContext.constant));
|
double key = (double) constantInvoke(evaluateForValue(caseContext.constant));
|
||||||
ExpressionHelper.check(!cases.containsKey(key), body, "Duplicate cases detected.");
|
check(!cases.containsKey(key), body, "Duplicate cases detected.");
|
||||||
cases.put(key, node);
|
cases.put(key, node);
|
||||||
} else {
|
} else {
|
||||||
ExpressionHelper.check(defaultCase == null, body, "Duplicate default cases detected.");
|
check(defaultCase == null, body, "Duplicate default cases detected.");
|
||||||
defaultCase = node;
|
defaultCase = node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ExpressionHandles.switchStatement(cases, evaluateForValue(ctx.target), defaultCase);
|
return switchStatement(cases, evaluateForValue(ctx.target), defaultCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -255,8 +280,8 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
public MethodHandle visitPostCrementExpr(ExpressionParser.PostCrementExprContext ctx) {
|
public MethodHandle visitPostCrementExpr(ExpressionParser.PostCrementExprContext ctx) {
|
||||||
Token target = ctx.target;
|
Token target = ctx.target;
|
||||||
int opType = ctx.op.getType();
|
int opType = ctx.op.getType();
|
||||||
return ExpressionHandles.call(data -> {
|
return call(data -> {
|
||||||
LocalSlot.Variable variable = ExpressionHandles.getVariable(data, target);
|
LocalSlot.Variable variable = getVariable(data, target);
|
||||||
double value = variable.getValue();
|
double value = variable.getValue();
|
||||||
if (opType == INCREMENT) {
|
if (opType == INCREMENT) {
|
||||||
value++;
|
value++;
|
||||||
@ -272,8 +297,8 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
public MethodHandle visitPreCrementExpr(ExpressionParser.PreCrementExprContext ctx) {
|
public MethodHandle visitPreCrementExpr(ExpressionParser.PreCrementExprContext ctx) {
|
||||||
Token target = ctx.target;
|
Token target = ctx.target;
|
||||||
int opType = ctx.op.getType();
|
int opType = ctx.op.getType();
|
||||||
return ExpressionHandles.call(data -> {
|
return call(data -> {
|
||||||
LocalSlot.Variable variable = ExpressionHandles.getVariable(data, target);
|
LocalSlot.Variable variable = getVariable(data, target);
|
||||||
double value = variable.getValue();
|
double value = variable.getValue();
|
||||||
double result = value;
|
double result = value;
|
||||||
if (opType == INCREMENT) {
|
if (opType == INCREMENT) {
|
||||||
@ -293,19 +318,15 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
case PLUS:
|
case PLUS:
|
||||||
return value;
|
return value;
|
||||||
case MINUS:
|
case MINUS:
|
||||||
return ExpressionHandles.call(data ->
|
return call(data -> -(double) standardInvoke(value, data));
|
||||||
-(double) ExpressionHandles.standardInvoke(value, data)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
throw ExpressionHelper.evalException(ctx, "Invalid text for plus/minus expr: " + ctx.op.getText());
|
throw evalException(ctx, "Invalid text for plus/minus expr: " + ctx.op.getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MethodHandle visitNotExpr(ExpressionParser.NotExprContext ctx) {
|
public MethodHandle visitNotExpr(ExpressionParser.NotExprContext ctx) {
|
||||||
MethodHandle expr = evaluateBoolean(ctx.expr);
|
MethodHandle expr = evaluateBoolean(ctx.expr);
|
||||||
return ExpressionHandles.call(data ->
|
return call(data -> boolToDouble(!(boolean) standardInvoke(expr, data)));
|
||||||
ExpressionHandles.boolToDouble(!(boolean) ExpressionHandles.standardInvoke(expr, data))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -315,21 +336,17 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
// - Convert back to double from following long
|
// - Convert back to double from following long
|
||||||
// - Convert to long from double value
|
// - Convert to long from double value
|
||||||
// - Convert from Object to Double to double.
|
// - Convert from Object to Double to double.
|
||||||
return ExpressionHandles.call(data ->
|
return call(data -> (double) ~(long) (double) standardInvoke(expr, data));
|
||||||
(double) ~(long) (double) ExpressionHandles.standardInvoke(expr, data)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MethodHandle visitConditionalAndExpr(ExpressionParser.ConditionalAndExprContext ctx) {
|
public MethodHandle visitConditionalAndExpr(ExpressionParser.ConditionalAndExprContext ctx) {
|
||||||
MethodHandle left = evaluateBoolean(ctx.left);
|
MethodHandle left = evaluateBoolean(ctx.left);
|
||||||
MethodHandle right = evaluateForValue(ctx.right);
|
MethodHandle right = evaluateForValue(ctx.right);
|
||||||
return MethodHandles.guardWithTest(
|
return guardWithTest(
|
||||||
left,
|
left,
|
||||||
right,
|
right,
|
||||||
ExpressionHandles.dropData(
|
dropData(constant(Double.class, boolToDouble(false)))
|
||||||
MethodHandles.constant(Double.class, ExpressionHandles.boolToDouble(false))
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,24 +356,24 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
MethodHandle right = evaluateForValue(ctx.right);
|
MethodHandle right = evaluateForValue(ctx.right);
|
||||||
// Inject left as primary condition, on failure take right with data parameter
|
// Inject left as primary condition, on failure take right with data parameter
|
||||||
// logic = (Double,ExecutionData)Double
|
// logic = (Double,ExecutionData)Double
|
||||||
MethodHandle logic = MethodHandles.guardWithTest(
|
MethodHandle logic = guardWithTest(
|
||||||
// data arg dropped implicitly
|
// data arg dropped implicitly
|
||||||
DOUBLE_TO_BOOL,
|
DOUBLE_TO_BOOL,
|
||||||
// drop data arg
|
// drop data arg
|
||||||
MethodHandles.dropArguments(
|
dropArguments(
|
||||||
MethodHandles.identity(Double.class), 1, ExecutionData.class
|
identity(Double.class), 1, ExecutionData.class
|
||||||
),
|
),
|
||||||
// drop left arg, call right
|
// drop left arg, call right
|
||||||
MethodHandles.dropArguments(
|
dropArguments(
|
||||||
right, 0, Double.class
|
right, 0, Double.class
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
// mixed = (ExecutionData,ExecutionData)Double
|
// mixed = (ExecutionData,ExecutionData)Double
|
||||||
MethodHandle mixed = MethodHandles.collectArguments(
|
MethodHandle mixed = collectArguments(
|
||||||
logic, 0, left
|
logic, 0, left
|
||||||
);
|
);
|
||||||
// Deduplicate ExecutionData
|
// Deduplicate ExecutionData
|
||||||
return ExpressionHandles.dedupData(mixed);
|
return dedupData(mixed);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MethodHandle evaluateBinary(ParserRuleContext left,
|
private MethodHandle evaluateBinary(ParserRuleContext left,
|
||||||
@ -365,12 +382,12 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
MethodHandle mhLeft = evaluateForValue(left);
|
MethodHandle mhLeft = evaluateForValue(left);
|
||||||
MethodHandle mhRight = evaluateForValue(right);
|
MethodHandle mhRight = evaluateForValue(right);
|
||||||
// Map two data args to two double args, then evaluate op
|
// Map two data args to two double args, then evaluate op
|
||||||
MethodHandle doubleData = MethodHandles.filterArguments(
|
MethodHandle doubleData = filterArguments(
|
||||||
CALL_BINARY_OP.bindTo(op), 0,
|
CALL_BINARY_OP.bindTo(op), 0,
|
||||||
mhLeft.asType(mhLeft.type().unwrap()), mhRight.asType(mhRight.type().unwrap())
|
mhLeft.asType(mhLeft.type().unwrap()), mhRight.asType(mhRight.type().unwrap())
|
||||||
);
|
);
|
||||||
doubleData = doubleData.asType(doubleData.type().wrap());
|
doubleData = doubleData.asType(doubleData.type().wrap());
|
||||||
return ExpressionHandles.dedupData(doubleData);
|
return dedupData(doubleData);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MethodHandle evaluateBinary(ParserRuleContext left,
|
private MethodHandle evaluateBinary(ParserRuleContext left,
|
||||||
@ -395,7 +412,7 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
case MODULO:
|
case MODULO:
|
||||||
return (l, r) -> l % r;
|
return (l, r) -> l % r;
|
||||||
}
|
}
|
||||||
throw ExpressionHelper.evalException(ctx, "Invalid text for multiplicative expr: " + ctx.op.getText());
|
throw evalException(ctx, "Invalid text for multiplicative expr: " + ctx.op.getText());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,7 +425,7 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
case MINUS:
|
case MINUS:
|
||||||
return (l, r) -> l - r;
|
return (l, r) -> l - r;
|
||||||
}
|
}
|
||||||
throw ExpressionHelper.evalException(ctx, "Invalid text for additive expr: " + ctx.op.getText());
|
throw evalException(ctx, "Invalid text for additive expr: " + ctx.op.getText());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -421,7 +438,7 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
case RIGHT_SHIFT:
|
case RIGHT_SHIFT:
|
||||||
return (l, r) -> (double) ((long) l >> (long) r);
|
return (l, r) -> (double) ((long) l >> (long) r);
|
||||||
}
|
}
|
||||||
throw ExpressionHelper.evalException(ctx, "Invalid text for shift expr: " + ctx.op.getText());
|
throw evalException(ctx, "Invalid text for shift expr: " + ctx.op.getText());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -430,15 +447,15 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
return evaluateBinary(ctx.left, ctx.right, () -> {
|
return evaluateBinary(ctx.left, ctx.right, () -> {
|
||||||
switch (ctx.op.getType()) {
|
switch (ctx.op.getType()) {
|
||||||
case LESS_THAN:
|
case LESS_THAN:
|
||||||
return (l, r) -> ExpressionHandles.boolToDouble(l < r);
|
return (l, r) -> boolToDouble(l < r);
|
||||||
case LESS_THAN_OR_EQUAL:
|
case LESS_THAN_OR_EQUAL:
|
||||||
return (l, r) -> ExpressionHandles.boolToDouble(l <= r);
|
return (l, r) -> boolToDouble(l <= r);
|
||||||
case GREATER_THAN:
|
case GREATER_THAN:
|
||||||
return (l, r) -> ExpressionHandles.boolToDouble(l > r);
|
return (l, r) -> boolToDouble(l > r);
|
||||||
case GREATER_THAN_OR_EQUAL:
|
case GREATER_THAN_OR_EQUAL:
|
||||||
return (l, r) -> ExpressionHandles.boolToDouble(l >= r);
|
return (l, r) -> boolToDouble(l >= r);
|
||||||
}
|
}
|
||||||
throw ExpressionHelper.evalException(ctx, "Invalid text for relational expr: " + ctx.op.getText());
|
throw evalException(ctx, "Invalid text for relational expr: " + ctx.op.getText());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -447,15 +464,15 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
return evaluateBinary(ctx.left, ctx.right, () -> {
|
return evaluateBinary(ctx.left, ctx.right, () -> {
|
||||||
switch (ctx.op.getType()) {
|
switch (ctx.op.getType()) {
|
||||||
case EQUAL:
|
case EQUAL:
|
||||||
return (l, r) -> ExpressionHandles.boolToDouble(l == r);
|
return (l, r) -> boolToDouble(l == r);
|
||||||
case NOT_EQUAL:
|
case NOT_EQUAL:
|
||||||
return (l, r) -> ExpressionHandles.boolToDouble(l != r);
|
return (l, r) -> boolToDouble(l != r);
|
||||||
case NEAR:
|
case NEAR:
|
||||||
return (l, r) -> ExpressionHandles.boolToDouble(almostEqual2sComplement(l, r, 450359963L));
|
return (l, r) -> boolToDouble(almostEqual2sComplement(l, r, 450359963L));
|
||||||
case GREATER_THAN_OR_EQUAL:
|
case GREATER_THAN_OR_EQUAL:
|
||||||
return (l, r) -> ExpressionHandles.boolToDouble(l >= r);
|
return (l, r) -> boolToDouble(l >= r);
|
||||||
}
|
}
|
||||||
throw ExpressionHelper.evalException(ctx, "Invalid text for equality expr: " + ctx.op.getText());
|
throw evalException(ctx, "Invalid text for equality expr: " + ctx.op.getText());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -481,11 +498,9 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
public MethodHandle visitPostfixExpr(ExpressionParser.PostfixExprContext ctx) {
|
public MethodHandle visitPostfixExpr(ExpressionParser.PostfixExprContext ctx) {
|
||||||
MethodHandle value = evaluateForValue(ctx.expr);
|
MethodHandle value = evaluateForValue(ctx.expr);
|
||||||
if (ctx.op.getType() == EXCLAMATION_MARK) {
|
if (ctx.op.getType() == EXCLAMATION_MARK) {
|
||||||
return ExpressionHandles.call(data ->
|
return call(data -> factorial((double) standardInvoke(value, data)));
|
||||||
factorial((double) ExpressionHandles.standardInvoke(value, data))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
throw ExpressionHelper.evalException(ctx,
|
throw evalException(ctx,
|
||||||
"Invalid text for post-unary expr: " + ctx.op.getText());
|
"Invalid text for post-unary expr: " + ctx.op.getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -517,15 +532,15 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
int type = extractToken(ctx.assignmentOperator()).getType();
|
int type = extractToken(ctx.assignmentOperator()).getType();
|
||||||
Token target = ctx.target;
|
Token target = ctx.target;
|
||||||
MethodHandle getArg = evaluateForValue(ctx.expression());
|
MethodHandle getArg = evaluateForValue(ctx.expression());
|
||||||
return ExpressionHandles.call(data -> {
|
return call(data -> {
|
||||||
double value;
|
double value;
|
||||||
double arg = (double) ExpressionHandles.standardInvoke(getArg, data);
|
double arg = (double) standardInvoke(getArg, data);
|
||||||
LocalSlot.Variable variable;
|
LocalSlot.Variable variable;
|
||||||
if (type == ASSIGN) {
|
if (type == ASSIGN) {
|
||||||
variable = ExpressionHandles.initVariable(data, target);
|
variable = initVariable(data, target);
|
||||||
value = arg;
|
value = arg;
|
||||||
} else {
|
} else {
|
||||||
variable = ExpressionHandles.getVariable(data, target);
|
variable = getVariable(data, target);
|
||||||
value = variable.getValue();
|
value = variable.getValue();
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case POWER_ASSIGN:
|
case POWER_ASSIGN:
|
||||||
@ -547,7 +562,7 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
value -= arg;
|
value -= arg;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw ExpressionHelper.evalException(ctx, "Invalid text for assign expr: " +
|
throw evalException(ctx, "Invalid text for assign expr: " +
|
||||||
ctx.assignmentOperator().getText());
|
ctx.assignmentOperator().getText());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -558,7 +573,7 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MethodHandle visitFunctionCall(ExpressionParser.FunctionCallContext ctx) {
|
public MethodHandle visitFunctionCall(ExpressionParser.FunctionCallContext ctx) {
|
||||||
MethodHandle handle = ExpressionHelper.resolveFunction(functions, ctx);
|
MethodHandle handle = resolveFunction(functions, ctx);
|
||||||
String fnName = ctx.name.getText();
|
String fnName = ctx.name.getText();
|
||||||
MethodHandle[] arguments = new MethodHandle[ctx.args.size()];
|
MethodHandle[] arguments = new MethodHandle[ctx.args.size()];
|
||||||
for (int i = 0; i < arguments.length; i++) {
|
for (int i = 0; i < arguments.length; i++) {
|
||||||
@ -573,10 +588,10 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
arguments[i] = transformed;
|
arguments[i] = transformed;
|
||||||
}
|
}
|
||||||
// Take each of our data accepting arguments, apply them over the source method
|
// Take each of our data accepting arguments, apply them over the source method
|
||||||
MethodHandle manyData = MethodHandles.filterArguments(handle, 0, arguments);
|
MethodHandle manyData = filterArguments(handle, 0, arguments);
|
||||||
// Collapse every data into one argument
|
// Collapse every data into one argument
|
||||||
int[] permutation = new int[arguments.length];
|
int[] permutation = new int[arguments.length];
|
||||||
return MethodHandles.permuteArguments(
|
return permuteArguments(
|
||||||
manyData, ExpressionHandles.COMPILED_EXPRESSION_SIG, permutation
|
manyData, ExpressionHandles.COMPILED_EXPRESSION_SIG, permutation
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -584,7 +599,7 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
// MH: (ExecutionData)T; (depends on target)
|
// MH: (ExecutionData)T; (depends on target)
|
||||||
private MethodHandle getArgument(String fnName, MethodType type, int i, ParserRuleContext arg) {
|
private MethodHandle getArgument(String fnName, MethodType type, int i, ParserRuleContext arg) {
|
||||||
// Pass variable handle in for modification?
|
// Pass variable handle in for modification?
|
||||||
String handleName = ExpressionHelper.getArgumentHandleName(fnName, type, i, arg);
|
String handleName = getArgumentHandleName(fnName, type, i, arg);
|
||||||
if (handleName == null) {
|
if (handleName == null) {
|
||||||
return evaluateForValue(arg);
|
return evaluateForValue(arg);
|
||||||
}
|
}
|
||||||
@ -592,39 +607,37 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
// pass arg into new LocalSlot.Constant
|
// pass arg into new LocalSlot.Constant
|
||||||
MethodHandle filter = evaluateForValue(arg);
|
MethodHandle filter = evaluateForValue(arg);
|
||||||
filter = filter.asType(filter.type().unwrap());
|
filter = filter.asType(filter.type().unwrap());
|
||||||
return MethodHandles.collectArguments(
|
return collectArguments(
|
||||||
NEW_LS_CONSTANT, 0, filter
|
NEW_LS_CONSTANT, 0, filter
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// small hack
|
// small hack
|
||||||
CommonToken fake = new CommonToken(arg.start);
|
CommonToken fake = new CommonToken(arg.start);
|
||||||
fake.setText(handleName);
|
fake.setText(handleName);
|
||||||
return ExpressionHandles.mhGetVariable(fake);
|
return mhGetVariable(fake);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MethodHandle visitConstantExpression(ExpressionParser.ConstantExpressionContext ctx) {
|
public MethodHandle visitConstantExpression(ExpressionParser.ConstantExpressionContext ctx) {
|
||||||
try {
|
try {
|
||||||
return ExpressionHandles.dropData(
|
return dropData(constant(Double.class, Double.parseDouble(ctx.getText())));
|
||||||
MethodHandles.constant(Double.class, Double.parseDouble(ctx.getText()))
|
|
||||||
);
|
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
// Rare, but might happen, e.g. if too many digits
|
// Rare, but might happen, e.g. if too many digits
|
||||||
throw ExpressionHelper.evalException(ctx, "Invalid constant: " + e.getMessage());
|
throw evalException(ctx, "Invalid constant: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MethodHandle visitIdExpr(ExpressionParser.IdExprContext ctx) {
|
public MethodHandle visitIdExpr(ExpressionParser.IdExprContext ctx) {
|
||||||
Token source = ctx.source;
|
Token source = ctx.source;
|
||||||
return ExpressionHandles.call(data -> ExpressionHandles.getSlotValue(data, source));
|
return call(data -> getSlotValue(data, source));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method handle (ExecutionData)Double, returns null.
|
* Method handle (ExecutionData)Double, returns null.
|
||||||
*/
|
*/
|
||||||
private static final MethodHandle DEFAULT_RESULT =
|
private static final MethodHandle DEFAULT_RESULT =
|
||||||
ExpressionHandles.dropData(MethodHandles.constant(Double.class, null));
|
dropData(constant(Double.class, null));
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected MethodHandle defaultResult() {
|
protected MethodHandle defaultResult() {
|
||||||
@ -672,14 +685,14 @@ class CompilingVisitor extends ExpressionBaseVisitor<MethodHandle> {
|
|||||||
return oldResult;
|
return oldResult;
|
||||||
}
|
}
|
||||||
// Add a dummy Double parameter to the end
|
// Add a dummy Double parameter to the end
|
||||||
MethodHandle dummyDouble = MethodHandles.dropArguments(
|
MethodHandle dummyDouble = dropArguments(
|
||||||
result, 1, Double.class
|
result, 1, Double.class
|
||||||
);
|
);
|
||||||
// Have oldResult turn it from data->Double
|
// Have oldResult turn it from data->Double
|
||||||
MethodHandle doubledData = MethodHandles.collectArguments(
|
MethodHandle doubledData = collectArguments(
|
||||||
dummyDouble, 1, oldResult
|
dummyDouble, 1, oldResult
|
||||||
);
|
);
|
||||||
// Deduplicate the `data` parameter
|
// Deduplicate the `data` parameter
|
||||||
return ExpressionHandles.dedupData(doubledData);
|
return dedupData(doubledData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,8 @@ import java.lang.invoke.MethodHandle;
|
|||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.lang.invoke.MethodType;
|
import java.lang.invoke.MethodType;
|
||||||
|
|
||||||
|
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.COMPILED_EXPRESSION_SIG;
|
||||||
|
import static com.sk89q.worldedit.internal.expression.invoke.ExpressionHandles.safeInvoke;
|
||||||
import static java.lang.invoke.MethodType.methodType;
|
import static java.lang.invoke.MethodType.methodType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -43,7 +45,7 @@ public class ExpressionCompiler {
|
|||||||
private static final MethodHandle HANDLE_TO_CE_CONVERTER;
|
private static final MethodHandle HANDLE_TO_CE_CONVERTER;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
MethodHandle handleInvoker = MethodHandles.invoker(ExpressionHandles.COMPILED_EXPRESSION_SIG);
|
MethodHandle handleInvoker = MethodHandles.invoker(COMPILED_EXPRESSION_SIG);
|
||||||
try {
|
try {
|
||||||
HANDLE_TO_CE_CONVERTER = LambdaMetafactory.metafactory(
|
HANDLE_TO_CE_CONVERTER = LambdaMetafactory.metafactory(
|
||||||
MethodHandles.lookup(),
|
MethodHandles.lookup(),
|
||||||
@ -52,11 +54,11 @@ public class ExpressionCompiler {
|
|||||||
// Take a handle, to be converted to CompiledExpression
|
// Take a handle, to be converted to CompiledExpression
|
||||||
HANDLE_TO_CE,
|
HANDLE_TO_CE,
|
||||||
// Raw signature for SAM type
|
// Raw signature for SAM type
|
||||||
ExpressionHandles.COMPILED_EXPRESSION_SIG,
|
COMPILED_EXPRESSION_SIG,
|
||||||
// Handle to call the captured handle.
|
// Handle to call the captured handle.
|
||||||
handleInvoker,
|
handleInvoker,
|
||||||
// Actual signature at invoke time
|
// Actual signature at invoke time
|
||||||
ExpressionHandles.COMPILED_EXPRESSION_SIG
|
COMPILED_EXPRESSION_SIG
|
||||||
).dynamicInvoker().asType(HANDLE_TO_CE);
|
).dynamicInvoker().asType(HANDLE_TO_CE);
|
||||||
} catch (LambdaConversionException e) {
|
} catch (LambdaConversionException e) {
|
||||||
throw new IllegalStateException("Failed to load ExpressionCompiler MetaFactory", e);
|
throw new IllegalStateException("Failed to load ExpressionCompiler MetaFactory", e);
|
||||||
@ -66,7 +68,7 @@ public class ExpressionCompiler {
|
|||||||
public CompiledExpression compileExpression(ExpressionParser.AllStatementsContext root,
|
public CompiledExpression compileExpression(ExpressionParser.AllStatementsContext root,
|
||||||
SetMultimap<String, MethodHandle> functions) {
|
SetMultimap<String, MethodHandle> functions) {
|
||||||
MethodHandle invokable = root.accept(new CompilingVisitor(functions));
|
MethodHandle invokable = root.accept(new CompilingVisitor(functions));
|
||||||
return (CompiledExpression) ExpressionHandles.safeInvoke(
|
return (CompiledExpression) safeInvoke(
|
||||||
HANDLE_TO_CE_CONVERTER, h -> h.invoke(invokable)
|
HANDLE_TO_CE_CONVERTER, h -> h.invoke(invokable)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user