geforkt von Mirrors/FastAsyncWorldEdit
Added support for if/else to the expression parser. Basically same syntax as Java.
Also added a test case.
Dieser Commit ist enthalten in:
Ursprung
5071885d10
Commit
aa43975e34
@ -26,9 +26,11 @@ import java.util.Map;
|
||||
|
||||
import com.sk89q.worldedit.expression.Identifiable;
|
||||
import com.sk89q.worldedit.expression.lexer.tokens.IdentifierToken;
|
||||
import com.sk89q.worldedit.expression.lexer.tokens.KeywordToken;
|
||||
import com.sk89q.worldedit.expression.lexer.tokens.NumberToken;
|
||||
import com.sk89q.worldedit.expression.lexer.tokens.OperatorToken;
|
||||
import com.sk89q.worldedit.expression.lexer.tokens.Token;
|
||||
import com.sk89q.worldedit.expression.runtime.Conditional;
|
||||
import com.sk89q.worldedit.expression.runtime.Constant;
|
||||
import com.sk89q.worldedit.expression.runtime.Functions;
|
||||
import com.sk89q.worldedit.expression.runtime.RValue;
|
||||
@ -71,7 +73,7 @@ public class Parser {
|
||||
}
|
||||
|
||||
private RValue parse() throws ParserException {
|
||||
final RValue ret = parseMultipleStatements();
|
||||
final RValue ret = parseStatements(false);
|
||||
if (position < tokens.size()) {
|
||||
final Token token = peek();
|
||||
throw new ParserException(token.getPosition(), "Extra token at the end of the input: " + token);
|
||||
@ -79,28 +81,76 @@ public class Parser {
|
||||
return ret;
|
||||
}
|
||||
|
||||
private RValue parseMultipleStatements() throws ParserException {
|
||||
private RValue parseStatements(boolean singleStatement) throws ParserException {
|
||||
List<RValue> statements = new ArrayList<RValue>();
|
||||
loop: while (true) {
|
||||
if (position >= tokens.size()) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (peek().id()) {
|
||||
final Token current = peek();
|
||||
switch (current.id()) {
|
||||
case ';':
|
||||
++position;
|
||||
|
||||
if (singleStatement) {
|
||||
break loop;
|
||||
}
|
||||
break;
|
||||
|
||||
case '{':
|
||||
statements.add(parseBlock());
|
||||
|
||||
if (singleStatement) {
|
||||
break loop;
|
||||
}
|
||||
break;
|
||||
|
||||
case '}':
|
||||
break loop;
|
||||
|
||||
case 'k':
|
||||
final String keyword = ((KeywordToken) current).value;
|
||||
switch (keyword.charAt(0)) {
|
||||
case 'i': // if
|
||||
++position;
|
||||
final RValue condition = parseBracket();
|
||||
final RValue truePart = parseStatements(true);
|
||||
final RValue falsePart;
|
||||
|
||||
final Token next = peek();
|
||||
if ((next instanceof KeywordToken) && ((KeywordToken) next).value.equals("else")) {
|
||||
++position;
|
||||
falsePart = parseStatements(true);
|
||||
} else {
|
||||
falsePart = null;
|
||||
}
|
||||
|
||||
statements.add(new Conditional(current.getPosition(), condition, truePart, falsePart));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ParserException(current.getPosition(), "Unimplemented keyword '" + keyword + "'");
|
||||
}
|
||||
|
||||
if (singleStatement) {
|
||||
break loop;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
statements.add(parseExpression());
|
||||
break;
|
||||
|
||||
if (peek().id() == ';') {
|
||||
++position;
|
||||
if (singleStatement) {
|
||||
break loop;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else {
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -258,7 +308,7 @@ public class Parser {
|
||||
return new Sequence(peek().getPosition());
|
||||
}
|
||||
|
||||
final RValue ret = parseMultipleStatements();
|
||||
final RValue ret = parseStatements(false);
|
||||
|
||||
if (peek().id() != '}') {
|
||||
throw new ParserException(peek().getPosition(), "Unmatched opening brace");
|
||||
|
@ -0,0 +1,37 @@
|
||||
package com.sk89q.worldedit.expression.runtime;
|
||||
|
||||
public class Conditional extends Node {
|
||||
RValue condition;
|
||||
RValue truePart;
|
||||
RValue falsePart;
|
||||
|
||||
public Conditional(int position, RValue condition, RValue truePart, RValue falsePart) {
|
||||
super(position);
|
||||
|
||||
this.condition = condition;
|
||||
this.truePart = truePart;
|
||||
this.falsePart = falsePart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getValue() throws EvaluationException {
|
||||
if (condition.getValue() > 0.0) {
|
||||
return truePart.getValue();
|
||||
}
|
||||
else {
|
||||
return falsePart == null ? 0 : falsePart.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public char id() {
|
||||
return 't';
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "if ("+condition+") { "+truePart+" } else { "+falsePart+" }";
|
||||
}
|
||||
|
||||
//TODO: optimizer
|
||||
}
|
@ -10,7 +10,7 @@ import com.sk89q.worldedit.expression.parser.ParserException;
|
||||
|
||||
public class ExpressionTest {
|
||||
@Test
|
||||
public void testEvaluate() throws Exception {
|
||||
public void testEvaluate() throws ExpressionException {
|
||||
// check
|
||||
assertEquals(1-2+3, simpleEval("1-2+3"), 0);
|
||||
|
||||
@ -69,7 +69,25 @@ public class ExpressionTest {
|
||||
assertEquals(5, foo.getVariable("c").getValue(), 0);
|
||||
}
|
||||
|
||||
private double simpleEval(String expression) throws Exception {
|
||||
@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 = Expression.compile("if (1) if (0) x=4; else y=5;", "x", "y");
|
||||
expression1.evaluate(1, 2);
|
||||
assertEquals(1, expression1.getVariable("x").getValue(), 0);
|
||||
assertEquals(5, expression1.getVariable("y").getValue(), 0);
|
||||
|
||||
// test if the if construct is correctly recognized as a statement
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
private double simpleEval(String expression) throws ExpressionException {
|
||||
return Expression.compile(expression).evaluate();
|
||||
}
|
||||
}
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren