diff --git a/src/main/java/com/sk89q/worldedit/expression/parser/Parser.java b/src/main/java/com/sk89q/worldedit/expression/parser/Parser.java index e276a93e1..5aa062fd2 100644 --- a/src/main/java/com/sk89q/worldedit/expression/parser/Parser.java +++ b/src/main/java/com/sk89q/worldedit/expression/parser/Parser.java @@ -351,6 +351,7 @@ public class Parser { try { if (peek().id() == ')') { + ++position; return Functions.getFunction(identifierToken.getPosition(), identifierToken.value); } @@ -376,7 +377,7 @@ public class Parser { return Functions.getFunction(identifierToken.getPosition(), identifierToken.value, args.toArray(new RValue[args.size()])); } catch (NoSuchMethodException e) { - throw new ParserException(identifierToken.getPosition(), "Function not found", e); + throw new ParserException(identifierToken.getPosition(), "Function '"+identifierToken.value+"' not found", e); } } diff --git a/src/main/java/com/sk89q/worldedit/expression/runtime/Function.java b/src/main/java/com/sk89q/worldedit/expression/runtime/Function.java index 1db489cdd..82bf77471 100644 --- a/src/main/java/com/sk89q/worldedit/expression/runtime/Function.java +++ b/src/main/java/com/sk89q/worldedit/expression/runtime/Function.java @@ -31,7 +31,8 @@ import java.lang.reflect.Method; */ public class Function extends Node { /** - * Add this annotation on functions that don't always return the same value for the same inputs. + * Add this annotation on functions that don't always return the same value + * for the same inputs and on functions with side-effects. */ @Retention(RetentionPolicy.RUNTIME) public @interface Dynamic { } diff --git a/src/main/java/com/sk89q/worldedit/expression/runtime/Functions.java b/src/main/java/com/sk89q/worldedit/expression/runtime/Functions.java index 4fcfa5ffa..fcf165de3 100644 --- a/src/main/java/com/sk89q/worldedit/expression/runtime/Functions.java +++ b/src/main/java/com/sk89q/worldedit/expression/runtime/Functions.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Random; import com.sk89q.worldedit.expression.runtime.Function.Dynamic; @@ -281,4 +282,17 @@ public final class Functions { final int intIndex = (int) index.getValue(); return getSubBuffer(intIndex & ~1023)[intIndex & 1023] = value; } + + + private static final Random random = new Random(); + + @Dynamic + public static final double random() { + return random.nextDouble(); + } + + @Dynamic + public static final double randint(RValue max) throws EvaluationException { + return random.nextInt((int) Math.floor(max.getValue())); + } } diff --git a/src/main/java/com/sk89q/worldedit/expression/runtime/Sequence.java b/src/main/java/com/sk89q/worldedit/expression/runtime/Sequence.java index d5a0aab6e..3f7f153e1 100644 --- a/src/main/java/com/sk89q/worldedit/expression/runtime/Sequence.java +++ b/src/main/java/com/sk89q/worldedit/expression/runtime/Sequence.java @@ -69,17 +69,25 @@ public class Sequence extends Node { public Node optimize() throws EvaluationException { List newSequence = new ArrayList(); + RValue droppedLast = null; for (RValue invokable : sequence) { + droppedLast = null; invokable = invokable.optimize(); if (invokable instanceof Sequence) { for (RValue subInvokable : ((Sequence) invokable).sequence) { newSequence.add(subInvokable); } + } else if (invokable instanceof Constant) { + droppedLast = invokable; } else { newSequence.add(invokable); } } + if (droppedLast != null) { + newSequence.add(droppedLast); + } + return new Sequence(getPosition(), newSequence.toArray(new RValue[newSequence.size()])); } }