JS backend: support for while/do while with complex conditions

This commit is contained in:
Michael Nedzelsky
2014-08-20 14:46:55 +04:00
parent 53f0e6dcd2
commit d969e58b88
6 changed files with 193 additions and 6 deletions
@@ -25,4 +25,20 @@ public class WhileTest extends AbstractExpressionTest {
public void testWhileWithComplexOneStatement() throws Exception {
checkFooBoxIsOk();
}
public void testWhileWithComplexCondition() throws Exception {
checkFooBoxIsOk();
}
public void testWhileWithComplexConditionAndContinue() throws Exception {
checkFooBoxIsOk();
}
public void testDoWhileWithComplexCondition() throws Exception {
checkFooBoxIsOk();
}
public void testDoWhileWithComplexConditionAndContinue() throws Exception {
checkFooBoxIsOk();
}
}
@@ -29,6 +29,7 @@ import org.jetbrains.jet.lang.resolve.constants.NullValue;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeUtils;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.k2js.translate.context.TemporaryVariable;
import org.jetbrains.k2js.translate.context.TranslationContext;
import org.jetbrains.k2js.translate.declaration.ClassTranslator;
import org.jetbrains.k2js.translate.expression.foreach.ForTranslator;
@@ -237,19 +238,44 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
@Override
@NotNull
public JsNode visitWhileExpression(@NotNull JetWhileExpression expression, @NotNull TranslationContext context) {
return createWhile(new JsWhile(), expression, context);
return createWhile(false, expression, context);
}
@Override
@NotNull
public JsNode visitDoWhileExpression(@NotNull JetDoWhileExpression expression, @NotNull TranslationContext context) {
return createWhile(new JsDoWhile(), expression, context);
return createWhile(true, expression, context);
}
private JsNode createWhile(@NotNull JsWhile result, @NotNull JetWhileExpressionBase expression, @NotNull TranslationContext context) {
result.setCondition(translateConditionExpression(expression.getCondition(), context));
TranslationContext bodyContext = context.innerBlock();
JsStatement bodyStatement = translateNullableExpressionAsNotNullStatement(expression.getBody(), bodyContext);
private static JsNode createWhile(boolean doWhile, @NotNull JetWhileExpressionBase expression, @NotNull TranslationContext context) {
JetExpression conditionExpression = expression.getCondition();
assert conditionExpression != null : "condition expression should not be null: " + expression.getText();
JsBlock conditionBlock = new JsBlock();
JsExpression jsCondition = Translation.translateAsExpression(conditionExpression, context, conditionBlock);
JsStatement bodyStatement = translateNullableExpressionAsNotNullStatement(expression.getBody(), context);
if (!conditionBlock.isEmpty()) {
JsIf IfStatement = new JsIf(not(jsCondition), new JsBreak());
JsBlock bodyBlock = JsAstUtils.convertToBlock(bodyStatement);
jsCondition = JsLiteral.TRUE;
if (doWhile) {
// translate to: tmpSecondRun = false; do { if(tmpSecondRun) { <expr> if(!tmpExprVar) break; } else tmpSecondRun=true; <body> } while(true)
TemporaryVariable secondRun = context.declareTemporary(JsLiteral.FALSE);
context.addStatementToCurrentBlock(secondRun.assignmentExpression().makeStmt());
conditionBlock.getStatements().add(IfStatement);
bodyBlock.getStatements().add(0,
new JsIf(secondRun.reference(), conditionBlock,
JsAstUtils.assignment(secondRun.reference(), JsLiteral.TRUE).makeStmt())
);
} else {
// translate to: while (true) { <expr> if(!tmpExprVar) break; <body> }
conditionBlock.getStatements().add(IfStatement);
bodyBlock.getStatements().addAll(0, conditionBlock.getStatements());
}
bodyStatement = bodyBlock;
}
JsWhile result = doWhile ? new JsDoWhile() : new JsWhile();
result.setCondition(jsCondition);
result.setBody(bodyStatement);
return result.source(expression);
}
@@ -0,0 +1,32 @@
package foo
var global: String = ""
fun box(): String {
var i:Int = 0
i = 0
global = ""
do i++ while(try { global += "A"; i } finally {} < 3)
assertEquals("AAA", global)
assertEquals(3, i)
i = 0
global = ""
do {
if (i==3) break
i++
} while(try { global += "A"; i } finally {} < 10)
assertEquals("AAA", global)
assertEquals(3, i)
i = 0
global = ""
do
try { global += "B"; i++} finally {}
while( try { global += "A"; i } finally{} < 3)
assertEquals("BABABA", global)
assertEquals(3, i)
return "OK"
}
@@ -0,0 +1,41 @@
package foo
var global: String = ""
fun box(): String {
var i = 0
i = 0
global = ""
do {
if (i<3) {i++; continue}
break
} while(try { global += "A"; i } finally {} < 10)
assertEquals("AAA", global)
assertEquals(3, i)
i = 0
global = ""
@labelA do {
if (i<3) {i++; continue@labelA}
break
} while(try { global += "A"; i } finally {} < 10)
assertEquals("AAA", global)
assertEquals(3, i)
i = 0
var j = 0
global = ""
@outer do {
j = 0
while( try {global += "B"; j++ } finally {} < 2) {
if (j==1) continue@outer
}
} while(try { global += "A"; i++ } finally {} < 3)
assertEquals("BABABABA", global)
assertEquals(4, i)
assertEquals(1, j)
return "OK"
}
@@ -0,0 +1,31 @@
package foo
var global: String = ""
fun box(): String {
var i:Int = 0
i = 0
global = ""
while(try { global += "A"; i } finally {} < 3)
i++
assertEquals("AAAA", global)
assertEquals(3, i)
i = 0
global = ""
while(try { global += "A"; i } finally {} < 10) {
if (i==3) break
i++
}
assertEquals("AAAA", global)
assertEquals(3, i)
i = 0
global = ""
while( try { global += "A"; i } finally{} < 3)
try { global += "B"; i++} finally {}
assertEquals("ABABABA", global)
return "OK"
}
@@ -0,0 +1,41 @@
package foo
var global: String = ""
fun box(): String {
var i = 0
i = 0
global = ""
while(try { global += "A"; i } finally {} < 10) {
if (i<3) {i++; continue}
break
}
assertEquals("AAAA", global)
assertEquals(3, i)
i = 0
global = ""
@labelA while(try { global += "A"; i } finally {} < 10) {
if (i<3) {i++; continue@labelA}
break
}
assertEquals("AAAA", global)
assertEquals(3, i)
i = 0
var j = 0
global = ""
@outer while(try { global += "A"; i++ } finally {} < 3) {
j = 0
while( try {global += "B"; j++ } finally {} < 2) {
if (j==1) continue@outer
}
}
assertEquals("ABABABA", global)
assertEquals(4, i)
assertEquals(1, j)
return "OK"
}