geforkt von Mirrors/FastAsyncWorldEdit
Added a simple for loop to the expression parser.
Syntax: for (counter = first, last) { body } Also added a test case.
Dieser Commit ist enthalten in:
Ursprung
7e13b60a51
Commit
71287299b5
@ -50,6 +50,7 @@ public interface Identifiable {
|
||||
* F - For
|
||||
* r - Return
|
||||
* b - Break (includes continue)
|
||||
* S - SimpleFor
|
||||
* </pre>
|
||||
*/
|
||||
public abstract char id();
|
||||
|
@ -35,9 +35,11 @@ import com.sk89q.worldedit.expression.runtime.Conditional;
|
||||
import com.sk89q.worldedit.expression.runtime.Constant;
|
||||
import com.sk89q.worldedit.expression.runtime.For;
|
||||
import com.sk89q.worldedit.expression.runtime.Functions;
|
||||
import com.sk89q.worldedit.expression.runtime.LValue;
|
||||
import com.sk89q.worldedit.expression.runtime.RValue;
|
||||
import com.sk89q.worldedit.expression.runtime.Return;
|
||||
import com.sk89q.worldedit.expression.runtime.Sequence;
|
||||
import com.sk89q.worldedit.expression.runtime.SimpleFor;
|
||||
import com.sk89q.worldedit.expression.runtime.Variable;
|
||||
import com.sk89q.worldedit.expression.runtime.While;
|
||||
|
||||
@ -153,15 +155,50 @@ public class Parser {
|
||||
case 'f': { // for
|
||||
++position;
|
||||
consumeCharacter('(');
|
||||
int oldPosition = position;
|
||||
final RValue init = parseExpression(true);
|
||||
consumeCharacter(';');
|
||||
final RValue condition = parseExpression(true);
|
||||
consumeCharacter(';');
|
||||
final RValue increment = parseExpression(true);
|
||||
consumeCharacter(')');
|
||||
final RValue body = parseStatements(true);
|
||||
//if ((init instanceof LValue) && )
|
||||
if (peek().id() == ';') {
|
||||
++position;
|
||||
final RValue condition = parseExpression(true);
|
||||
consumeCharacter(';');
|
||||
final RValue increment = parseExpression(true);
|
||||
consumeCharacter(')');
|
||||
final RValue body = parseStatements(true);
|
||||
|
||||
statements.add(new For(current.getPosition(), init, condition, increment, body));
|
||||
statements.add(new For(current.getPosition(), init, condition, increment, body));
|
||||
}
|
||||
else {
|
||||
position = oldPosition;
|
||||
|
||||
final Token variableToken = peek();
|
||||
if (!(variableToken instanceof IdentifierToken)) {
|
||||
throw new ParserException(variableToken.getPosition(), "Expected identifier");
|
||||
}
|
||||
|
||||
// In theory, I should have to create non-existant variables here.
|
||||
// However, the java-for parsing attempt further up already takes care of that :)
|
||||
RValue variable = variables.get(((IdentifierToken) variableToken).value);
|
||||
if (!(variable instanceof LValue)) {
|
||||
throw new ParserException(variableToken.getPosition(), "Expected variable");
|
||||
}
|
||||
|
||||
++position;
|
||||
|
||||
final Token equalsToken = peek();
|
||||
if (!(equalsToken instanceof OperatorToken) || !((OperatorToken) equalsToken).operator.equals("=")) {
|
||||
throw new ParserException(variableToken.getPosition(), "Expected '=' or a term and ';'");
|
||||
}
|
||||
++position;
|
||||
|
||||
final RValue first = parseExpression(true);
|
||||
consumeCharacter(',');
|
||||
final RValue last = parseExpression(true);
|
||||
consumeCharacter(')');
|
||||
final RValue body = parseStatements(true);
|
||||
|
||||
statements.add(new SimpleFor(current.getPosition(), (LValue) variable, first, last, body));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
58
src/main/java/com/sk89q/worldedit/expression/runtime/SimpleFor.java
Normale Datei
58
src/main/java/com/sk89q/worldedit/expression/runtime/SimpleFor.java
Normale Datei
@ -0,0 +1,58 @@
|
||||
package com.sk89q.worldedit.expression.runtime;
|
||||
|
||||
public class SimpleFor extends Node {
|
||||
LValue counter;
|
||||
RValue first;
|
||||
RValue last;
|
||||
RValue body;
|
||||
|
||||
public SimpleFor(int position, LValue counter, RValue first, RValue last, RValue body) {
|
||||
super(position);
|
||||
|
||||
this.counter = counter;
|
||||
this.first = first;
|
||||
this.last = last;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getValue() throws EvaluationException {
|
||||
int iterations = 0;
|
||||
double ret = 0.0;
|
||||
|
||||
double firstValue = first.getValue();
|
||||
double lastValue = last.getValue();
|
||||
|
||||
for (double i = firstValue; i <= lastValue; ++i) {
|
||||
if (iterations > 256) {
|
||||
throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations.");
|
||||
}
|
||||
++iterations;
|
||||
|
||||
try {
|
||||
counter.assign(i);
|
||||
ret = body.getValue();
|
||||
} catch (BreakException e) {
|
||||
if (e.doContinue) {
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char id() {
|
||||
return 'S';
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "for (" + counter + " = " + first + ", " + last + ") { " + body + " }";
|
||||
}
|
||||
|
||||
//TODO: optimizer
|
||||
}
|
@ -95,6 +95,7 @@ public class ExpressionTest {
|
||||
@Test
|
||||
public void testFor() throws ExpressionException {
|
||||
assertEquals(5, simpleEval("a=0; for (i=0; i<5; ++i) { ++a; } a"), 0);
|
||||
assertEquals(12345, simpleEval("y=0; for (i=1,5) { y *= 10; y += i; } y"), 0);
|
||||
}
|
||||
|
||||
private double simpleEval(String expression) throws ExpressionException {
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren