From 9374816823bf5f9622ef0f13764f6acf5e0dfd04 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Tue, 13 Nov 2018 17:24:05 +0300 Subject: [PATCH] New J2K: Add conversion of prefix and postfix expressions --- .../jetbrains/kotlin/j2k/ConversionsRunner.kt | 2 +- .../conversions/BinaryExpressionConversion.kt | 30 --------- .../OperatorExpressionConversion.kt | 47 +++++++++++++ .../org/jetbrains/kotlin/j2k/expressions.kt | 66 ++++++++++++++----- .../org/jetbrains/kotlin/j2k/tree/impl/j.kt | 2 + .../org/jetbrains/kotlin/j2k/tree/types.kt | 4 ++ 6 files changed, 104 insertions(+), 47 deletions(-) delete mode 100644 j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/BinaryExpressionConversion.kt create mode 100644 j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/OperatorExpressionConversion.kt diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionsRunner.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionsRunner.kt index 3d72e071967..bdee9dc731f 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionsRunner.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionsRunner.kt @@ -23,7 +23,7 @@ object ConversionsRunner { private fun createRootConversion(context: ConversionContext) = batchPipe { - +BinaryExpressionConversion(context) + +OperatorExpressionConversion(context) +ThrowStatementConversion() +ArrayInitializerConversion(context) +TryStatementConversion(context) diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/BinaryExpressionConversion.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/BinaryExpressionConversion.kt deleted file mode 100644 index 7463b71875d..00000000000 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/BinaryExpressionConversion.kt +++ /dev/null @@ -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) - } - -} \ No newline at end of file diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/OperatorExpressionConversion.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/OperatorExpressionConversion.kt new file mode 100644 index 00000000000..e73701cb4ce --- /dev/null +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/OperatorExpressionConversion.kt @@ -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) + } + } +} \ No newline at end of file diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/expressions.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/expressions.kt index fcff9628761..db4c1b95195 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/expressions.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/expressions.kt @@ -22,28 +22,29 @@ fun kotlinTypeByName(name: String, symbolProvider: JKSymbolProvider): JKClassTyp 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, rightType: JKType, symbolProvider: JKSymbolProvider ): 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 = if (operatorName == "equals") listOf("equals", "compareTo") else listOf(operatorName) - return classSymbol.target.declarations// todo look for extensions + return leftType.classSymbol(symbolProvider).target.declarations// todo look for extensions .asSequence() .filterIsInstance() .filter { it.name in operatorNames } @@ -51,6 +52,17 @@ private fun JKKtOperatorToken.methodSymbol( .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() + .filter { it.name == operatorName } + .mapNotNull { symbolProvider.provideDirectSymbol(it) as? JKMethodSymbol } + .firstOrNull()!! + fun kotlinBinaryExpression( left: JKExpression, @@ -60,10 +72,32 @@ fun kotlinBinaryExpression( ): JKBinaryExpression? { val leftType = left.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)) } +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( from: JKExpression, to: JKExpression, diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/j.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/j.kt index 54b5dd40241..0153803a691 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/j.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/j.kt @@ -130,6 +130,8 @@ fun JKJavaOperatorToken.toKtToken(): JKKtOperatorToken = JavaTokenType.NE -> JKKtSingleValueOperatorToken(KtTokens.EXCLEQ) JavaTokenType.PLUSEQ -> JKKtSingleValueOperatorToken(KtTokens.PLUSEQ) JavaTokenType.MINUSEQ -> JKKtSingleValueOperatorToken(KtTokens.MINUSEQ) + JavaTokenType.PLUSPLUS -> JKKtSingleValueOperatorToken(KtTokens.PLUSPLUS) + JavaTokenType.MINUSMINUS -> JKKtSingleValueOperatorToken(KtTokens.MINUSMINUS) JavaTokenType.AND -> JKKtWordOperatorToken("and") JavaTokenType.OR -> JKKtWordOperatorToken("or") diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/types.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/types.kt index 5c1042f58d7..de39608f80e 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/types.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/types.kt @@ -34,6 +34,10 @@ fun JKExpression.type(context: ConversionContext): JKType = kotlinTypeByName("kotlin.Boolean", context.symbolProvider) } else operatorSymbol.returnType } + is JKPostfixExpressionImpl -> + (operator as JKKtOperatorImpl).methodSymbol.returnType + is JKPrefixExpression -> + (operator as JKKtOperatorImpl).methodSymbol.returnType is JKMethodCallExpression -> identifier.returnType is JKFieldAccessExpressionImpl -> identifier.fieldType is JKQualifiedExpressionImpl -> this.selector.type(context)