diff --git a/core/src/main/java/com/boydti/fawe/Fawe.java b/core/src/main/java/com/boydti/fawe/Fawe.java index d34315d7..96d8f90e 100644 --- a/core/src/main/java/com/boydti/fawe/Fawe.java +++ b/core/src/main/java/com/boydti/fawe/Fawe.java @@ -116,6 +116,7 @@ import com.sk89q.worldedit.internal.LocalWorldAdapter; import com.sk89q.worldedit.internal.command.WorldEditBinding; import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.runtime.ExpressionEnvironment; +import com.sk89q.worldedit.internal.expression.runtime.For; import com.sk89q.worldedit.internal.expression.runtime.Functions; import com.sk89q.worldedit.math.convolution.HeightMap; import com.sk89q.worldedit.math.interpolation.KochanekBartelsInterpolation; @@ -645,6 +646,7 @@ public class Fawe { WorldEditExpressionEnvironment.inject(); // Optimizations + features Expression.inject(); // Optimizations Functions.inject(); // Optimizations + For.inject(); // Fixes // BlockData BlockData.inject(); // Temporary fix for 1.9.4 BundledBlockData.inject(); // Add custom rotation diff --git a/core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index c4389c30..e5eade68 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -87,10 +87,7 @@ import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.UUID; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.*; import java.util.stream.Collectors; @@ -552,21 +549,30 @@ public class UtilityCommands extends MethodCommands { try { FaweLimit limit = FawePlayer.wrap(actor).getLimit(); final Expression expression = Expression.compile(input); - double[] result = new double[] { Double.NaN }; + ExecutorService executor = Executors.newSingleThreadExecutor(); + Future futureResult = executor.submit(new Callable() { + @Override + public Double call() throws Exception { + + return expression.evaluate(); + } + }); + + Double result = Double.NaN; try { - executor.invokeAll(Arrays.asList(new Callable() { - @Override - public Object call() throws Exception { - result[0] = expression.evaluate(); - return null; - } - }), limit.MAX_EXPRESSION_MS, TimeUnit.MILLISECONDS); // Default timeout of 50 milliseconds to prevent abuse. + result = futureResult.get(limit.MAX_EXPRESSION_MS, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { - throw new RuntimeException(e); + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } catch (TimeoutException e) { + futureResult.cancel(true); + e.printStackTrace(); } - executor.shutdown(); - actor.print(BBC.getPrefix() + "= " + result[0]); + + executor.shutdownNow(); + actor.print(BBC.getPrefix() + "= " + result); } catch (EvaluationException e) { actor.printError(String.format( "'%s' could not be parsed as a valid expression", input)); diff --git a/core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/For.java b/core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/For.java new file mode 100644 index 00000000..4d4cb485 --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/For.java @@ -0,0 +1,76 @@ +package com.sk89q.worldedit.internal.expression.runtime; + +import com.sk89q.worldedit.command.UtilityCommands; +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.parser.ParserException; + +public class For extends Node { + RValue init; + RValue condition; + RValue increment; + RValue body; + + public For(int position, RValue init, RValue condition, RValue increment, RValue body) { + super(position); + this.init = init; + this.condition = condition; + this.increment = increment; + this.body = body; + } + + public double getValue() throws EvaluationException { + + int iterations = 0; + double ret = 0.0D; + this.init.getValue(); + + for(; this.condition.getValue() > 0.0D; this.increment.getValue()) { + + if(iterations > 256) { + throw new EvaluationException(this.getPosition(), "Loop exceeded 256 iterations."); + } + + if(Thread.currentThread().isInterrupted()){ + throw new EvaluationException(this.getPosition(), "Thread has been interuppted."); + } + + ++iterations; + + try { + ret = this.body.getValue(); + } catch (BreakException var5) { + if(!var5.doContinue) { + return ret; + } + } + } + + return ret; + } + + public char id() { + return 'F'; + } + + public String toString() { + return "for (" + this.init + "; " + this.condition + "; " + this.increment + ") { " + this.body + " }"; + } + + public RValue optimize() throws EvaluationException { + RValue newCondition = this.condition.optimize(); + return (RValue)(newCondition instanceof Constant && newCondition.getValue() <= 0.0D?(new Sequence(this.getPosition(), new RValue[]{this.init, new Constant(this.getPosition(), 0.0D)})).optimize():new For(this.getPosition(), this.init.optimize(), newCondition, this.increment.optimize(), this.body.optimize())); + } + + public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { + this.init = this.init.bindVariables(expression, false); + this.condition = this.condition.bindVariables(expression, false); + this.increment = this.increment.bindVariables(expression, false); + this.body = this.body.bindVariables(expression, false); + return this; + } + + public static Class inject() { + return For.class; + } +} +