From 153b04ed1c1626ba98ef8cefb175e06a03f229e6 Mon Sep 17 00:00:00 2001 From: gnembon Date: Mon, 23 Mar 2020 14:14:25 -0300 Subject: [PATCH] 'break' and 'continue' support for 'scan' and 'volume' --- docs/scarpet/api/BlockIterations.md | 8 +++++ .../language/LoopsAndHigherOrderFunctions.md | 7 ++-- .../java/carpet/script/CarpetExpression.java | 36 ++++++++++++++++--- 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/docs/scarpet/api/BlockIterations.md b/docs/scarpet/api/BlockIterations.md index 304815cf..4f2085ff 100644 --- a/docs/scarpet/api/BlockIterations.md +++ b/docs/scarpet/api/BlockIterations.md @@ -8,11 +8,19 @@ Evaluates expression over area of blocks defined by its center (`cx, cy, cz`), e by `dx, dy, dz` blocks, or optionally in negative with `d` coords, and `p` coords in positive values. `expr` receives `_x, _y, _z` as coords of current analyzed block and `_`, which represents the block itself. +Returns number of successful evaluations of `expr` (with `true` boolean result) unless called in void context, +which would cause the expression not be evaluated for their boolean value. + +`scan` also handles `continue` and `break` statements, using `continue`'s return value to use in place of expression +return value. `break` return value has no effect. + ### `volume(x1, y1, z1, x2, y2, z2, expr)` Evaluates expression for each block in the area, the same as the `scan`function, but using two opposite corners of the rectangular cuboid. Any corners can be specified, its like you would do with `/fill` command. +For return value and handling `break` and `continue` statements, see `scan` function above. + ### `neighbours(x, y, z), neighbours(block), neighbours(l(x,y,z))` Returns the list of 6 neighbouring blocks to the argument. Commonly used with other loop functions like `for`. diff --git a/docs/scarpet/language/LoopsAndHigherOrderFunctions.md b/docs/scarpet/language/LoopsAndHigherOrderFunctions.md index 65dc2715..82fdacd3 100644 --- a/docs/scarpet/language/LoopsAndHigherOrderFunctions.md +++ b/docs/scarpet/language/LoopsAndHigherOrderFunctions.md @@ -10,16 +10,17 @@ and maps, where the iterator returns all the map keys ### `break(), break(expr), continue(), continue(expr)` These allow to control execution of a loop either skipping current iteration code, using `continue`, or finishing the -current loop, using `break`. `break` and `continue` can only be used inside `for, while, loop, map, filter and reduce` +current loop, using `break`. `break` and `continue` can only be used inside `for`, `c_for`, `while`, `loop`, `map`, +`filter`, `reduce` as well as Minecraft API block loops, `scan` and `volume` functions, while `break` can be used in `first` as well. Outside of the internal expressions of these functions, -calling `break` or `continue` will cause an error. In case of the nexted loops, and more complex setups, use +calling `break` or `continue` will cause an error. In case of the nested loops, and more complex setups, use custom `try` and `throw` setup. Please check corresponding loop function description what `continue` and `break` do in their contexts, but in general case, passed values to `break` and `continue` will be used in place of the return value of the internal iteration expression. -### `cfor(init, condition, increment, body)` +### `c_for(init, condition, increment, body)` `c_for` Mimics c-style tri-arg (plus body) for loops. Return value of `c_for` is number of iterations performed in the loop. Unlike other loops, the `body` is not provided with pre-initialized `_` style variables - all initialization diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index da72d743..a52e5c77 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -11,11 +11,13 @@ import carpet.mixins.PointOfInterest_scarpetMixin; import carpet.mixins.ServerChunkManager_scarpetMixin; import carpet.script.Fluff.TriFunction; import carpet.script.bundled.Module; +import carpet.CarpetSettings; +import carpet.script.exception.BreakStatement; import carpet.script.exception.CarpetExpressionException; +import carpet.script.exception.ContinueStatement; import carpet.script.exception.ExitStatement; import carpet.script.exception.ExpressionException; import carpet.script.exception.InternalExpressionException; -import carpet.CarpetSettings; import carpet.script.value.BlockValue; import carpet.script.value.EntityValue; import carpet.script.value.FunctionValue; @@ -1824,7 +1826,7 @@ public class CarpetExpression LazyValue _z = c.getVariable("_z"); LazyValue __ = c.getVariable("_"); int sCount = 0; - for (int y=cy-yrange; y <= cy+yprange; y++) + outer:for (int y=cy-yrange; y <= cy+yprange; y++) { int yFinal = y; c.setVariable("_y", (c_, t_) -> new NumericValue(yFinal).bindTo("_y")); @@ -1839,7 +1841,19 @@ public class CarpetExpression c.setVariable("_z", (c_, t_) -> new NumericValue(zFinal).bindTo("_z")); Value blockValue = BlockValue.fromCoords(((CarpetContext)c), xFinal,yFinal,zFinal).bindTo("_"); c.setVariable( "_", (cc_, t_c) -> blockValue); - Value result = expr.evalValue(c, t); + Value result; + try + { + result = expr.evalValue(c, t); + } + catch (ContinueStatement notIgnored) + { + result = notIgnored.retval; + } + catch (BreakStatement notIgnored) + { + break outer; + } if (t != Context.VOID && result.getBoolean()) { sCount += 1; @@ -1878,7 +1892,7 @@ public class CarpetExpression LazyValue _z = c.getVariable("_z"); LazyValue __ = c.getVariable("_"); int sCount = 0; - for (int y=miny; y <= maxy; y++) + outer:for (int y=miny; y <= maxy; y++) { int yFinal = y; c.setVariable("_y", (c_, t_) -> new NumericValue(yFinal).bindTo("_y")); @@ -1892,7 +1906,19 @@ public class CarpetExpression c.setVariable("_z", (c_, t_) -> new NumericValue(zFinal).bindTo("_z")); Value blockValue = BlockValue.fromCoords(((CarpetContext)c), xFinal,yFinal,zFinal).bindTo("_"); c.setVariable( "_", (cc_, t_c) -> blockValue); - Value result = expr.evalValue(c, t); + Value result; + try + { + result = expr.evalValue(c, t); + } + catch (ContinueStatement notIgnored) + { + result = notIgnored.retval; + } + catch (BreakStatement notIgnored) + { + break outer; + } if (t != Context.VOID && result.getBoolean()) { sCount += 1;