geforkt von Mirrors/FastAsyncWorldEdit
Added while loops to the expression parser.
Also added a test case. Iterations are currently limited to 256 maximum.
Dieser Commit ist enthalten in:
Ursprung
aa43975e34
Commit
f217be0bdf
@ -107,7 +107,7 @@ public class Lexer {
|
||||
characterTokens.add(';');
|
||||
}
|
||||
|
||||
private static final Set<String> keywords = new HashSet<String>(Arrays.asList("if", "else"));
|
||||
private static final Set<String> keywords = new HashSet<String>(Arrays.asList("if", "else", "while", "do"));
|
||||
|
||||
private static final Pattern numberPattern = Pattern.compile("^([0-9]*(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?)");
|
||||
private static final Pattern identifierPattern = Pattern.compile("^([A-Za-z][0-9A-Za-z_]*)");
|
||||
|
@ -36,6 +36,7 @@ import com.sk89q.worldedit.expression.runtime.Functions;
|
||||
import com.sk89q.worldedit.expression.runtime.RValue;
|
||||
import com.sk89q.worldedit.expression.runtime.Sequence;
|
||||
import com.sk89q.worldedit.expression.runtime.Variable;
|
||||
import com.sk89q.worldedit.expression.runtime.While;
|
||||
|
||||
/**
|
||||
* Processes a list of tokens into an executable tree.
|
||||
@ -112,7 +113,7 @@ public class Parser {
|
||||
case 'k':
|
||||
final String keyword = ((KeywordToken) current).value;
|
||||
switch (keyword.charAt(0)) {
|
||||
case 'i': // if
|
||||
case 'i': { // if
|
||||
++position;
|
||||
final RValue condition = parseBracket();
|
||||
final RValue truePart = parseStatements(true);
|
||||
@ -128,6 +129,31 @@ public class Parser {
|
||||
|
||||
statements.add(new Conditional(current.getPosition(), condition, truePart, falsePart));
|
||||
break;
|
||||
}
|
||||
|
||||
case 'w': { // while
|
||||
++position;
|
||||
final RValue condition = parseBracket();
|
||||
final RValue body = parseStatements(true);
|
||||
|
||||
statements.add(new While(current.getPosition(), condition, body, false));
|
||||
break;
|
||||
}
|
||||
|
||||
case 'd': { // do
|
||||
++position;
|
||||
final RValue body = parseStatements(true);
|
||||
|
||||
final Token next = peek();
|
||||
if (!(next instanceof KeywordToken) || !((KeywordToken) next).value.equals("while")) {
|
||||
throw new ParserException(current.getPosition(), "Expected while");
|
||||
}
|
||||
++position;
|
||||
final RValue condition = parseBracket();
|
||||
|
||||
statements.add(new While(current.getPosition(), condition, body, true));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new ParserException(current.getPosition(), "Unimplemented keyword '" + keyword + "'");
|
||||
|
@ -30,7 +30,11 @@ public class Conditional extends Node {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "if ("+condition+") { "+truePart+" } else { "+falsePart+" }";
|
||||
if (falsePart == null) {
|
||||
return "if ("+condition+") { "+truePart+" }";
|
||||
} else {
|
||||
return "if ("+condition+") { "+truePart+" } else { "+falsePart+" }";
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: optimizer
|
||||
|
57
src/main/java/com/sk89q/worldedit/expression/runtime/While.java
Normale Datei
57
src/main/java/com/sk89q/worldedit/expression/runtime/While.java
Normale Datei
@ -0,0 +1,57 @@
|
||||
package com.sk89q.worldedit.expression.runtime;
|
||||
|
||||
public class While extends Node {
|
||||
RValue condition;
|
||||
RValue body;
|
||||
boolean footChecked;
|
||||
|
||||
public While(int position, RValue condition, RValue body, boolean footChecked) {
|
||||
super(position);
|
||||
|
||||
this.condition = condition;
|
||||
this.body = body;
|
||||
this.footChecked = footChecked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getValue() throws EvaluationException {
|
||||
int iterations = 0;
|
||||
double ret = 0.0;
|
||||
|
||||
if (footChecked) {
|
||||
do {
|
||||
ret = body.getValue();
|
||||
++iterations;
|
||||
if (iterations > 256) {
|
||||
throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations.");
|
||||
}
|
||||
} while (condition.getValue() > 0.0);
|
||||
} else {
|
||||
while (condition.getValue() > 0.0) {
|
||||
ret = body.getValue();
|
||||
++iterations;
|
||||
if (iterations > 256) {
|
||||
throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char id() {
|
||||
return 't';
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (footChecked) {
|
||||
return "do { "+body+" } while ("+condition+")";
|
||||
} else {
|
||||
return "while ("+condition+") { "+body+" }";
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: optimizer
|
||||
}
|
@ -84,7 +84,12 @@ public class ExpressionTest {
|
||||
final Expression expression2 = Expression.compile("if (0) if (1) x=5; y=4;", "x", "y");
|
||||
expression2.evaluate(1, 2);
|
||||
assertEquals(4, expression2.getVariable("y").getValue(), 0);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWhile() throws ExpressionException {
|
||||
assertEquals(5, simpleEval("c=5; a=0; while (c > 0) { ++a; --c; } a"), 0);
|
||||
assertEquals(5, simpleEval("c=5; a=0; do { ++a; --c; } while (c > 0) a"), 0);
|
||||
}
|
||||
|
||||
private double simpleEval(String expression) throws ExpressionException {
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren