Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-11-10 05:20:04 +01:00
Added switch/case to the expression parser.
Also added a test case.
Dieser Commit ist enthalten in:
Ursprung
61b2ea4007
Commit
a8e64fd8bc
@ -51,6 +51,7 @@ public interface Identifiable {
|
||||
* r - Return
|
||||
* b - Break (includes continue)
|
||||
* S - SimpleFor
|
||||
* C - Switch
|
||||
* </pre>
|
||||
*/
|
||||
public abstract char id();
|
||||
|
@ -109,7 +109,7 @@ public class Lexer {
|
||||
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 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.Sequence;
|
||||
import com.sk89q.worldedit.expression.runtime.SimpleFor;
|
||||
import com.sk89q.worldedit.expression.runtime.Switch;
|
||||
import com.sk89q.worldedit.expression.runtime.While;
|
||||
|
||||
/**
|
||||
@ -134,7 +135,11 @@ public class Parser {
|
||||
break;
|
||||
}
|
||||
|
||||
case 'd': { // do
|
||||
case 'd': { // do/default
|
||||
if (hasKeyword("default")) {
|
||||
break loop;
|
||||
}
|
||||
|
||||
++position;
|
||||
final RValue body = parseStatements(true);
|
||||
|
||||
@ -199,7 +204,11 @@ public class Parser {
|
||||
statements.add(new Break(current.getPosition(), false));
|
||||
break;
|
||||
|
||||
case 'c': // continue
|
||||
case 'c': // continue/case
|
||||
if (hasKeyword("case")) {
|
||||
break loop;
|
||||
}
|
||||
|
||||
++position;
|
||||
statements.add(new Break(current.getPosition(), true));
|
||||
break;
|
||||
@ -211,8 +220,55 @@ public class Parser {
|
||||
expectSemicolon = true;
|
||||
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:
|
||||
throw new ParserException(current.getPosition(), "Unimplemented keyword '" + keyword + "'");
|
||||
}
|
||||
|
||||
break;
|
||||
|
85
src/main/java/com/sk89q/worldedit/expression/runtime/Switch.java
Normale Datei
85
src/main/java/com/sk89q/worldedit/expression/runtime/Switch.java
Normale Datei
@ -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);
|
||||
}
|
||||
|
||||
@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 {
|
||||
final Expression expression = compile(expressionString);
|
||||
return expression.evaluate();
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren