public int makeShape(final Region region, final Vector3 zero, final Vector3 unit, final Pattern pattern, final String expressionString, final boolean hollow) throws ExpressionException, MaxChangedBlocksException { final Expression expression = Expression.compile(expressionString, "x", "y", "z", "type", "data"); expression.optimize(); final RValue typeVariable = expression.getVariable("type", false); final RValue dataVariable = expression.getVariable("data", false); final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(this, unit, zero); expression.setEnvironment(environment); final ArbitraryShape shape = new ArbitraryShape(region) { @Override protected BaseBlock getMaterial(int x, int y, int z, BaseBlock defaultMaterial) { final Vector3 current = Vector3.at(x, y, z); environment.setCurrentBlock(current); final Vector3 scaled = current.subtract(zero).divide(unit); try { if (expression.evaluate(scaled.getX(), scaled.getY(), scaled.getZ(), defaultMaterial.getBlockType().getLegacyId(), 0) <= 0) { // TODO data return null; } return LegacyMapper.getInstance().getBlockFromLegacy((int) typeVariable.getValue(), (int) dataVariable.getValue()).toBaseBlock(); } catch (Exception e) { log.log(Level.WARNING, "Failed to create shape", e); return null; } } }; return shape.generate(this, pattern, hollow); }
/** * Try to parse numeric input as either a number or a mathematical expression. * * @param input input * @return a number * @throws ParameterException thrown on parse error */ private @Nullable Double parseNumericInput(@Nullable String input) throws ParameterException { if (input == null) { return null; } try { return Double.parseDouble(input); } catch (NumberFormatException e1) { try { Expression expression = Expression.compile(input); return expression.evaluate(); } catch (EvaluationException e) { throw new ParameterException(String.format( "Expected '%s' to be a valid number (or a valid mathematical expression)", input)); } catch (ExpressionException e) { throw new ParameterException(String.format( "Expected '%s' to be a number or valid math expression (error: %s)", input, e.getMessage())); } } }
public static Expression compile(String expression, String... variableNames) throws ExpressionException { return new Expression(expression, variableNames); }
@Dynamic public static double megabuf(RValue index, double value) throws EvaluationException { return setBufferItem(Expression.getInstance().getFunctions().megabuf, (int) index.getValue(), value); }
public int makeBiomeShape(final Region region, final Vector3 zero, final Vector3 unit, final BaseBiome biomeType, final String expressionString, final boolean hollow) throws ExpressionException, MaxChangedBlocksException { final Vector2 zero2D = zero.toVector2(); final Vector2 unit2D = unit.toVector2(); final Expression expression = Expression.compile(expressionString, "x", "z"); expression.optimize(); final EditSession editSession = this; final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(editSession, unit, zero); expression.setEnvironment(environment); final ArbitraryBiomeShape shape = new ArbitraryBiomeShape(region) { @Override protected BaseBiome getBiome(int x, int z, BaseBiome defaultBiomeType) { final Vector2 current = Vector2.at(x, z); environment.setCurrentBlock(current.toVector3(0)); final Vector2 scaled = current.subtract(zero2D).divide(unit2D); try { if (expression.evaluate(scaled.getX(), scaled.getZ()) <= 0) { return null; // TODO should return OUTSIDE? seems to cause issues otherwise, workedaround for now } // TODO: Allow biome setting via a script variable (needs BiomeType<->int mapping) return defaultBiomeType; } catch (Exception e) { log.log(Level.WARNING, "Failed to create shape", e); return null; } } }; return shape.generate(this, biomeType, hollow); }
@Test public void testAssign() throws ExpressionException { Expression foo = compile("{a=x} b=y; c=z", "x", "y", "z", "a", "b", "c"); foo.evaluate(2, 3, 5); assertEquals(2, foo.getVariable("a", false).getValue(), 0); assertEquals(3, foo.getVariable("b", false).getValue(), 0); assertEquals(5, foo.getVariable("c", false).getValue(), 0); }
@Override public Mask parseFromInput(String input, ParserContext context) throws InputParseException { if (!input.startsWith("=")) { return null; } try { Expression exp = Expression.compile(input.substring(1), "x", "y", "z"); WorldEditExpressionEnvironment env = new WorldEditExpressionEnvironment( Request.request().getEditSession(), Vector3.ONE, Vector3.ZERO); exp.setEnvironment(env); return new ExpressionMask(exp); } catch (ExpressionException e) { throw new InputParseException("Invalid expression: " + e.getMessage()); } } }
private double simpleEval(String expressionString) throws ExpressionException { final Expression expression = compile(expressionString); expression.setEnvironment(new ExpressionEnvironment() { @Override public int getBlockType(double x, double y, double z) { return (int) x; } @Override public int getBlockData(double x, double y, double z) { return (int) y; } @Override public int getBlockTypeAbs(double x, double y, double z) { return (int) x*10; } @Override public int getBlockDataAbs(double x, double y, double z) { return (int) y*10; } @Override public int getBlockTypeRel(double x, double y, double z) { return (int) x*100; } @Override public int getBlockDataRel(double x, double y, double z) { return (int) y*100; } }); return expression.evaluate(); }
public RValue bind(Expression expression, boolean isLValue) throws ParserException { final RValue variable = expression.getVariable(name, isLValue); if (variable == null) { throw new ParserException(getPosition(), "Variable '" + name + "' not found"); } return variable; }
@Override public boolean test(BlockVector2 vector) { try { return expression.evaluate(vector.getX(), 0, vector.getZ()) > 0; } catch (EvaluationException e) { return false; } }
@Override public boolean test(BlockVector3 vector) { try { if (expression.getEnvironment() instanceof WorldEditExpressionEnvironment) { ((WorldEditExpressionEnvironment) expression.getEnvironment()).setCurrentBlock(vector.toVector3()); } return expression.evaluate(vector.getX(), vector.getY(), vector.getZ()) > 0; } catch (EvaluationException e) { return false; } }
@Dynamic public static double query(RValue x, RValue y, RValue z, RValue type, RValue data) throws EvaluationException { final double xp = x.getValue(); final double yp = y.getValue(); final double zp = z.getValue(); final ExpressionEnvironment environment = Expression.getInstance().getEnvironment(); // Read values from world final double typeId = environment.getBlockType(xp, yp, zp); final double dataValue = environment.getBlockData(xp, yp, zp); return queryInternal(type, data, typeId, dataValue); }
/** * Create a new instance. * * @param expression the expression * @throws ExpressionException thrown if there is an error with the expression */ public ExpressionMask(String expression) throws ExpressionException { checkNotNull(expression); this.expression = Expression.compile(expression, "x", "y", "z"); }
@Test public void testIf() throws ExpressionException { assertEquals(40, simpleEval("if (1) x=4; else y=5; x*10+y;"), 0); assertEquals(5, simpleEval("if (0) x=4; else y=5; x*10+y;"), 0); // test 'dangling else' final Expression expression1 = compile("if (1) if (0) x=4; else y=5;", "x", "y"); expression1.evaluate(1, 2); assertEquals(1, expression1.getVariable("x", false).getValue(), 0); assertEquals(5, expression1.getVariable("y", false).getValue(), 0); // test if the if construct is correctly recognized as a statement final Expression expression2 = compile("if (0) if (1) x=5; y=4;", "x", "y"); expression2.evaluate(1, 2); assertEquals(4, expression2.getVariable("y", false).getValue(), 0); }
@Override public LValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { final RValue variable = expression.getVariable(name, preferLValue); if (variable == null) { throw new ParserException(getPosition(), "Variable '" + name + "' not found"); } return (LValue) variable; }
@Override protected BaseBiome getBiome(int x, int z, BaseBiome defaultBiomeType) { final Vector2 current = Vector2.at(x, z); environment.setCurrentBlock(current.toVector3(0)); final Vector2 scaled = current.subtract(zero2D).divide(unit2D); try { if (expression.evaluate(scaled.getX(), scaled.getZ()) <= 0) { return null; // TODO should return OUTSIDE? seems to cause issues otherwise, workedaround for now } // TODO: Allow biome setting via a script variable (needs BiomeType<->int mapping) return defaultBiomeType; } catch (Exception e) { log.log(Level.WARNING, "Failed to create shape", e); return null; } } };
@Dynamic public static double queryAbs(RValue x, RValue y, RValue z, RValue type, RValue data) throws EvaluationException { final double xp = x.getValue(); final double yp = y.getValue(); final double zp = z.getValue(); final ExpressionEnvironment environment = Expression.getInstance().getEnvironment(); // Read values from world final double typeId = environment.getBlockTypeAbs(xp, yp, zp); final double dataValue = environment.getBlockDataAbs(xp, yp, zp); return queryInternal(type, data, typeId, dataValue); }
@Dynamic public static double megabuf(RValue index) throws EvaluationException { return getBufferItem(Expression.getInstance().getFunctions().megabuf, (int) index.getValue()); }
/** * Create a new instance. * * @param expression the expression * @throws ExpressionException thrown if there is an error with the expression */ public ExpressionMask2D(String expression) throws ExpressionException { checkNotNull(expression); this.expression = Expression.compile(expression, "x", "z"); }