Skip to content

Commit

Permalink
Implement continue statement
Browse files Browse the repository at this point in the history
  • Loading branch information
Franco Montenegro committed May 25, 2016
1 parent ceacd4b commit 1386702
Show file tree
Hide file tree
Showing 8 changed files with 203 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.ruke.vrjassc.translator.expression;

public class ContinueStatement extends Statement {

@Override
public String translate() {
LoopStatement loop = ((StatementBody) this.getParent()).getLoop();

if (loop == null || loop.getContinueSymbol() == null) {
return "";
}

Expression continueTrue = new AssignmentStatement(
new VariableExpression(loop.getContinueSymbol(), null),
new RawExpression("true")
);

return continueTrue.translate() + "\nexitwhen true\n";
}

}
Original file line number Diff line number Diff line change
@@ -1,10 +1,96 @@
package com.ruke.vrjassc.translator.expression;

import com.ruke.vrjassc.vrjassc.symbol.BuiltInTypeSymbol;
import com.ruke.vrjassc.vrjassc.symbol.Symbol;

/**
* Thanks to Aniki for providing the continue translation!
* http://www.hiveworkshop.com/forums/warcraft-editing-tools-277/vrjass-264114/index9.html#post2788578
*/
public class LoopStatement extends StatementBody {

protected static int LOOP_CONTINUE_COUNTER = 0;
protected Symbol _continue;

protected void registerContinue() {
if (this._continue != null) {
return;
}

this._continue = new Symbol("vr_c_" + LOOP_CONTINUE_COUNTER, null, null);
this._continue.setType(new BuiltInTypeSymbol("boolean", null, null));

this.add(new VariableStatement(this._continue, null));

LOOP_CONTINUE_COUNTER++;
}

@Override
public void add(Statement e) {
super.add(e);

if (this._continue == null && this.containsContinue(e)) {
this.registerContinue();
}
}

protected boolean containsContinue(Statement e) {
if (e == null) {
return false;
}

if (e instanceof LoopStatement) {
return false;
}

if (e instanceof ContinueStatement) {
return true;
}

if (e instanceof StatementBody) {
for (Statement s : ((StatementBody) e).getStatements()) {
if (this.containsContinue(s)) {
return true;
}
}
}

return false;
}

public Symbol getContinueSymbol() {
return this._continue;
}

@Override
public String translate() {
return "loop\n"+ super.translate() + "endloop";
String continueHeader = "";
String body = super.translate();
String continueFooter = "";

if (this._continue != null) {
continueHeader = new AssignmentStatement(
new VariableExpression(this._continue, null),
new RawExpression("false")
).translate() + "\n";

body = "loop\n" + body + "endloop\n";

continueFooter = new ExitWhenStatement(
new BooleanExpression(
new VariableExpression(this._continue, null),
BooleanExpression.Operator.EQUAL_EQUAL,
new RawExpression("false")
)
).translate() + "\n";
}

return
"loop\n" +
continueHeader +
body +
continueFooter +
"endloop";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,31 @@ protected void addVariableStatement(VariableStatement e) {
}
}
}

public LoopStatement getLoop() {
Expression loop = this;

while (loop instanceof LoopStatement == false) {
if (loop == null) {
break;
}

loop = loop.getParent();
}

if (loop instanceof LoopStatement) {
return (LoopStatement) loop;
}

return null;
}

public void add(Statement e) {
if (e == null) {
return;
}

e.setParent(this);

this.getUsedFunctions().addAll(e.getUsedFunctions());

if (e instanceof VariableStatement) {
Expand Down
11 changes: 10 additions & 1 deletion src/main/java/com/ruke/vrjassc/vrjassc/phase/ReferencePhase.java
Original file line number Diff line number Diff line change
Expand Up @@ -693,7 +693,16 @@ public Symbol visitExitWhenStatement(ExitWhenStatementContext ctx) {

return this.visit(ctx.expression());
}


@Override
public Symbol visitContinueStatement(ContinueStatementContext ctx) {
if (!this.validator.mustBeInsideOfLoop(ctx, ctx.getStart())) {
throw this.validator.getException();
}

return null;
}

@Override
public Symbol visitBreakStatement(BreakStatementContext ctx) {
if (!this.validator.mustBeInsideOfLoop(ctx, ctx.getStart())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,12 @@ public Expression visitExitWhenStatement(ExitWhenStatementContext ctx) {
BooleanExpression condition = new BooleanExpression(this.visit(ctx.expression()));
return new ExitWhenStatement(condition);
}


@Override
public Expression visitContinueStatement(ContinueStatementContext ctx) {
return new ContinueStatement();
}

@Override
public Expression visitBreakStatement(BreakStatementContext ctx) {
return new ExitWhenStatement(new RawExpression("true"));
Expand Down
48 changes: 48 additions & 0 deletions src/test/java/com/ruke/vrjassc/vrjassc/compiler/FunctionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,54 @@
import static org.junit.Assert.assertEquals;

public class FunctionTest extends TestHelper {

@Test
public void continueStatement() {
String code =
"function foo\n" +
"local integer i\n" +
"set i = 1\n" +
"loop\n" +
"exitwhen i > 9\n" +
"if i == 3 then\n" +
"continue\n" +
"endif\n" +
"if i == 5 then\n" +
"continue\n" +
"endif\n" +
"call BJDebugMsg(I2S(i))\n" +
"set i = i + 1\n" +
"endloop\n" +
"end";

String expected =
"globals\n" +
"endglobals\n" +
"function foo takes nothing returns nothing\n" +
"boolean vr_c_0=false\n" +
"local integer i=0\n" +
"set i=1\n" +
"loop\n" +
"set vr_c_0=false\n" +
"loop\n" +
"exitwhen i>9\n" +
"if i==3 then\n" +
"set vr_c_0=true\n" +
"exitwhen true\n" +
"endif\n" +
"if i==5 then\n" +
"set vr_c_0=true\n" +
"exitwhen true\n" +
"endif\n" +
"call BJDebugMsg(I2S(i))\n" +
"set i=i+1\n" +
"endloop\n" +
"exitwhen vr_c_0==false\n" +
"endloop\n" +
"endfunction";

assertEquals(expected, this.run(code));
}

@Test
public void anonymousFunction() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ public void validExitwhen() {
+ "endif\n"
+ "endfunction");
}

@Test
public void invalidContinue() {
this.expectedEx.expect(InvalidStatementException.class);
this.expectedEx.expectMessage("2:0 Can only be used inside of loops");
this.run("function foo takes nothing returns nothing\n"
+ "continue\n"
+ "endfunction");
}

@Test
public void invalidBreak() {
Expand Down
4 changes: 4 additions & 0 deletions vrjass.g4
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ statement
| whileLoopStatement
| breakStatement
| exitWhenStatement
| continueStatement
| ifStatement
| returnStatement
| NL
Expand All @@ -207,6 +208,8 @@ breakStatement: BREAK NL;

exitWhenStatement: EXITWHEN expression NL;

continueStatement: CONTINUE NL;

loopStatement:
LOOP NL
statement*
Expand Down Expand Up @@ -264,6 +267,7 @@ ARRAY: 'array';
LOCAL: 'local';
SET: 'set';
EXITWHEN: 'exitwhen';
CONTINUE: 'continue';
CALL: 'call';
GLOBALS: 'globals';
ENDGLOBALS: 'endglobals';
Expand Down

0 comments on commit 1386702

Please sign in to comment.