mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2025-07-01 19:06:41 +00:00
The expression parser can now parse more than a simple expression
- Added sequencing (; and {}). - Added =, +=, -=, *=, /=, %=, ^= to the expression parser. (left-associative for now, will change later) - Added pre-increment(++) and pre-decrement(--) operators. - Adjusted/added tests.
This commit is contained in:
@ -28,6 +28,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sk89q.worldedit.expression.Identifiable;
|
||||
import com.sk89q.worldedit.expression.lexer.tokens.CharacterToken;
|
||||
import com.sk89q.worldedit.expression.lexer.tokens.IdentifierToken;
|
||||
import com.sk89q.worldedit.expression.lexer.tokens.NumberToken;
|
||||
import com.sk89q.worldedit.expression.lexer.tokens.OperatorToken;
|
||||
@ -36,6 +37,7 @@ import com.sk89q.worldedit.expression.runtime.Constant;
|
||||
import com.sk89q.worldedit.expression.runtime.Functions;
|
||||
import com.sk89q.worldedit.expression.runtime.Invokable;
|
||||
import com.sk89q.worldedit.expression.runtime.Operators;
|
||||
import com.sk89q.worldedit.expression.runtime.Sequence;
|
||||
|
||||
public class Parser {
|
||||
private final class NullToken extends Token {
|
||||
@ -66,7 +68,7 @@ public class Parser {
|
||||
}
|
||||
|
||||
private Invokable parse() throws ParserException {
|
||||
final Invokable ret = parseInternal();
|
||||
final Invokable ret = parseInternal(true);
|
||||
if (position < tokens.size()) {
|
||||
final Token token = peek();
|
||||
throw new ParserException(token.getPosition(), "Extra token at the end of the input: " + token);
|
||||
@ -74,7 +76,7 @@ public class Parser {
|
||||
return ret;
|
||||
}
|
||||
|
||||
private final Invokable parseInternal() throws ParserException {
|
||||
private final Invokable parseInternal(boolean isStatement) throws ParserException {
|
||||
LinkedList<Identifiable> halfProcessed = new LinkedList<Identifiable>();
|
||||
|
||||
// process brackets, numbers, functions, variables and detect prefix operators
|
||||
@ -112,8 +114,15 @@ public class Parser {
|
||||
expressionStart = false;
|
||||
break;
|
||||
|
||||
case '{':
|
||||
halfProcessed.add(parseBlock());
|
||||
halfProcessed.add(new CharacterToken(-1, ';'));
|
||||
expressionStart = false;
|
||||
break;
|
||||
|
||||
case ',':
|
||||
case ')':
|
||||
case '}':
|
||||
break loop;
|
||||
|
||||
case 'o':
|
||||
@ -135,8 +144,57 @@ public class Parser {
|
||||
}
|
||||
}
|
||||
|
||||
// process binary operators
|
||||
return processBinaryOps(halfProcessed, binaryOpMaps.length - 1);
|
||||
if (isStatement) {
|
||||
return processStatement(halfProcessed);
|
||||
}
|
||||
else {
|
||||
// process binary operators
|
||||
return processExpression(halfProcessed);
|
||||
}
|
||||
}
|
||||
|
||||
private Invokable processStatement(LinkedList<Identifiable> input) throws ParserException {
|
||||
LinkedList<Identifiable> lhs = new LinkedList<Identifiable>();
|
||||
LinkedList<Identifiable> rhs = new LinkedList<Identifiable>();
|
||||
boolean semicolonFound = false;
|
||||
|
||||
for (Iterator<Identifiable> it = input.descendingIterator(); it.hasNext();) {
|
||||
Identifiable identifiable = it.next();
|
||||
if (semicolonFound) {
|
||||
lhs.addFirst(identifiable);
|
||||
}
|
||||
else {
|
||||
if (identifiable.id() == ';') {
|
||||
semicolonFound = true;
|
||||
}
|
||||
else {
|
||||
rhs.addFirst(identifiable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lhs.isEmpty()) {
|
||||
if (rhs.isEmpty()) {
|
||||
return new Sequence(semicolonFound ? input.get(0).getPosition() : -1);
|
||||
}
|
||||
|
||||
return processExpression(rhs);
|
||||
}
|
||||
else if (rhs.isEmpty()) {
|
||||
return processStatement(lhs);
|
||||
}
|
||||
else {
|
||||
assert(semicolonFound);
|
||||
|
||||
Invokable rhsInvokable = processExpression(rhs);
|
||||
Invokable lhsInvokable = processStatement(lhs);
|
||||
|
||||
return new Sequence(position, lhsInvokable, rhsInvokable);
|
||||
}
|
||||
}
|
||||
|
||||
private Invokable processExpression(LinkedList<Identifiable> input) throws ParserException {
|
||||
return processBinaryOps(input, binaryOpMaps.length - 1);
|
||||
}
|
||||
|
||||
private static final Map<String, String>[] binaryOpMaps;
|
||||
@ -146,6 +204,7 @@ public class Parser {
|
||||
final Object[][][] binaryOps = {
|
||||
{
|
||||
{ "^", "pow" },
|
||||
{ "**", "pow" },
|
||||
},
|
||||
{
|
||||
{ "*", "mul" },
|
||||
@ -177,6 +236,15 @@ public class Parser {
|
||||
{
|
||||
{ "||", "or" },
|
||||
},
|
||||
{
|
||||
{ "=", "ass" },
|
||||
{ "+=", "aadd" },
|
||||
{ "-=", "asub" },
|
||||
{ "*=", "amul" },
|
||||
{ "/=", "adiv" },
|
||||
{ "%=", "amod" },
|
||||
{ "^=", "aexp" },
|
||||
},
|
||||
};
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -205,6 +273,8 @@ public class Parser {
|
||||
unaryOpMap.put("-", "neg");
|
||||
unaryOpMap.put("!", "not");
|
||||
unaryOpMap.put("~", "inv");
|
||||
unaryOpMap.put("++", "inc");
|
||||
unaryOpMap.put("--", "dec");
|
||||
}
|
||||
|
||||
private Invokable processBinaryOps(LinkedList<Identifiable> input, int level) throws ParserException {
|
||||
@ -315,7 +385,7 @@ public class Parser {
|
||||
List<Invokable> args = new ArrayList<Invokable>();
|
||||
|
||||
loop: while (true) {
|
||||
args.add(parseInternal());
|
||||
args.add(parseInternal(false));
|
||||
|
||||
final Token current = peek();
|
||||
++position;
|
||||
@ -345,7 +415,7 @@ public class Parser {
|
||||
}
|
||||
++position;
|
||||
|
||||
final Invokable ret = parseInternal();
|
||||
final Invokable ret = parseInternal(false);
|
||||
|
||||
if (peek().id() != ')') {
|
||||
throw new ParserException(peek().getPosition(), "Unmatched opening bracket");
|
||||
@ -354,4 +424,20 @@ public class Parser {
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private final Invokable parseBlock() throws ParserException {
|
||||
if (peek().id() != '{') {
|
||||
throw new ParserException(peek().getPosition(), "Unexpected character in parseBlock");
|
||||
}
|
||||
++position;
|
||||
|
||||
final Invokable ret = parseInternal(true);
|
||||
|
||||
if (peek().id() != '}') {
|
||||
throw new ParserException(peek().getPosition(), "Unmatched opening brace");
|
||||
}
|
||||
++position;
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user