diff --git a/j2k/src/org/jetbrains/kotlin/j2k/ExpressionConverter.kt b/j2k/src/org/jetbrains/kotlin/j2k/ExpressionConverter.kt index 1406755ab14..125e8d84c03 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/ExpressionConverter.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/ExpressionConverter.kt @@ -666,6 +666,26 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter { } } + + private fun polyadicExpressionToBinaryExpressions(operands: List, operators: List): Expression { + if (operators.isEmpty()) + return operands.first() + else { + var op: Operator = operators.first() + var index = 0 + operators.forEachIndexed { i, operator -> + if(operator.precedence >= op.precedence) { + op = operator + index = i + } + } + val left = polyadicExpressionToBinaryExpressions(operands.subList(0, index + 1), operators.subList(0, index)) + val right = polyadicExpressionToBinaryExpressions(operands.subList(index + 1, operands.size), + operators.subList(index + 1, operators.size)) + return BinaryExpression(left, right, op).assignNoPrototype() + } + } + override fun visitPolyadicExpression(expression: PsiPolyadicExpression) { val args = expression.operands.map { codeConverter.convertExpression(it, expression.type).assignPrototype(it, CommentsAndSpacesInheritance.LINE_BREAKS) @@ -677,8 +697,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter { operator.assignPrototype(it, commentsAndSpacesInheritance) } } - - result = PolyadicExpression(args, operators).assignPrototype(expression) + result = polyadicExpressionToBinaryExpressions(args, operators).assignPrototype(expression) } private fun convertArguments(expression: PsiCallExpression, isExtension: Boolean = false): ArgumentList { diff --git a/j2k/src/org/jetbrains/kotlin/j2k/ast/Expressions.kt b/j2k/src/org/jetbrains/kotlin/j2k/ast/Expressions.kt index 9649f63ccd3..f204c72a735 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/ast/Expressions.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/ast/Expressions.kt @@ -145,20 +145,6 @@ class QualifiedExpression(val qualifier: Expression, val identifier: Expression, } } -class PolyadicExpression(val expressions: List, val operators: List) : Expression() { - override fun generateCode(builder: CodeBuilder) { - assert(expressions.size == operators.size + 1) - for ((i, expression) in expressions.withIndex()) { - builder.append(expression) - if (i < operators.size) { - builder.append(" ") - builder.append(operators[i]) - builder.append(" ") - } - } - } -} - open class Operator(val operatorType: IElementType): Expression() { override fun generateCode(builder: CodeBuilder) { builder.append(asString(operatorType)) @@ -176,8 +162,21 @@ open class Operator(val operatorType: IElementType): Expression() { } } + val precedence: Int + get() = when (this.operatorType) { + JavaTokenType.ASTERISK, JavaTokenType.DIV, JavaTokenType.PERC -> 3 + JavaTokenType.PLUS, JavaTokenType.MINUS -> 4 + KtTokens.ELVIS -> 7 + JavaTokenType.GT, JavaTokenType.LT, JavaTokenType.GE, JavaTokenType.LE -> 9 + JavaTokenType.EQEQ, JavaTokenType.NE, KtTokens.EQEQEQ, KtTokens.EXCLEQEQEQ -> 10 + JavaTokenType.ANDAND -> 11 + JavaTokenType.OROR -> 12 + JavaTokenType.GTGTGT, JavaTokenType.GTGT, JavaTokenType.LTLT -> 7 + else -> 6 /* simple name */ + } + private fun asString(tokenType: IElementType): String { - return when(tokenType) { + return when (tokenType) { JavaTokenType.EQ -> "=" JavaTokenType.EQEQ -> "==" JavaTokenType.NE -> "!=" diff --git a/j2k/src/org/jetbrains/kotlin/j2k/ast/Util.kt b/j2k/src/org/jetbrains/kotlin/j2k/ast/Util.kt index a60275e2b5f..935d456bd6a 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/ast/Util.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/ast/Util.kt @@ -33,23 +33,14 @@ fun CodeBuilder.appendOperand(expression: Expression, operand: Expression, paren } private fun Expression.precedence(): Int? { - return when(this) { + return when (this) { is QualifiedExpression, is MethodCallExpression, is ArrayAccessExpression, is PostfixExpression, is BangBangExpression, is StarExpression -> 0 is PrefixExpression -> 1 is TypeCastExpression -> 2 - is BinaryExpression -> when(op.asString()) { - "*", "/", "%" -> 3 - "+", "-" -> 4 - "?:" -> 7 - ">", "<", ">=", "<=" -> 9 - "==", "!=", "===", "!===" -> 10 - "&&" -> 11 - "||" -> 12 - else -> 6 /* simple name */ - } + is BinaryExpression -> op.precedence is RangeExpression, is DownToExpression -> 5 diff --git a/j2k/testData/fileOrElement/assignmentExpression/bitOperationPriority.java b/j2k/testData/fileOrElement/assignmentExpression/bitOperationPriority.java new file mode 100644 index 00000000000..22a42a89a37 --- /dev/null +++ b/j2k/testData/fileOrElement/assignmentExpression/bitOperationPriority.java @@ -0,0 +1,2 @@ +//expression +5 << 16 | 0 >> 8 | 1 \ No newline at end of file diff --git a/j2k/testData/fileOrElement/assignmentExpression/bitOperationPriority.kt b/j2k/testData/fileOrElement/assignmentExpression/bitOperationPriority.kt new file mode 100644 index 00000000000..e1a78268701 --- /dev/null +++ b/j2k/testData/fileOrElement/assignmentExpression/bitOperationPriority.kt @@ -0,0 +1 @@ +5 shl 16 or (0 shr 8) or 1 \ No newline at end of file diff --git a/j2k/testData/fileOrElement/assignmentExpression/bitOperationPriorityComments.java b/j2k/testData/fileOrElement/assignmentExpression/bitOperationPriorityComments.java new file mode 100644 index 00000000000..3dab416a115 --- /dev/null +++ b/j2k/testData/fileOrElement/assignmentExpression/bitOperationPriorityComments.java @@ -0,0 +1,2 @@ +//expression +/*pre*/ 5 /*operand '5'*/ << /*left shift*/ 16 /*operand '16'*/ | /*or*/ 1 /*operand '1'*/ >> /*right shift*/ 8 /*operand '8'*/ | /*or*/ 0 /*operand '0'*/ /*post comment*/ \ No newline at end of file diff --git a/j2k/testData/fileOrElement/assignmentExpression/bitOperationPriorityComments.kt b/j2k/testData/fileOrElement/assignmentExpression/bitOperationPriorityComments.kt new file mode 100644 index 00000000000..71e8eb84def --- /dev/null +++ b/j2k/testData/fileOrElement/assignmentExpression/bitOperationPriorityComments.kt @@ -0,0 +1 @@ +/*pre*/ 5 /*operand '5'*/ shl /*left shift*/ 16 or /*or*/ (1 /*operand '1'*/ shr /*right shift*/ 8 /*operand '8'*/) or /*or*/ 0 /*operand '0'*/ /*post comment*/ \ No newline at end of file diff --git a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java index 5729b975ddf..d34e2398822 100644 --- a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java +++ b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java @@ -418,6 +418,18 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo doTest(fileName); } + @TestMetadata("bitOperationPriority.java") + public void testBitOperationPriority() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/assignmentExpression/bitOperationPriority.java"); + doTest(fileName); + } + + @TestMetadata("bitOperationPriorityComments.java") + public void testBitOperationPriorityComments() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/assignmentExpression/bitOperationPriorityComments.java"); + doTest(fileName); + } + @TestMetadata("divideAssign.java") public void testDivideAssign() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/assignmentExpression/divideAssign.java"); diff --git a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java index a0a9e4b91ee..7a561847cd7 100644 --- a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java +++ b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java @@ -418,6 +418,18 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo doTest(fileName); } + @TestMetadata("bitOperationPriority.java") + public void testBitOperationPriority() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/assignmentExpression/bitOperationPriority.java"); + doTest(fileName); + } + + @TestMetadata("bitOperationPriorityComments.java") + public void testBitOperationPriorityComments() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/assignmentExpression/bitOperationPriorityComments.java"); + doTest(fileName); + } + @TestMetadata("divideAssign.java") public void testDivideAssign() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/assignmentExpression/divideAssign.java");