From 27526cf866c16d2e291fce12216c13e35f585a98 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Wed, 17 Oct 2018 13:11:33 +0300 Subject: [PATCH] New J2K: Add labeled statement --- .../jetbrains/kotlin/j2k/ConversionsRunner.kt | 1 + .../kotlin/j2k/JavaToJKTreeBuilder.kt | 13 +++ .../jetbrains/kotlin/j2k/NewCodeBuilder.kt | 19 +++ .../kotlin/j2k/conversions/ForConversion.kt | 20 ++-- .../conversions/LabeledStatementConversion.kt | 27 +++++ .../org/jetbrains/kotlin/j2k/expressions.kt | 108 ++++++++++++++++++ .../org/jetbrains/kotlin/j2k/tree/impl/jk.kt | 6 + .../org/jetbrains/kotlin/j2k/tree/impl/k.kt | 10 ++ .../org/jetbrains/kotlin/j2k/tree/jk.kt | 5 + j2k/newSrc/org/jetbrains/kotlin/j2k/tree/k.kt | 5 + .../kotlin/j2k/tree/visitors/JKVisitor.kt | 2 + .../kotlin/j2k/tree/visitors/JKVisitorVoid.kt | 4 + 12 files changed, 209 insertions(+), 11 deletions(-) create mode 100644 j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/LabeledStatementConversion.kt create mode 100644 j2k/newSrc/org/jetbrains/kotlin/j2k/expressions.kt diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionsRunner.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionsRunner.kt index c266a0a9593..598a753a00c 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionsRunner.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionsRunner.kt @@ -51,6 +51,7 @@ object ConversionsRunner { +SwitchStatementConversion(context) +InstanceofConversion() +ForConversion(context) + +LabeledStatementConversion() } fun doApply(trees: List, context: ConversionContext) { diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/JavaToJKTreeBuilder.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/JavaToJKTreeBuilder.kt index bcf7e5ea87d..e776e5524f8 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/JavaToJKTreeBuilder.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/JavaToJKTreeBuilder.kt @@ -21,6 +21,7 @@ import com.intellij.psi.* import com.intellij.psi.JavaTokenType.SUPER_KEYWORD import com.intellij.psi.JavaTokenType.THIS_KEYWORD import com.intellij.psi.impl.source.tree.ChildRole +import com.intellij.psi.impl.source.tree.java.PsiLabeledStatementImpl import com.intellij.psi.impl.source.tree.java.PsiLiteralExpressionImpl import com.intellij.psi.impl.source.tree.java.PsiNewExpressionImpl import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl @@ -397,6 +398,10 @@ class JavaToJKTreeBuilder(var symbolProvider: JKSymbolProvider) { } ?: JKLabelEmptyImpl() JKContinueStatementImpl(label) } + is PsiLabeledStatement -> { + val (labels, statement) = collectLabels() + JKLabeledStatementImpl(statement.toJK(), labels.map { JKNameIdentifierImpl(it.text) }) + } else -> TODO("for ${this::class}") }.also { if (this != null) backAnnotation[it] = this @@ -404,6 +409,14 @@ class JavaToJKTreeBuilder(var symbolProvider: JKSymbolProvider) { } } + //TODO better way than generateSequence.last?? + fun PsiLabeledStatement.collectLabels(): Pair, PsiStatement> = + generateSequence(emptyList() to this as PsiStatement) { (labels, statement) -> + if (statement !is PsiLabeledStatementImpl) return@generateSequence null + (labels + statement.labelIdentifier) to statement.statement!! + }.last() + + private inner class ModifierMapper { fun PsiModifierList?.toJK(finalAsMutability: Boolean = false): JKModifierList { diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/NewCodeBuilder.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/NewCodeBuilder.kt index bc1bd1636d8..3fe5575ae48 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/NewCodeBuilder.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/NewCodeBuilder.kt @@ -315,6 +315,18 @@ class NewCodeBuilder { printer.printWithNoIndent(" ") } + override fun visitLabeledStatement(labeledStatement: JKLabeledStatement) { + for (label in labeledStatement.labels) { + label.accept(this) + printer.printWithNoIndent("@") + } + labeledStatement.statement.accept(this) + } + + override fun visitNameIdentifier(nameIdentifier: JKNameIdentifier) { + printer.printWithNoIndent(nameIdentifier.value) + } + override fun visitPostfixExpression(postfixExpression: JKPostfixExpression) { postfixExpression.expression.accept(this) printer.printWithNoIndent(postfixExpression.operator.operatorText) @@ -392,6 +404,13 @@ class NewCodeBuilder { printer.printlnWithNoIndent() } + override fun visitKtConvertedFromForLoopSyntheticWhileStatement( + ktConvertedFromForLoopSyntheticWhileStatement: JKKtConvertedFromForLoopSyntheticWhileStatement + ) { + ktConvertedFromForLoopSyntheticWhileStatement.variableDeclaration.accept(this) + printer.printlnWithNoIndent() + ktConvertedFromForLoopSyntheticWhileStatement.whileStatement.accept(this) + } private fun renderType(type: JKType) { when (type) { diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/ForConversion.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/ForConversion.kt index 61d0ec89d77..a2bda5c5e94 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/ForConversion.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/ForConversion.kt @@ -6,9 +6,7 @@ package org.jetbrains.kotlin.j2k.conversions import com.intellij.psi.* -import org.jetbrains.kotlin.j2k.ConversionContext -import org.jetbrains.kotlin.j2k.ReferenceSearcher -import org.jetbrains.kotlin.j2k.hasWriteAccesses +import org.jetbrains.kotlin.j2k.* import org.jetbrains.kotlin.j2k.tree.* import org.jetbrains.kotlin.j2k.tree.impl.* import org.jetbrains.kotlin.lexer.KtTokens @@ -30,18 +28,18 @@ class ForConversion(private val context: ConversionContext) : RecursiveApplicabl private fun convertToWhile(loopStatement: JKJavaForLoopStatement): JKStatement? { val whileBody = createWhileBody(loopStatement) - - val whileStatement = - JKWhileStatementImpl( - if (loopStatement.condition !is JKStubExpression) loopStatement.condition.detached() - else JKKtLiteralExpressionImpl("true", JKLiteralExpression.LiteralType.BOOLEAN), - whileBody - ) + val condition = + if (loopStatement.condition !is JKStubExpression) loopStatement.condition.detached() + else JKKtLiteralExpressionImpl("true", JKLiteralExpression.LiteralType.BOOLEAN) val whileStatement = JKWhileStatementImpl(condition, whileBody) if (loopStatement.initializer is JKEmptyStatement) return whileStatement //TODO check for error conflict - return JKBlockStatementImpl(JKBlockImpl(listOf(loopStatement.initializer.detached(), whileStatement))) + + return JKKtConvertedFromForLoopSyntheticWhileStatementImpl( + loopStatement.initializer.detached(), + JKWhileStatementImpl(condition, whileBody) + ) } private fun createWhileBody(loopStatement: JKJavaForLoopStatement): JKStatement { diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/LabeledStatementConversion.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/LabeledStatementConversion.kt new file mode 100644 index 00000000000..4584326e149 --- /dev/null +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/LabeledStatementConversion.kt @@ -0,0 +1,27 @@ +/* + * 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.blockStatement +import org.jetbrains.kotlin.j2k.tree.* +import org.jetbrains.kotlin.j2k.tree.impl.* + + +class LabeledStatementConversion : RecursiveApplicableConversionBase() { + override fun applyToElement(element: JKTreeElement): JKTreeElement { + if (element !is JKLabeledStatement) return recurse(element) + val statement = element.statement as? JKKtConvertedFromForLoopSyntheticWhileStatementImpl ?: return recurse(element) + + return recurse( + JKBlockStatementWithoutBracketsImpl( + JKBlockImpl( + statement::variableDeclaration.detached(), + JKLabeledStatementImpl(statement::whileStatement.detached(), element::labels.detached()) + ) + ) + ) + } +} \ 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 new file mode 100644 index 00000000000..481954b131f --- /dev/null +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/expressions.kt @@ -0,0 +1,108 @@ +/* + * 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 + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.j2k.conversions.multiResolveFqName +import org.jetbrains.kotlin.j2k.conversions.resolveFqName +import org.jetbrains.kotlin.j2k.tree.* +import org.jetbrains.kotlin.j2k.tree.impl.* +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.psi.KtNamedFunction + +fun kotlinTypeByName(name: String, symbolProvider: JKSymbolProvider): JKClassType { + val symbol = + symbolProvider.provideDirectSymbol( + resolveFqName(ClassId.fromString(name), symbolProvider.symbolsByPsi.keys.first())!! + ) as JKClassSymbol + return JKClassTypeImpl(symbol, emptyList()) +} + +private fun JKKtOperatorToken.methodSymbol( + 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 + .asSequence() + .filterIsInstance() + .filter { it.name in operatorNames } + .mapNotNull { symbolProvider.provideDirectSymbol(it) as? JKMethodSymbol } + .firstOrNull { it.parameterTypes.singleOrNull()?.takeIf { it.isSubtypeOf(rightType, symbolProvider) } != null }!! +} + + +fun kotlinBinaryExpression( + left: JKExpression, + right: JKExpression, + token: JKKtOperatorToken, + context: ConversionContext +): JKBinaryExpression? { + val leftType = left.type(context) + val rightType = right.type(context) + val methodSymbol = token.methodSymbol(leftType, rightType, context.symbolProvider) + return JKBinaryExpressionImpl(left, right, JKKtOperatorImpl(token, methodSymbol)) +} + +fun untilToExpression( + from: JKExpression, + to: JKExpression, + conversionContext: ConversionContext, + psiContext: PsiElement +): JKKtOperatorExpression = + rangeExpression( + from, + to, + "until", + conversionContext, + psiContext + ) + +fun downToExpression( + from: JKExpression, + to: JKExpression, + conversionContext: ConversionContext, + psiContext: PsiElement +): JKKtOperatorExpression = + rangeExpression( + from, + to, + "downTo", + conversionContext, + psiContext + ) + +fun rangeExpression( + from: JKExpression, + to: JKExpression, + operatorName: String, + conversionContext: ConversionContext, + psiContext: PsiElement +): JKKtOperatorExpressionImpl { + val symbol = conversionContext.symbolProvider.provideDirectSymbol( + multiResolveFqName(ClassId.fromString("kotlin/ranges/$operatorName"), psiContext).first() + ) as JKMethodSymbol + return JKKtOperatorExpressionImpl(from, symbol, to) +} + +fun blockStatement(vararg statements: JKStatement) = + JKBlockStatementImpl(JKBlockImpl(statements.toList())) diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/jk.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/jk.kt index 0868d0c1ddd..fa958e2223b 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/jk.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/jk.kt @@ -394,4 +394,10 @@ class JKLabelTextImpl(label: JKNameIdentifier) : JKLabelText, JKBranchElementBas class JKContinueStatementImpl(label: JKLabel) : JKContinueStatement, JKBranchElementBase() { override var label: JKLabel by child(label) override fun accept(visitor: JKVisitor, data: D): R = visitor.visitContinueStatement(this, data) +} + +class JKLabeledStatementImpl(statement: JKStatement, labels: List) : JKLabeledStatement, JKBranchElementBase() { + override var statement: JKStatement by child(statement) + override val labels: List by children(labels) + override fun accept(visitor: JKVisitor, data: D): R = visitor.visitLabeledStatement(this, data) } \ No newline at end of file diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/k.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/k.kt index 14ec27c683c..c6fd2ee1c46 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/k.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/k.kt @@ -286,3 +286,13 @@ class JKKtOperatorExpressionImpl( override var argument: JKExpression by child(argument) override fun accept(visitor: JKVisitor, data: D): R = visitor.visitKtOperatorExpression(this, data) } + +class JKKtConvertedFromForLoopSyntheticWhileStatementImpl( + variableDeclaration: JKStatement, + whileStatement: JKWhileStatement +) : JKKtConvertedFromForLoopSyntheticWhileStatement, JKBranchElementBase(), PsiOwner by PsiOwnerImpl() { + override var variableDeclaration: JKStatement by child(variableDeclaration) + override var whileStatement: JKWhileStatement by child(whileStatement) + override fun accept(visitor: JKVisitor, data: D): R = + visitor.visitKtConvertedFromForLoopSyntheticWhileStatement(this, data) +} diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/jk.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/jk.kt index 7f86a326841..35c8af52c4d 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/jk.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/jk.kt @@ -261,4 +261,9 @@ interface JKLabelText : JKLabel { interface JKContinueStatement : JKStatement { var label: JKLabel +} + +interface JKLabeledStatement : JKStatement { + var statement: JKStatement + val labels: List } \ No newline at end of file diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/k.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/k.kt index 206cf3d0fa2..b440ecd2b49 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/k.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/k.kt @@ -97,4 +97,9 @@ interface JKKtOperatorExpression : JKExpression { var receiver: JKExpression var identifier: JKMethodSymbol var argument: JKExpression +} + +interface JKKtConvertedFromForLoopSyntheticWhileStatement : JKStatement { + var variableDeclaration: JKStatement + var whileStatement: JKWhileStatement } \ No newline at end of file diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/visitors/JKVisitor.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/visitors/JKVisitor.kt index 6e5009f5ebf..7500753403f 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/visitors/JKVisitor.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/visitors/JKVisitor.kt @@ -58,6 +58,7 @@ interface JKVisitor { fun visitLabelEmpty(labelEmpty: JKLabelEmpty, data: D): R = visitLabel(labelEmpty, data) fun visitLabelText(labelText: JKLabelText, data: D): R = visitLabel(labelText, data) fun visitContinueStatement(continueStatement: JKContinueStatement, data: D): R = visitStatement(continueStatement, data) + fun visitLabeledStatement(labeledStatement: JKLabeledStatement, data: D): R = visitStatement(labeledStatement, data) fun visitJavaField(javaField: JKJavaField, data: D): R = visitField(javaField, data) fun visitJavaMethod(javaMethod: JKJavaMethod, data: D): R = visitMethod(javaMethod, data) fun visitJavaMethodCallExpression(javaMethodCallExpression: JKJavaMethodCallExpression, data: D): R = visitMethodCallExpression(javaMethodCallExpression, data) @@ -97,4 +98,5 @@ interface JKVisitor { fun visitKtInitDeclaration(ktInitDeclaration: JKKtInitDeclaration, data: D): R = visitDeclaration(ktInitDeclaration, data) fun visitKtForInStatement(ktForInStatement: JKKtForInStatement, data: D): R = visitStatement(ktForInStatement, data) fun visitKtOperatorExpression(ktOperatorExpression: JKKtOperatorExpression, data: D): R = visitExpression(ktOperatorExpression, data) + fun visitKtConvertedFromForLoopSyntheticWhileStatement(ktConvertedFromForLoopSyntheticWhileStatement: JKKtConvertedFromForLoopSyntheticWhileStatement, data: D): R = visitStatement(ktConvertedFromForLoopSyntheticWhileStatement, data) } diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/visitors/JKVisitorVoid.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/visitors/JKVisitorVoid.kt index 269368f09b4..891a1daf6f7 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/visitors/JKVisitorVoid.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/visitors/JKVisitorVoid.kt @@ -113,6 +113,8 @@ interface JKVisitorVoid : JKVisitor { override fun visitLabelText(labelText: JKLabelText, data: Nothing?) = visitLabelText(labelText) fun visitContinueStatement(continueStatement: JKContinueStatement) = visitStatement(continueStatement, null) override fun visitContinueStatement(continueStatement: JKContinueStatement, data: Nothing?) = visitContinueStatement(continueStatement) + fun visitLabeledStatement(labeledStatement: JKLabeledStatement) = visitStatement(labeledStatement, null) + override fun visitLabeledStatement(labeledStatement: JKLabeledStatement, data: Nothing?) = visitLabeledStatement(labeledStatement) fun visitJavaField(javaField: JKJavaField) = visitField(javaField, null) override fun visitJavaField(javaField: JKJavaField, data: Nothing?) = visitJavaField(javaField) fun visitJavaMethod(javaMethod: JKJavaMethod) = visitMethod(javaMethod, null) @@ -191,4 +193,6 @@ interface JKVisitorVoid : JKVisitor { override fun visitKtForInStatement(ktForInStatement: JKKtForInStatement, data: Nothing?) = visitKtForInStatement(ktForInStatement) fun visitKtOperatorExpression(ktOperatorExpression: JKKtOperatorExpression) = visitExpression(ktOperatorExpression, null) override fun visitKtOperatorExpression(ktOperatorExpression: JKKtOperatorExpression, data: Nothing?) = visitKtOperatorExpression(ktOperatorExpression) + fun visitKtConvertedFromForLoopSyntheticWhileStatement(ktConvertedFromForLoopSyntheticWhileStatement: JKKtConvertedFromForLoopSyntheticWhileStatement) = visitStatement(ktConvertedFromForLoopSyntheticWhileStatement, null) + override fun visitKtConvertedFromForLoopSyntheticWhileStatement(ktConvertedFromForLoopSyntheticWhileStatement: JKKtConvertedFromForLoopSyntheticWhileStatement, data: Nothing?) = visitKtConvertedFromForLoopSyntheticWhileStatement(ktConvertedFromForLoopSyntheticWhileStatement) }