geforkt von Mirrors/FastAsyncWorldEdit
Added for loops to the expression parser, java style.
Also: - Added a test case for for - Fixed Identifiable.id() for the runtime Nodes and added missing elements to the list in Identifiable.java. - Factored keyword and character consumption into a common function.
Dieser Commit ist enthalten in:
Ursprung
f217be0bdf
Commit
effbf9f79c
@ -37,13 +37,17 @@ public interface Identifiable {
|
||||
* CharacterTokens are returned literally
|
||||
*
|
||||
* PseudoTokens:
|
||||
* p - PrefixOperator
|
||||
* p - UnaryOperator
|
||||
*
|
||||
* Invokables:
|
||||
* Nodes:
|
||||
* c - Constant
|
||||
* v - Variable
|
||||
* f - Function
|
||||
* l - LValueFunction
|
||||
* s - Sequence
|
||||
* I - Conditional
|
||||
* w - While
|
||||
* F - For
|
||||
* </pre>
|
||||
*/
|
||||
public abstract char id();
|
||||
|
@ -107,7 +107,7 @@ public class Lexer {
|
||||
characterTokens.add(';');
|
||||
}
|
||||
|
||||
private static final Set<String> keywords = new HashSet<String>(Arrays.asList("if", "else", "while", "do"));
|
||||
private static final Set<String> keywords = new HashSet<String>(Arrays.asList("if", "else", "while", "do", "for"));
|
||||
|
||||
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_]*)");
|
||||
|
@ -32,6 +32,7 @@ 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.For;
|
||||
import com.sk89q.worldedit.expression.runtime.Functions;
|
||||
import com.sk89q.worldedit.expression.runtime.RValue;
|
||||
import com.sk89q.worldedit.expression.runtime.Sequence;
|
||||
@ -119,8 +120,7 @@ public class Parser {
|
||||
final RValue truePart = parseStatements(true);
|
||||
final RValue falsePart;
|
||||
|
||||
final Token next = peek();
|
||||
if ((next instanceof KeywordToken) && ((KeywordToken) next).value.equals("else")) {
|
||||
if (hasKeyword("else")) {
|
||||
++position;
|
||||
falsePart = parseStatements(true);
|
||||
} else {
|
||||
@ -144,17 +144,29 @@ public class Parser {
|
||||
++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;
|
||||
consumeKeyword("while");
|
||||
|
||||
final RValue condition = parseBracket();
|
||||
|
||||
statements.add(new While(current.getPosition(), condition, body, true));
|
||||
break;
|
||||
}
|
||||
|
||||
case 'f': { // for
|
||||
++position;
|
||||
consumeCharacter('(');
|
||||
final RValue init = parseExpression();
|
||||
consumeCharacter(';');
|
||||
final RValue condition = parseExpression();
|
||||
consumeCharacter(';');
|
||||
final RValue increment = parseExpression();
|
||||
consumeCharacter(')');
|
||||
final RValue body = parseStatements(true);
|
||||
|
||||
statements.add(new For(current.getPosition(), init, condition, increment, body));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new ParserException(current.getPosition(), "Unimplemented keyword '" + keyword + "'");
|
||||
}
|
||||
@ -272,10 +284,7 @@ public class Parser {
|
||||
}
|
||||
|
||||
private Identifiable parseFunctionCall(IdentifierToken identifierToken) throws ParserException {
|
||||
if (peek().id() != '(') {
|
||||
throw new ParserException(peek().getPosition(), "Unexpected character in parseFunctionCall");
|
||||
}
|
||||
++position;
|
||||
consumeCharacter('(');
|
||||
|
||||
try {
|
||||
if (peek().id() == ')') {
|
||||
@ -309,26 +318,17 @@ public class Parser {
|
||||
}
|
||||
|
||||
private final RValue parseBracket() throws ParserException {
|
||||
if (peek().id() != '(') {
|
||||
throw new ParserException(peek().getPosition(), "Unexpected character in parseBracket");
|
||||
}
|
||||
++position;
|
||||
consumeCharacter('(');
|
||||
|
||||
final RValue ret = parseExpression();
|
||||
|
||||
if (peek().id() != ')') {
|
||||
throw new ParserException(peek().getPosition(), "Unmatched opening bracket");
|
||||
}
|
||||
++position;
|
||||
consumeCharacter(')');
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private final RValue parseBlock() throws ParserException {
|
||||
if (peek().id() != '{') {
|
||||
throw new ParserException(peek().getPosition(), "Unexpected character in parseBlock");
|
||||
}
|
||||
++position;
|
||||
consumeCharacter('{');
|
||||
|
||||
if (peek().id() == '}') {
|
||||
return new Sequence(peek().getPosition());
|
||||
@ -336,11 +336,39 @@ public class Parser {
|
||||
|
||||
final RValue ret = parseStatements(false);
|
||||
|
||||
if (peek().id() != '}') {
|
||||
throw new ParserException(peek().getPosition(), "Unmatched opening brace");
|
||||
}
|
||||
++position;
|
||||
consumeCharacter('}');
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private boolean hasKeyword(String keyword) {
|
||||
final Token next = peek();
|
||||
if (!(next instanceof KeywordToken)) {
|
||||
return false;
|
||||
}
|
||||
return ((KeywordToken) next).value.equals(keyword);
|
||||
}
|
||||
|
||||
private void assertCharacter(char character) throws ParserException {
|
||||
final Token next = peek();
|
||||
if (next.id() != character) {
|
||||
throw new ParserException(next.getPosition(), "Expected '" + character + "'");
|
||||
}
|
||||
}
|
||||
|
||||
private void assertKeyword(String keyword) throws ParserException {
|
||||
if (!hasKeyword(keyword)) {
|
||||
throw new ParserException(peek().getPosition(), "Expected '" + keyword + "'");
|
||||
}
|
||||
}
|
||||
|
||||
private void consumeCharacter(char character) throws ParserException {
|
||||
assertCharacter(character);
|
||||
++position;
|
||||
}
|
||||
|
||||
private void consumeKeyword(String keyword) throws ParserException {
|
||||
assertKeyword(keyword);
|
||||
++position;
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ public class Conditional extends Node {
|
||||
|
||||
@Override
|
||||
public char id() {
|
||||
return 't';
|
||||
return 'I';
|
||||
}
|
||||
|
||||
@Override
|
||||
|
45
src/main/java/com/sk89q/worldedit/expression/runtime/For.java
Normale Datei
45
src/main/java/com/sk89q/worldedit/expression/runtime/For.java
Normale Datei
@ -0,0 +1,45 @@
|
||||
package com.sk89q.worldedit.expression.runtime;
|
||||
|
||||
public class For extends Node {
|
||||
RValue init;
|
||||
RValue condition;
|
||||
RValue increment;
|
||||
RValue body;
|
||||
|
||||
public For(int position, RValue init, RValue condition, RValue increment, RValue body) {
|
||||
super(position);
|
||||
|
||||
this.init = init;
|
||||
this.condition = condition;
|
||||
this.increment = increment;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getValue() throws EvaluationException {
|
||||
int iterations = 0;
|
||||
double ret = 0.0;
|
||||
|
||||
for (init.getValue(); condition.getValue() > 0; increment.getValue()) {
|
||||
ret = body.getValue();
|
||||
++iterations;
|
||||
if (iterations > 256) {
|
||||
throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations.");
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char id() {
|
||||
return 'F';
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "for ("+init+"; "+condition+"; "+increment+") { "+body+" }";
|
||||
}
|
||||
|
||||
//TODO: optimizer
|
||||
}
|
@ -41,7 +41,7 @@ public class While extends Node {
|
||||
|
||||
@Override
|
||||
public char id() {
|
||||
return 't';
|
||||
return 'w';
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -92,6 +92,11 @@ public class ExpressionTest {
|
||||
assertEquals(5, simpleEval("c=5; a=0; do { ++a; --c; } while (c > 0) a"), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFor() throws ExpressionException {
|
||||
assertEquals(5, simpleEval("a=0; for (i=0; i<5; ++i) { ++a; } a"), 0);
|
||||
}
|
||||
|
||||
private double simpleEval(String expression) throws ExpressionException {
|
||||
return Expression.compile(expression).evaluate();
|
||||
}
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren