diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt index fd76d98e18a..d918ff4dbb8 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt @@ -157,14 +157,9 @@ class WhenStatement(val subject: Expression, val caseContainers: List } } -class WhenEntry(val selectors: List, statements: List) : Statement() { - private val block = run { - val filteredStatements = statements.filterNot { it is BreakStatement || it is ContinueStatement } - Block(filteredStatements, LBrace().assignNoPrototype(), RBrace().assignNoPrototype(), true).assignNoPrototype() - } - +class WhenEntry(val selectors: List, val body: Statement) : Statement() { override fun generateCode(builder: CodeBuilder) { - builder.append(selectors, ", ").append(" -> ").append(block) + builder.append(selectors, ", ").append(" -> ").append(body) } } diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt index 889c9693da7..09fd606fa23 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt @@ -210,38 +210,45 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito } private fun switchBodyToWhenEntries(body: PsiCodeBlock?): List { - val cases: List> = splitToCases(body) - val allSwitchStatements = ArrayList() - if (body != null) { - allSwitchStatements.addAll(body.getStatements()) + //TODO: this code is to be changed when continue in when is supported by Kotlin + + val cases = splitToCases(body) + + fun isSwitchBreak(statement: PsiStatement) = statement is PsiBreakStatement && statement.getLabelIdentifier() == null + + fun convertStatements(statements: List): List + = statements.filterNot(::isSwitchBreak).map { converter.convertStatement(it) } + + fun convertCaseStatements(caseIndex: Int): List { + val case = cases[caseIndex] + return if (case.statements.any { it is PsiBreakStatement || it is PsiContinueStatement || it is PsiReturnStatement || it is PsiThrowStatement } || + caseIndex == cases.lastIndex) { + convertStatements(case.statements) + } + else { // otherwise we fall through into the next case + convertStatements(case.statements) + convertCaseStatements(caseIndex + 1) + } } + + fun convertCaseStatementsToBody(caseIndex: Int): Statement { + val statements = convertCaseStatements(caseIndex) + return if (statements.size == 1) + statements.single() + else + Block(statements, LBrace().assignNoPrototype(), RBrace().assignNoPrototype(), true).assignNoPrototype() + } + val result = ArrayList() var pendingSelectors = ArrayList() - var i = 0 - var hasDefaultCase = false - for (ls in cases) { - if (ls.isNotEmpty()) { - val label = ls[0] as PsiSwitchLabelStatement - hasDefaultCase = hasDefaultCase || label.isDefaultCase() - // TODO assert {(label is PsiSwitchLabelStatement?)} - // TODO assert("not a right index") {allSwitchStatements?.get(i) == label} - pendingSelectors.add(converter.convertStatement(label) as WhenEntrySelector) - if (ls.size() > 1) { - val slice = ls.drop(1) - - fun convertStatements(elements: List): List - = elements.map { if (it is PsiStatement) converter.convertStatement(it) else null }.filterNotNull() - - if (!containsBreak(slice)) { - val statements = convertStatements(slice) + convertStatements(getAllToNextBreak(allSwitchStatements, i + ls.size())) - result.add(WhenEntry(pendingSelectors, statements).assignNoPrototype()) - } - else { - result.add(WhenEntry(pendingSelectors, convertStatements(slice)).assignNoPrototype()) - } - pendingSelectors = ArrayList() - } - i += ls.size() + for ((i, case) in cases.withIndices()) { + if (case.label == null) { // invalid switch - no case labels + result.add(WhenEntry(listOf(ValueWhenEntrySelector(Expression.Empty).assignNoPrototype()), convertCaseStatementsToBody(i)).assignNoPrototype()) + continue + } + pendingSelectors.add(converter.convertStatement(case.label) as WhenEntrySelector) + if (case.statements.isNotEmpty()) { + result.add(WhenEntry(pendingSelectors, convertCaseStatementsToBody(i)).assignNoPrototype()) + pendingSelectors = ArrayList() } } return result @@ -359,44 +366,28 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito (this is PsiPrefixExpression && this.getOperationTokenType() == JavaTokenType.PLUSPLUS) } - private fun containsBreak(slice: List) = slice.any { it is PsiBreakStatement } + private data class SwitchCase(val label: PsiSwitchLabelStatement?, val statements: List) - private fun getAllToNextBreak(allStatements: List, start: Int): List { - val result = ArrayList() - for (i in start..allStatements.size() - 1) { - val s = allStatements[i] - if (s is PsiBreakStatement || s is PsiReturnStatement) { - return result - } - - if (s !is PsiSwitchLabelStatement) { - result.add(s) - } - - } - return result - } - - private fun splitToCases(body: PsiCodeBlock?): List> { - val cases = ArrayList>() - var currentCaseStatements = ArrayList() + private fun splitToCases(body: PsiCodeBlock?): List { + val cases = ArrayList() + var currentCaseStatements = ArrayList() if (body != null) { - var isFirst = true - for (s in body.getChildren()) { - if (s !is PsiStatement && s !is PsiComment) continue - if (s is PsiSwitchLabelStatement) { - if (isFirst) { - isFirst = false - } - else { - cases.add(currentCaseStatements) + var label: PsiSwitchLabelStatement? = null + for (statement in body.getStatements()) { + if (statement is PsiSwitchLabelStatement) { + if (label != null) { + cases.add(SwitchCase(label, currentCaseStatements)) currentCaseStatements = ArrayList() } + label = statement + } + else { + currentCaseStatements.add(statement) } - - currentCaseStatements.add(s) } - cases.add(currentCaseStatements) + if (label != null || currentCaseStatements.isNotEmpty()) { + cases.add(SwitchCase(label, currentCaseStatements)) + } } return cases diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java index 2e6473f4a08..26afc5a999e 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java @@ -2601,6 +2601,11 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv doTest("j2k/tests/testData/ast/switch/comlicatedFallDown.java"); } + @TestMetadata("continueAndBreakWithLabel.java") + public void testContinueAndBreakWithLabel() throws Exception { + doTest("j2k/tests/testData/ast/switch/continueAndBreakWithLabel.java"); + } + @TestMetadata("emptySwitch.java") public void testEmptySwitch() throws Exception { doTest("j2k/tests/testData/ast/switch/emptySwitch.java"); @@ -2611,6 +2616,11 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv doTest("j2k/tests/testData/ast/switch/fallDown.java"); } + @TestMetadata("invalidSwitch.java") + public void testInvalidSwitch() throws Exception { + doTest("j2k/tests/testData/ast/switch/invalidSwitch.java"); + } + @TestMetadata("kt-539.java") public void testKt_539() throws Exception { doTest("j2k/tests/testData/ast/switch/kt-539.java"); @@ -2621,6 +2631,11 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv doTest("j2k/tests/testData/ast/switch/nondefault.java"); } + @TestMetadata("returnsAndThrows.java") + public void testReturnsAndThrows() throws Exception { + doTest("j2k/tests/testData/ast/switch/returnsAndThrows.java"); + } + } @TestMetadata("j2k/tests/testData/ast/synchronizedStatement") diff --git a/j2k/tests/testData/ast/issues/kt-879.kt b/j2k/tests/testData/ast/issues/kt-879.kt index 1e1ff71b3ad..35d52670192 100644 --- a/j2k/tests/testData/ast/issues/kt-879.kt +++ b/j2k/tests/testData/ast/issues/kt-879.kt @@ -2,21 +2,11 @@ class Test { class object { public fun getInt(i: Int): Int { when (i) { - 0 -> { - return 0 - } - 1 -> { - return 1 - } - 2 -> { - return 2 - } - 3 -> { - return 3 - } - else -> { - return -1 - } + 0 -> return 0 + 1 -> return 1 + 2 -> return 2 + 3 -> return 3 + else -> return -1 } } } diff --git a/j2k/tests/testData/ast/switch/comlicatedFallDown.kt b/j2k/tests/testData/ast/switch/comlicatedFallDown.kt index 4e6ccabb380..dcd8cd667a1 100644 --- a/j2k/tests/testData/ast/switch/comlicatedFallDown.kt +++ b/j2k/tests/testData/ast/switch/comlicatedFallDown.kt @@ -31,9 +31,7 @@ public class SwitchDemo { print(4) print(5) } - 5 -> { - print(5) - } + 5 -> print(5) 6 -> { print(6) print(7) @@ -73,12 +71,8 @@ public class SwitchDemo { print(11) monthString = "December" } - 12 -> { - monthString = "December" - } - else -> { - monthString = "Invalid month" - } + 12 -> monthString = "December" + else -> monthString = "Invalid month" } System.out.println(monthString) } diff --git a/j2k/tests/testData/ast/switch/continueAndBreakWithLabel.java b/j2k/tests/testData/ast/switch/continueAndBreakWithLabel.java new file mode 100644 index 00000000000..ecb52b6afd5 --- /dev/null +++ b/j2k/tests/testData/ast/switch/continueAndBreakWithLabel.java @@ -0,0 +1,12 @@ +//method +void foo() { +Loop: + while(true) { + switch(take()) { + case 1: continue; + case 2: System.out.println("2"); return; + case 3: break Loop; + } + System.out.println(); + } +} diff --git a/j2k/tests/testData/ast/switch/continueAndBreakWithLabel.kt b/j2k/tests/testData/ast/switch/continueAndBreakWithLabel.kt new file mode 100644 index 00000000000..6eab3c00ac8 --- /dev/null +++ b/j2k/tests/testData/ast/switch/continueAndBreakWithLabel.kt @@ -0,0 +1,13 @@ +fun foo() { + @Loop while (true) { + when (take()) { + 1 -> continue + 2 -> { + System.out.println("2") + return + } + 3 -> break@Loop + } + System.out.println() + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/switch/fallDown.kt b/j2k/tests/testData/ast/switch/fallDown.kt index 1b74f96466b..90e6a0e3f6b 100644 --- a/j2k/tests/testData/ast/switch/fallDown.kt +++ b/j2k/tests/testData/ast/switch/fallDown.kt @@ -6,12 +6,8 @@ public class SwitchDemo { val month = 8 val monthString: String when (month) { - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 -> { - monthString = "December" - } - else -> { - monthString = "Invalid month" - } + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 -> monthString = "December" + else -> monthString = "Invalid month" } System.out.println(monthString) } diff --git a/j2k/tests/testData/ast/switch/invalidSwitch.java b/j2k/tests/testData/ast/switch/invalidSwitch.java new file mode 100644 index 00000000000..ef6d6f259f3 --- /dev/null +++ b/j2k/tests/testData/ast/switch/invalidSwitch.java @@ -0,0 +1,7 @@ +//method +void foo() { + switch(a) { + System.out.println("1") + System.out.println("2") + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/switch/invalidSwitch.kt b/j2k/tests/testData/ast/switch/invalidSwitch.kt new file mode 100644 index 00000000000..19a65b7f6ba --- /dev/null +++ b/j2k/tests/testData/ast/switch/invalidSwitch.kt @@ -0,0 +1,8 @@ +fun foo() { + when (a) { + -> { + System.out.println("1") + System.out.println("2") + } + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/switch/kt-539.kt b/j2k/tests/testData/ast/switch/kt-539.kt index 103176085ec..e67c0f7e5be 100644 --- a/j2k/tests/testData/ast/switch/kt-539.kt +++ b/j2k/tests/testData/ast/switch/kt-539.kt @@ -7,45 +7,19 @@ public class SwitchDemo { val month = 8 val monthString: String when (month) { - 1 -> { - monthString = "January" - } - 2 -> { - monthString = "February" - } - 3 -> { - monthString = "March" - } - 4 -> { - monthString = "April" - } - 5 -> { - monthString = "May" - } - 6 -> { - monthString = "June" - } - 7 -> { - monthString = "July" - } - 8 -> { - monthString = "August" - } - 9 -> { - monthString = "September" - } - 10 -> { - monthString = "October" - } - 11 -> { - monthString = "November" - } - 12 -> { - monthString = "December" - } - else -> { - monthString = "Invalid month" - } + 1 -> monthString = "January" + 2 -> monthString = "February" + 3 -> monthString = "March" + 4 -> monthString = "April" + 5 -> monthString = "May" + 6 -> monthString = "June" + 7 -> monthString = "July" + 8 -> monthString = "August" + 9 -> monthString = "September" + 10 -> monthString = "October" + 11 -> monthString = "November" + 12 -> monthString = "December" + else -> monthString = "Invalid month" } System.out.println(monthString) } diff --git a/j2k/tests/testData/ast/switch/nondefault.kt b/j2k/tests/testData/ast/switch/nondefault.kt index 29c85c4da2b..874defa3f72 100644 --- a/j2k/tests/testData/ast/switch/nondefault.kt +++ b/j2k/tests/testData/ast/switch/nondefault.kt @@ -5,15 +5,9 @@ public class NonDefault { val value = 3 var valueString = "" when (value) { - 1 -> { - valueString = "ONE" - } - 2 -> { - valueString = "TWO" - } - 3 -> { - valueString = "THREE" - } + 1 -> valueString = "ONE" + 2 -> valueString = "TWO" + 3 -> valueString = "THREE" } System.out.println(valueString) } diff --git a/j2k/tests/testData/ast/switch/returnsAndThrows.java b/j2k/tests/testData/ast/switch/returnsAndThrows.java new file mode 100644 index 00000000000..1d5ce775387 --- /dev/null +++ b/j2k/tests/testData/ast/switch/returnsAndThrows.java @@ -0,0 +1,9 @@ +//method +int foo(int a) { + switch(a) { + case 1: System.out.println("1"); return 1; + case 2: System.out.println("2"); return 2; + case 3: System.out.println("3"); throw new RuntimeException(); + default: System.out.println("default"); return 0; + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/switch/returnsAndThrows.kt b/j2k/tests/testData/ast/switch/returnsAndThrows.kt new file mode 100644 index 00000000000..2d06758c936 --- /dev/null +++ b/j2k/tests/testData/ast/switch/returnsAndThrows.kt @@ -0,0 +1,20 @@ +fun foo(a: Int): Int { + when (a) { + 1 -> { + System.out.println("1") + return 1 + } + 2 -> { + System.out.println("2") + return 2 + } + 3 -> { + System.out.println("3") + throw RuntimeException() + } + else -> { + System.out.println("default") + return 0 + } + } +} \ No newline at end of file