Fix for KT-5312 J2K: Correct bit operations priority after conversion

Now `PolyadicExpression` breaks down to BinaryExpression`s
This commit is contained in:
Simon Ogorodnik
2016-10-14 19:49:10 +03:00
parent 1069257e95
commit f1c371143c
9 changed files with 67 additions and 28 deletions
@@ -666,6 +666,26 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
}
}
private fun polyadicExpressionToBinaryExpressions(operands: List<Expression>, operators: List<Operator>): 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 {
@@ -145,20 +145,6 @@ class QualifiedExpression(val qualifier: Expression, val identifier: Expression,
}
}
class PolyadicExpression(val expressions: List<Expression>, val operators: List<Operator>) : 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 -> "!="
+2 -11
View File
@@ -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
@@ -0,0 +1,2 @@
//expression
5 << 16 | 0 >> 8 | 1
@@ -0,0 +1 @@
5 shl 16 or (0 shr 8) or 1
@@ -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*/
@@ -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*/
@@ -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");
@@ -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");