Added support for if/else to the expression parser. Basically same syntax as Java.

Also added a test case.
This commit is contained in:
TomyLobo
2011-11-22 04:11:58 +01:00
parent 5071885d10
commit aa43975e34
3 changed files with 112 additions and 7 deletions

View File

@ -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");

View File

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