Added return, break and continue.

This commit is contained in:
TomyLobo 2011-11-22 17:54:43 +01:00
parent efc2209c0f
commit 1a57f6e95d
10 changed files with 156 additions and 8 deletions

View File

@ -29,6 +29,7 @@ import com.sk89q.worldedit.expression.parser.Parser;
import com.sk89q.worldedit.expression.runtime.Constant; import com.sk89q.worldedit.expression.runtime.Constant;
import com.sk89q.worldedit.expression.runtime.EvaluationException; import com.sk89q.worldedit.expression.runtime.EvaluationException;
import com.sk89q.worldedit.expression.runtime.RValue; import com.sk89q.worldedit.expression.runtime.RValue;
import com.sk89q.worldedit.expression.runtime.ReturnException;
import com.sk89q.worldedit.expression.runtime.Variable; import com.sk89q.worldedit.expression.runtime.Variable;
/** /**
@ -97,7 +98,12 @@ public class Expression {
((Variable) invokable).value = values[i]; ((Variable) invokable).value = values[i];
} }
return root.getValue(); try {
return root.getValue();
}
catch (ReturnException e) {
return e.getValue();
}
} }
public void optimize() throws EvaluationException { public void optimize() throws EvaluationException {

View File

@ -48,6 +48,8 @@ public interface Identifiable {
* I - Conditional * I - Conditional
* w - While * w - While
* F - For * F - For
* r - Return
* b - Break (includes continue)
* </pre> * </pre>
*/ */
public abstract char id(); public abstract char id();

View File

@ -107,7 +107,7 @@ public class Lexer {
characterTokens.add(';'); characterTokens.add(';');
} }
private static final Set<String> keywords = new HashSet<String>(Arrays.asList("if", "else", "while", "do", "for")); private static final Set<String> keywords = new HashSet<String>(Arrays.asList("if", "else", "while", "do", "for", "break", "continue", "return"));
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_]*)");

View File

@ -30,11 +30,13 @@ import com.sk89q.worldedit.expression.lexer.tokens.KeywordToken;
import com.sk89q.worldedit.expression.lexer.tokens.NumberToken; import com.sk89q.worldedit.expression.lexer.tokens.NumberToken;
import com.sk89q.worldedit.expression.lexer.tokens.OperatorToken; import com.sk89q.worldedit.expression.lexer.tokens.OperatorToken;
import com.sk89q.worldedit.expression.lexer.tokens.Token; import com.sk89q.worldedit.expression.lexer.tokens.Token;
import com.sk89q.worldedit.expression.runtime.Break;
import com.sk89q.worldedit.expression.runtime.Conditional; import com.sk89q.worldedit.expression.runtime.Conditional;
import com.sk89q.worldedit.expression.runtime.Constant; import com.sk89q.worldedit.expression.runtime.Constant;
import com.sk89q.worldedit.expression.runtime.For; import com.sk89q.worldedit.expression.runtime.For;
import com.sk89q.worldedit.expression.runtime.Functions; import com.sk89q.worldedit.expression.runtime.Functions;
import com.sk89q.worldedit.expression.runtime.RValue; 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.Sequence;
import com.sk89q.worldedit.expression.runtime.Variable; import com.sk89q.worldedit.expression.runtime.Variable;
import com.sk89q.worldedit.expression.runtime.While; import com.sk89q.worldedit.expression.runtime.While;
@ -163,6 +165,28 @@ public class Parser {
break; break;
} }
case 'b': // break
++position;
statements.add(new Break(current.getPosition(), false));
break;
case 'c': // continue
++position;
statements.add(new Break(current.getPosition(), true));
break;
case 'r': // return
++position;
statements.add(new Return(current.getPosition(), parseExpression(true)));
if (peek().id() == ';') {
++position;
break;
}
else {
break loop;
}
default: default:
throw new ParserException(current.getPosition(), "Unimplemented keyword '" + keyword + "'"); throw new ParserException(current.getPosition(), "Unimplemented keyword '" + keyword + "'");
} }

View File

@ -0,0 +1,28 @@
package com.sk89q.worldedit.expression.runtime;
public class Break extends Node {
boolean doContinue;
public Break(int position, boolean doContinue) {
super(position);
this.doContinue = doContinue;
}
@Override
public double getValue() throws EvaluationException {
throw new BreakException(doContinue);
}
@Override
public char id() {
return 'b';
}
@Override
public String toString() {
return doContinue ? "continue" : "break";
}
//TODO: optimizer
}

View File

@ -0,0 +1,13 @@
package com.sk89q.worldedit.expression.runtime;
public class BreakException extends EvaluationException {
private static final long serialVersionUID = 1L;
final boolean doContinue;
public BreakException(boolean doContinue) {
super(-1, doContinue ? "'continue' encountered outside a loop" : "'break' encountered outside a loop");
this.doContinue = doContinue;
}
}

View File

@ -21,11 +21,21 @@ public class For extends Node {
double ret = 0.0; double ret = 0.0;
for (init.getValue(); condition.getValue() > 0; increment.getValue()) { for (init.getValue(); condition.getValue() > 0; increment.getValue()) {
ret = body.getValue();
++iterations;
if (iterations > 256) { if (iterations > 256) {
throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations."); throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations.");
} }
++iterations;
try {
ret = body.getValue();
}
catch (BreakException e) {
if (e.doContinue) {
continue;
} else {
break;
}
}
} }
return ret; return ret;

View File

@ -0,0 +1,28 @@
package com.sk89q.worldedit.expression.runtime;
public class Return extends Node {
RValue value;
public Return(int position, RValue value) {
super(position);
this.value = value;
}
@Override
public double getValue() throws EvaluationException {
throw new ReturnException(value.getValue());
}
@Override
public char id() {
return 'r';
}
@Override
public String toString() {
return "return "+value;
}
//TODO: optimizer
}

View File

@ -0,0 +1,17 @@
package com.sk89q.worldedit.expression.runtime;
public class ReturnException extends EvaluationException {
private static final long serialVersionUID = 1L;
final double value;
public ReturnException(double value) {
super(-1);
this.value = value;
}
public double getValue() {
return value;
}
}

View File

@ -20,19 +20,39 @@ public class While extends Node {
if (footChecked) { if (footChecked) {
do { do {
ret = body.getValue();
++iterations;
if (iterations > 256) { if (iterations > 256) {
throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations."); throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations.");
} }
++iterations;
try {
ret = body.getValue();
}
catch (BreakException e) {
if (e.doContinue) {
continue;
} else {
break;
}
}
} while (condition.getValue() > 0.0); } while (condition.getValue() > 0.0);
} else { } else {
while (condition.getValue() > 0.0) { while (condition.getValue() > 0.0) {
ret = body.getValue();
++iterations;
if (iterations > 256) { if (iterations > 256) {
throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations."); throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations.");
} }
++iterations;
try {
ret = body.getValue();
}
catch (BreakException e) {
if (e.doContinue) {
continue;
} else {
break;
}
}
} }
} }