diff --git a/worldedit-core/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 b/worldedit-core/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 index 507aa3ad0..505ce3062 100644 --- a/worldedit-core/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 +++ b/worldedit-core/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 @@ -114,7 +114,7 @@ breakStatement : BREAK ; continueStatement : CONTINUE ; -returnStatement : RETURN value=expression? ; +returnStatement : RETURN value=expression ; switchStatement : SWITCH '(' target=expression ')' '{' (labels+=switchLabel ':' bodies+=statements )+ '}' ; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java index 37f0ec10e..c9cd732e9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java @@ -34,6 +34,8 @@ import java.time.Instant; import java.util.List; import java.util.Objects; +import static com.google.common.base.Preconditions.checkNotNull; + /** * Compiles and evaluates expressions. * @@ -119,7 +121,9 @@ public class Expression { Instant deadline = Instant.now().plusMillis(timeout); // evaluation exceptions are thrown out of this method - return compiledExpression.execute(new ExecutionData(slots, functions, deadline)); + Double result = compiledExpression.execute(new ExecutionData(slots, functions, deadline)); + checkNotNull(result, "Expression must result in a value"); + return result; } public void optimize() { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/CompilingVisitor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/CompilingVisitor.java index 72e5f6f64..91bea6009 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/CompilingVisitor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/CompilingVisitor.java @@ -227,19 +227,12 @@ class CompilingVisitor extends ExpressionBaseVisitor { @Override public MethodHandle visitReturnStatement(ExpressionParser.ReturnStatementContext ctx) { - // MH:returnValue = (ExecutionData)Double - MethodHandle returnValue; - if (ctx.value != null) { - returnValue = evaluate(ctx.value).handle; - } else { - returnValue = defaultResult(); - } return MethodHandles.filterArguments( // take the (Double)Double return statement RETURN_STATEMENT_BASE, 0, // map the Double back to ExecutionData via the returnValue - returnValue + evaluate(ctx.value).handle ); } diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java index acb5d6961..8508a2640 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java @@ -103,6 +103,12 @@ class ExpressionTest extends BaseExpressionTest { () -> compile("x()")); assertEquals(0, e.getPosition(), "Error position"); } + { + // verify that you must return a value + ExpressionException e = assertThrows(ExpressionException.class, + () -> compile("return")); + assertEquals(6, e.getPosition(), "Error position"); + } assertThrows(ExpressionException.class, () -> compile("(")); assertThrows(ExpressionException.class, @@ -156,6 +162,24 @@ class ExpressionTest extends BaseExpressionTest { public void testWhile() throws ExpressionException { checkTestCase("c=5; a=0; while (c > 0) { ++a; --c; } a", 5); checkTestCase("c=5; a=0; do { ++a; --c; } while (c > 0); a", 5); + checkTestCase("" + + "c=5;" + + "a=0;" + + "while (c > 0) {" + + " ++a;" + + " --c;" + + " if (c == 1) break;" + + "}" + + "a", 4); + checkTestCase("" + + "c=5;" + + "a=0;" + + "while (c > 0) {" + + " ++a;" + + " if (a < 5) continue;" + + " --c;" + + "}" + + "a", 9); } @Test