From d969e58b880ef19e93e1bfa8b298cea2f8ea4209 Mon Sep 17 00:00:00 2001 From: Michael Nedzelsky Date: Wed, 20 Aug 2014 14:46:55 +0400 Subject: [PATCH] JS backend: support for while/do while with complex conditions --- .../k2js/test/semantics/WhileTest.java | 16 ++++++++ .../expression/ExpressionVisitor.java | 38 ++++++++++++++--- .../cases/doWhileWithComplexCondition.kt | 32 +++++++++++++++ .../doWhileWithComplexConditionAndContinue.kt | 41 +++++++++++++++++++ .../while/cases/whileWithComplexCondition.kt | 31 ++++++++++++++ .../whileWithComplexConditionAndContinue.kt | 41 +++++++++++++++++++ 6 files changed, 193 insertions(+), 6 deletions(-) create mode 100644 js/js.translator/testData/expression/while/cases/doWhileWithComplexCondition.kt create mode 100644 js/js.translator/testData/expression/while/cases/doWhileWithComplexConditionAndContinue.kt create mode 100644 js/js.translator/testData/expression/while/cases/whileWithComplexCondition.kt create mode 100644 js/js.translator/testData/expression/while/cases/whileWithComplexConditionAndContinue.kt diff --git a/js/js.tests/test/org/jetbrains/k2js/test/semantics/WhileTest.java b/js/js.tests/test/org/jetbrains/k2js/test/semantics/WhileTest.java index bf05522ec9e..2814fb0f74d 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/semantics/WhileTest.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/semantics/WhileTest.java @@ -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(); + } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java b/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java index f1b40795ab3..d757402d892 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java @@ -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 { @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) { if(!tmpExprVar) break; } else tmpSecondRun=true; } 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) { if(!tmpExprVar) break; } + 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); } diff --git a/js/js.translator/testData/expression/while/cases/doWhileWithComplexCondition.kt b/js/js.translator/testData/expression/while/cases/doWhileWithComplexCondition.kt new file mode 100644 index 00000000000..5fe7e9c90f2 --- /dev/null +++ b/js/js.translator/testData/expression/while/cases/doWhileWithComplexCondition.kt @@ -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" +} \ No newline at end of file diff --git a/js/js.translator/testData/expression/while/cases/doWhileWithComplexConditionAndContinue.kt b/js/js.translator/testData/expression/while/cases/doWhileWithComplexConditionAndContinue.kt new file mode 100644 index 00000000000..04374791c7d --- /dev/null +++ b/js/js.translator/testData/expression/while/cases/doWhileWithComplexConditionAndContinue.kt @@ -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" +} \ No newline at end of file diff --git a/js/js.translator/testData/expression/while/cases/whileWithComplexCondition.kt b/js/js.translator/testData/expression/while/cases/whileWithComplexCondition.kt new file mode 100644 index 00000000000..92d313c12da --- /dev/null +++ b/js/js.translator/testData/expression/while/cases/whileWithComplexCondition.kt @@ -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" +} \ No newline at end of file diff --git a/js/js.translator/testData/expression/while/cases/whileWithComplexConditionAndContinue.kt b/js/js.translator/testData/expression/while/cases/whileWithComplexConditionAndContinue.kt new file mode 100644 index 00000000000..8c7adb1d13e --- /dev/null +++ b/js/js.translator/testData/expression/while/cases/whileWithComplexConditionAndContinue.kt @@ -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" +} \ No newline at end of file