New J2K: Add conversion of prefix and postfix expressions

This commit is contained in:
Ilya Kirillov
2018-11-13 17:24:05 +03:00
committed by Ilya Kirillov
parent 3d418d8904
commit 9374816823
6 changed files with 104 additions and 47 deletions
@@ -23,7 +23,7 @@ object ConversionsRunner {
private fun createRootConversion(context: ConversionContext) = private fun createRootConversion(context: ConversionContext) =
batchPipe { batchPipe {
+BinaryExpressionConversion(context) +OperatorExpressionConversion(context)
+ThrowStatementConversion() +ThrowStatementConversion()
+ArrayInitializerConversion(context) +ArrayInitializerConversion(context)
+TryStatementConversion(context) +TryStatementConversion(context)
@@ -1,30 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.j2k.conversions
import org.jetbrains.kotlin.j2k.ConversionContext
import org.jetbrains.kotlin.j2k.tree.JKBinaryExpression
import org.jetbrains.kotlin.j2k.tree.JKBranchElement
import org.jetbrains.kotlin.j2k.tree.JKTreeElement
import org.jetbrains.kotlin.j2k.tree.impl.JKBinaryExpressionImpl
import org.jetbrains.kotlin.j2k.tree.impl.JKJavaOperatorImpl
import org.jetbrains.kotlin.j2k.tree.impl.toKtToken
import org.jetbrains.kotlin.j2k.kotlinBinaryExpression
class BinaryExpressionConversion(private val context: ConversionContext) : RecursiveApplicableConversionBase() {
override fun applyToElement(element: JKTreeElement): JKTreeElement {
if (element !is JKBinaryExpression) return recurse(element)
val ktOperatorToken = (element.operator as? JKJavaOperatorImpl)?.token?.toKtToken() ?: return recurse(element)
val left = recurse(element.left)
val right = recurse(element.right)
(element as? JKBranchElement)?.invalidate()
val ktBinaryExpression = kotlinBinaryExpression(left, right, ktOperatorToken, context)
?: return JKBinaryExpressionImpl(left, right, element.operator)
return recurse(ktBinaryExpression)
}
}
@@ -0,0 +1,47 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.j2k.conversions
import org.jetbrains.kotlin.j2k.ConversionContext
import org.jetbrains.kotlin.j2k.kotlinBinaryExpression
import org.jetbrains.kotlin.j2k.kotlinPostfixExpression
import org.jetbrains.kotlin.j2k.kotlinPrefixExpression
import org.jetbrains.kotlin.j2k.tree.*
import org.jetbrains.kotlin.j2k.tree.impl.JKJavaOperatorImpl
import org.jetbrains.kotlin.j2k.tree.impl.toKtToken
class OperatorExpressionConversion(private val context: ConversionContext) : RecursiveApplicableConversionBase() {
override fun applyToElement(element: JKTreeElement): JKTreeElement {
val operatorToken =
((when (element) {
is JKBinaryExpression ->
element.operator
is JKPrefixExpression ->
element.operator
is JKPostfixExpression ->
element.operator
else -> null
} as? JKJavaOperatorImpl)?.token)?.toKtToken() ?: return recurse(element)
return when (element) {
is JKBinaryExpression -> {
val left = applyToElement(element::left.detached()) as JKExpression
val right = applyToElement(element::right.detached()) as JKExpression
recurse(kotlinBinaryExpression(left, right, operatorToken, context)!!)
}
is JKPrefixExpression -> {
val operand = applyToElement(element::expression.detached()) as JKExpression
recurse(kotlinPrefixExpression(operand, operatorToken, context))
}
is JKPostfixExpression -> {
val operand = applyToElement(element::expression.detached()) as JKExpression
recurse(kotlinPostfixExpression(operand, operatorToken, context))
}
else -> recurse(element)
}
}
}
@@ -22,28 +22,29 @@ fun kotlinTypeByName(name: String, symbolProvider: JKSymbolProvider): JKClassTyp
return JKClassTypeImpl(symbol, emptyList()) return JKClassTypeImpl(symbol, emptyList())
} }
private fun JKKtOperatorToken.methodSymbol( private fun JKType.classSymbol(symbolProvider: JKSymbolProvider) =
when (this) {
is JKClassType -> classReference as JKMultiverseKtClassSymbol
is JKJavaPrimitiveType -> {
val psiClass = resolveFqName(
ClassId.fromString(jvmPrimitiveType.primitiveType.typeFqName.asString()),
symbolProvider.symbolsByPsi.keys.first()
)!!
symbolProvider.provideDirectSymbol(psiClass) as JKMultiverseKtClassSymbol
}
else ->
TODO(this::class.java.toString())
}
private fun JKKtOperatorToken.binaryExpressionMethodSymbol(
leftType: JKType, leftType: JKType,
rightType: JKType, rightType: JKType,
symbolProvider: JKSymbolProvider symbolProvider: JKSymbolProvider
): JKMethodSymbol { ): JKMethodSymbol {
val classSymbol =
when (leftType) {
is JKClassType -> leftType.classReference as JKMultiverseKtClassSymbol
is JKJavaPrimitiveType -> {
val psiClass = resolveFqName(
ClassId.fromString(leftType.jvmPrimitiveType.primitiveType.typeFqName.asString()),
symbolProvider.symbolsByPsi.keys.first()
)!!
symbolProvider.provideDirectSymbol(psiClass) as JKMultiverseKtClassSymbol
}
else ->
TODO(leftType::class.java.toString())
}
val operatorNames = val operatorNames =
if (operatorName == "equals") listOf("equals", "compareTo") if (operatorName == "equals") listOf("equals", "compareTo")
else listOf(operatorName) else listOf(operatorName)
return classSymbol.target.declarations// todo look for extensions return leftType.classSymbol(symbolProvider).target.declarations// todo look for extensions
.asSequence() .asSequence()
.filterIsInstance<KtNamedFunction>() .filterIsInstance<KtNamedFunction>()
.filter { it.name in operatorNames } .filter { it.name in operatorNames }
@@ -51,6 +52,17 @@ private fun JKKtOperatorToken.methodSymbol(
.firstOrNull { it.parameterTypes.singleOrNull()?.takeIf { it.isSubtypeOf(rightType, symbolProvider) } != null }!! .firstOrNull { it.parameterTypes.singleOrNull()?.takeIf { it.isSubtypeOf(rightType, symbolProvider) } != null }!!
} }
private fun JKKtOperatorToken.unaryExpressionMethodSymbol(
operandType: JKType,
symbolProvider: JKSymbolProvider
): JKMethodSymbol =
operandType.classSymbol(symbolProvider).target.declarations// todo look for extensions
.asSequence()
.filterIsInstance<KtNamedFunction>()
.filter { it.name == operatorName }
.mapNotNull { symbolProvider.provideDirectSymbol(it) as? JKMethodSymbol }
.firstOrNull()!!
fun kotlinBinaryExpression( fun kotlinBinaryExpression(
left: JKExpression, left: JKExpression,
@@ -60,10 +72,32 @@ fun kotlinBinaryExpression(
): JKBinaryExpression? { ): JKBinaryExpression? {
val leftType = left.type(context) val leftType = left.type(context)
val rightType = right.type(context) val rightType = right.type(context)
val methodSymbol = token.methodSymbol(leftType, rightType, context.symbolProvider) val methodSymbol = token.binaryExpressionMethodSymbol(leftType, rightType, context.symbolProvider)
return JKBinaryExpressionImpl(left, right, JKKtOperatorImpl(token, methodSymbol)) return JKBinaryExpressionImpl(left, right, JKKtOperatorImpl(token, methodSymbol))
} }
fun kotlinPrefixExpression(
operand: JKExpression,
token: JKKtOperatorToken,
context: ConversionContext
): JKPrefixExpression {
val operandType = operand.type(context)
val methodSymbol = token.unaryExpressionMethodSymbol(operandType, context.symbolProvider)
return JKPrefixExpressionImpl(operand, JKKtOperatorImpl(token, methodSymbol))
}
fun kotlinPostfixExpression(
operand: JKExpression,
token: JKKtOperatorToken,
context: ConversionContext
): JKPostfixExpression {
val operandType = operand.type(context)
val methodSymbol = token.unaryExpressionMethodSymbol(operandType, context.symbolProvider)
return JKPostfixExpressionImpl(operand, JKKtOperatorImpl(token, methodSymbol))
}
fun untilToExpression( fun untilToExpression(
from: JKExpression, from: JKExpression,
to: JKExpression, to: JKExpression,
@@ -130,6 +130,8 @@ fun JKJavaOperatorToken.toKtToken(): JKKtOperatorToken =
JavaTokenType.NE -> JKKtSingleValueOperatorToken(KtTokens.EXCLEQ) JavaTokenType.NE -> JKKtSingleValueOperatorToken(KtTokens.EXCLEQ)
JavaTokenType.PLUSEQ -> JKKtSingleValueOperatorToken(KtTokens.PLUSEQ) JavaTokenType.PLUSEQ -> JKKtSingleValueOperatorToken(KtTokens.PLUSEQ)
JavaTokenType.MINUSEQ -> JKKtSingleValueOperatorToken(KtTokens.MINUSEQ) JavaTokenType.MINUSEQ -> JKKtSingleValueOperatorToken(KtTokens.MINUSEQ)
JavaTokenType.PLUSPLUS -> JKKtSingleValueOperatorToken(KtTokens.PLUSPLUS)
JavaTokenType.MINUSMINUS -> JKKtSingleValueOperatorToken(KtTokens.MINUSMINUS)
JavaTokenType.AND -> JKKtWordOperatorToken("and") JavaTokenType.AND -> JKKtWordOperatorToken("and")
JavaTokenType.OR -> JKKtWordOperatorToken("or") JavaTokenType.OR -> JKKtWordOperatorToken("or")
@@ -34,6 +34,10 @@ fun JKExpression.type(context: ConversionContext): JKType =
kotlinTypeByName("kotlin.Boolean", context.symbolProvider) kotlinTypeByName("kotlin.Boolean", context.symbolProvider)
} else operatorSymbol.returnType } else operatorSymbol.returnType
} }
is JKPostfixExpressionImpl ->
(operator as JKKtOperatorImpl).methodSymbol.returnType
is JKPrefixExpression ->
(operator as JKKtOperatorImpl).methodSymbol.returnType
is JKMethodCallExpression -> identifier.returnType is JKMethodCallExpression -> identifier.returnType
is JKFieldAccessExpressionImpl -> identifier.fieldType is JKFieldAccessExpressionImpl -> identifier.fieldType
is JKQualifiedExpressionImpl -> this.selector.type(context) is JKQualifiedExpressionImpl -> this.selector.type(context)