mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2024-12-23 17:57:38 +00:00
Added support for if/else to the expression parser. Basically same syntax as Java.
Also added a test case.
This commit is contained in:
parent
5071885d10
commit
aa43975e34
@ -26,9 +26,11 @@ import java.util.Map;
|
|||||||
|
|
||||||
import com.sk89q.worldedit.expression.Identifiable;
|
import com.sk89q.worldedit.expression.Identifiable;
|
||||||
import com.sk89q.worldedit.expression.lexer.tokens.IdentifierToken;
|
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.NumberToken;
|
||||||
import com.sk89q.worldedit.expression.lexer.tokens.OperatorToken;
|
import com.sk89q.worldedit.expression.lexer.tokens.OperatorToken;
|
||||||
import com.sk89q.worldedit.expression.lexer.tokens.Token;
|
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.Constant;
|
||||||
import com.sk89q.worldedit.expression.runtime.Functions;
|
import com.sk89q.worldedit.expression.runtime.Functions;
|
||||||
import com.sk89q.worldedit.expression.runtime.RValue;
|
import com.sk89q.worldedit.expression.runtime.RValue;
|
||||||
@ -71,7 +73,7 @@ public class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private RValue parse() throws ParserException {
|
private RValue parse() throws ParserException {
|
||||||
final RValue ret = parseMultipleStatements();
|
final RValue ret = parseStatements(false);
|
||||||
if (position < tokens.size()) {
|
if (position < tokens.size()) {
|
||||||
final Token token = peek();
|
final Token token = peek();
|
||||||
throw new ParserException(token.getPosition(), "Extra token at the end of the input: " + token);
|
throw new ParserException(token.getPosition(), "Extra token at the end of the input: " + token);
|
||||||
@ -79,28 +81,76 @@ public class Parser {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
private RValue parseMultipleStatements() throws ParserException {
|
private RValue parseStatements(boolean singleStatement) throws ParserException {
|
||||||
List<RValue> statements = new ArrayList<RValue>();
|
List<RValue> statements = new ArrayList<RValue>();
|
||||||
loop: while (true) {
|
loop: while (true) {
|
||||||
if (position >= tokens.size()) {
|
if (position >= tokens.size()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (peek().id()) {
|
final Token current = peek();
|
||||||
|
switch (current.id()) {
|
||||||
case ';':
|
case ';':
|
||||||
++position;
|
++position;
|
||||||
|
|
||||||
|
if (singleStatement) {
|
||||||
|
break loop;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '{':
|
case '{':
|
||||||
statements.add(parseBlock());
|
statements.add(parseBlock());
|
||||||
|
|
||||||
|
if (singleStatement) {
|
||||||
|
break loop;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '}':
|
case '}':
|
||||||
break loop;
|
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:
|
default:
|
||||||
statements.add(parseExpression());
|
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());
|
return new Sequence(peek().getPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
final RValue ret = parseMultipleStatements();
|
final RValue ret = parseStatements(false);
|
||||||
|
|
||||||
if (peek().id() != '}') {
|
if (peek().id() != '}') {
|
||||||
throw new ParserException(peek().getPosition(), "Unmatched opening brace");
|
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 {
|
public class ExpressionTest {
|
||||||
@Test
|
@Test
|
||||||
public void testEvaluate() throws Exception {
|
public void testEvaluate() throws ExpressionException {
|
||||||
// check
|
// check
|
||||||
assertEquals(1-2+3, simpleEval("1-2+3"), 0);
|
assertEquals(1-2+3, simpleEval("1-2+3"), 0);
|
||||||
|
|
||||||
@ -69,7 +69,25 @@ public class ExpressionTest {
|
|||||||
assertEquals(5, foo.getVariable("c").getValue(), 0);
|
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();
|
return Expression.compile(expression).evaluate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user