mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2024-12-24 10:17:39 +00:00
Added switch/case to the expression parser.
Also added a test case.
This commit is contained in:
parent
61b2ea4007
commit
a8e64fd8bc
@ -51,6 +51,7 @@ public interface Identifiable {
|
|||||||
* r - Return
|
* r - Return
|
||||||
* b - Break (includes continue)
|
* b - Break (includes continue)
|
||||||
* S - SimpleFor
|
* S - SimpleFor
|
||||||
|
* C - Switch
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public abstract char id();
|
public abstract char id();
|
||||||
|
@ -109,7 +109,7 @@ public class Lexer {
|
|||||||
characterTokens.add(':');
|
characterTokens.add(':');
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Set<String> keywords = new HashSet<String>(Arrays.asList("if", "else", "while", "do", "for", "break", "continue", "return", "switch", "case"));
|
private static final Set<String> keywords = new HashSet<String>(Arrays.asList("if", "else", "while", "do", "for", "break", "continue", "return", "switch", "case", "default"));
|
||||||
|
|
||||||
private static final Pattern numberPattern = Pattern.compile("^([0-9]*(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?)");
|
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_]*)");
|
private static final Pattern identifierPattern = Pattern.compile("^([A-Za-z][0-9A-Za-z_]*)");
|
||||||
|
@ -39,6 +39,7 @@ import com.sk89q.worldedit.expression.runtime.RValue;
|
|||||||
import com.sk89q.worldedit.expression.runtime.Return;
|
import com.sk89q.worldedit.expression.runtime.Return;
|
||||||
import com.sk89q.worldedit.expression.runtime.Sequence;
|
import com.sk89q.worldedit.expression.runtime.Sequence;
|
||||||
import com.sk89q.worldedit.expression.runtime.SimpleFor;
|
import com.sk89q.worldedit.expression.runtime.SimpleFor;
|
||||||
|
import com.sk89q.worldedit.expression.runtime.Switch;
|
||||||
import com.sk89q.worldedit.expression.runtime.While;
|
import com.sk89q.worldedit.expression.runtime.While;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -134,7 +135,11 @@ public class Parser {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'd': { // do
|
case 'd': { // do/default
|
||||||
|
if (hasKeyword("default")) {
|
||||||
|
break loop;
|
||||||
|
}
|
||||||
|
|
||||||
++position;
|
++position;
|
||||||
final RValue body = parseStatements(true);
|
final RValue body = parseStatements(true);
|
||||||
|
|
||||||
@ -199,7 +204,11 @@ public class Parser {
|
|||||||
statements.add(new Break(current.getPosition(), false));
|
statements.add(new Break(current.getPosition(), false));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'c': // continue
|
case 'c': // continue/case
|
||||||
|
if (hasKeyword("case")) {
|
||||||
|
break loop;
|
||||||
|
}
|
||||||
|
|
||||||
++position;
|
++position;
|
||||||
statements.add(new Break(current.getPosition(), true));
|
statements.add(new Break(current.getPosition(), true));
|
||||||
break;
|
break;
|
||||||
@ -211,8 +220,55 @@ public class Parser {
|
|||||||
expectSemicolon = true;
|
expectSemicolon = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 's': // switch
|
||||||
|
++position;
|
||||||
|
final RValue parameter = parseBracket();
|
||||||
|
final List<Double> values = new ArrayList<Double>();
|
||||||
|
final List<RValue> caseStatements = new ArrayList<RValue>();
|
||||||
|
RValue defaultCase = null;
|
||||||
|
|
||||||
|
consumeCharacter('{');
|
||||||
|
while (peek().id() != '}') {
|
||||||
|
if (position >= tokens.size()) {
|
||||||
|
throw new ParserException(current.getPosition(), "Expected '}' instead of EOF");
|
||||||
|
}
|
||||||
|
if (defaultCase != null) {
|
||||||
|
throw new ParserException(current.getPosition(), "Expected '}' instead of " + peek());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasKeyword("case")) {
|
||||||
|
++position;
|
||||||
|
|
||||||
|
final Token valueToken = peek();
|
||||||
|
if (!(valueToken instanceof NumberToken)) {
|
||||||
|
throw new ParserException(current.getPosition(), "Expected number instead of " + peek());
|
||||||
|
}
|
||||||
|
|
||||||
|
++position;
|
||||||
|
|
||||||
|
values.add(((NumberToken) valueToken).value);
|
||||||
|
|
||||||
|
consumeCharacter(':');
|
||||||
|
caseStatements.add(parseStatements(false));
|
||||||
|
} else if (hasKeyword("default")) {
|
||||||
|
++position;
|
||||||
|
|
||||||
|
consumeCharacter(':');
|
||||||
|
defaultCase = parseStatements(false);
|
||||||
|
} else {
|
||||||
|
throw new ParserException(current.getPosition(), "Expected 'case' or 'default' instead of " + peek());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
consumeCharacter('}');
|
||||||
|
|
||||||
|
statements.add(new Switch(current.getPosition(), parameter, values, caseStatements, defaultCase));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ParserException(current.getPosition(), "Unexpected keyword '" + keyword + "'");
|
||||||
|
}
|
||||||
|
switch (1) {
|
||||||
default:
|
default:
|
||||||
throw new ParserException(current.getPosition(), "Unimplemented keyword '" + keyword + "'");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -0,0 +1,85 @@
|
|||||||
|
package com.sk89q.worldedit.expression.runtime;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
public class Switch extends Node implements RValue {
|
||||||
|
private final RValue parameter;
|
||||||
|
private final Map<Double, Integer> valueMap = new HashMap<Double, Integer>();
|
||||||
|
private final RValue[] caseStatements;
|
||||||
|
private final RValue defaultCase;
|
||||||
|
|
||||||
|
public Switch(int position, RValue parameter, List<Double> values, List<RValue> caseStatements, RValue defaultCase) {
|
||||||
|
super(position);
|
||||||
|
this.parameter = parameter;
|
||||||
|
|
||||||
|
assert(values.size() == caseStatements.size());
|
||||||
|
|
||||||
|
for (int i = 0; i < values.size(); ++i) {
|
||||||
|
valueMap.put(values.get(i), i);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.caseStatements = caseStatements.toArray(new RValue[caseStatements.size()]);
|
||||||
|
this.defaultCase = defaultCase;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char id() {
|
||||||
|
return 'W';
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getValue() throws EvaluationException {
|
||||||
|
final double parameter = this.parameter.getValue();
|
||||||
|
|
||||||
|
try {
|
||||||
|
double ret = 0.0;
|
||||||
|
|
||||||
|
final Integer index = valueMap.get(parameter);
|
||||||
|
if (index != null) {
|
||||||
|
for (int i = index; i < caseStatements.length; ++i) {
|
||||||
|
ret = caseStatements[i].getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaultCase == null ? ret : defaultCase.getValue();
|
||||||
|
} catch (BreakException e) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
sb.append("switch (");
|
||||||
|
sb.append(parameter);
|
||||||
|
sb.append(") { ");
|
||||||
|
|
||||||
|
for (int i = 0; i < caseStatements.length; ++i) {
|
||||||
|
RValue caseStatement = caseStatements[i];
|
||||||
|
sb.append("case ");
|
||||||
|
for (Entry<Double, Integer> entry : valueMap.entrySet()) {
|
||||||
|
if (entry.getValue() == i) {
|
||||||
|
sb.append(entry.getKey());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb.append(": ");
|
||||||
|
sb.append(caseStatement);
|
||||||
|
sb.append(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defaultCase != null) {
|
||||||
|
sb.append("default: ");
|
||||||
|
sb.append(defaultCase);
|
||||||
|
sb.append(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.append("}");
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -99,6 +99,17 @@ public class ExpressionTest {
|
|||||||
assertEquals(12345, simpleEval("y=0; for (i=1,5) { y *= 10; y += i; } y"), 0);
|
assertEquals(12345, simpleEval("y=0; for (i=1,5) { y *= 10; y += i; } y"), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSwitch() throws ExpressionException {
|
||||||
|
assertEquals(523, simpleEval("x=1;y=2;z=3;switch (1) { case 1: x=5; break; case 2: y=6; break; default: z=7 } x*100+y*10+z"), 0);
|
||||||
|
assertEquals(163, simpleEval("x=1;y=2;z=3;switch (2) { case 1: x=5; break; case 2: y=6; break; default: z=7 } x*100+y*10+z"), 0);
|
||||||
|
assertEquals(127, simpleEval("x=1;y=2;z=3;switch (3) { case 1: x=5; break; case 2: y=6; break; default: z=7 } x*100+y*10+z"), 0);
|
||||||
|
|
||||||
|
assertEquals(567, simpleEval("x=1;y=2;z=3;switch (1) { case 1: x=5; case 2: y=6; default: z=7 } x*100+y*10+z"), 0);
|
||||||
|
assertEquals(167, simpleEval("x=1;y=2;z=3;switch (2) { case 1: x=5; case 2: y=6; default: z=7 } x*100+y*10+z"), 0);
|
||||||
|
assertEquals(127, simpleEval("x=1;y=2;z=3;switch (3) { case 1: x=5; case 2: y=6; default: z=7 } x*100+y*10+z"), 0);
|
||||||
|
}
|
||||||
|
|
||||||
private double simpleEval(String expressionString) throws ExpressionException {
|
private double simpleEval(String expressionString) throws ExpressionException {
|
||||||
final Expression expression = compile(expressionString);
|
final Expression expression = compile(expressionString);
|
||||||
return expression.evaluate();
|
return expression.evaluate();
|
||||||
|
Loading…
Reference in New Issue
Block a user