Added a simple for loop to the expression parser.

Syntax: for (counter = first, last) { body }
Also added a test case.
This commit is contained in:
TomyLobo 2011-11-24 02:32:55 +01:00
parent 7e13b60a51
commit 71287299b5
4 changed files with 104 additions and 7 deletions

View File

@ -50,6 +50,7 @@ public interface Identifiable {
* F - For * F - For
* r - Return * r - Return
* b - Break (includes continue) * b - Break (includes continue)
* S - SimpleFor
* </pre> * </pre>
*/ */
public abstract char id(); public abstract char id();

View File

@ -35,9 +35,11 @@ import com.sk89q.worldedit.expression.runtime.Conditional;
import com.sk89q.worldedit.expression.runtime.Constant; import com.sk89q.worldedit.expression.runtime.Constant;
import com.sk89q.worldedit.expression.runtime.For; import com.sk89q.worldedit.expression.runtime.For;
import com.sk89q.worldedit.expression.runtime.Functions; 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.RValue;
import com.sk89q.worldedit.expression.runtime.Return; import com.sk89q.worldedit.expression.runtime.Return;
import com.sk89q.worldedit.expression.runtime.Sequence; 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.Variable;
import com.sk89q.worldedit.expression.runtime.While; import com.sk89q.worldedit.expression.runtime.While;
@ -153,15 +155,50 @@ public class Parser {
case 'f': { // for case 'f': { // for
++position; ++position;
consumeCharacter('('); consumeCharacter('(');
int oldPosition = position;
final RValue init = parseExpression(true); final RValue init = parseExpression(true);
consumeCharacter(';'); //if ((init instanceof LValue) && )
final RValue condition = parseExpression(true); if (peek().id() == ';') {
consumeCharacter(';'); ++position;
final RValue increment = parseExpression(true); final RValue condition = parseExpression(true);
consumeCharacter(')'); consumeCharacter(';');
final RValue body = parseStatements(true); 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; break;
} }

View File

@ -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
}

View File

@ -95,6 +95,7 @@ public class ExpressionTest {
@Test @Test
public void testFor() throws ExpressionException { public void testFor() throws ExpressionException {
assertEquals(5, simpleEval("a=0; for (i=0; i<5; ++i) { ++a; } a"), 0); 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 { private double simpleEval(String expression) throws ExpressionException {