Desugar basic binary operators (+, -, *, /, %, ..).

Fold String.plus calls to IrStringConcatenationExpression.
This commit is contained in:
Dmitry Petrov
2016-08-17 14:10:08 +03:00
committed by Dmitry Petrov
parent 287d804131
commit 1b018a6ead
14 changed files with 197 additions and 11 deletions
@@ -22,12 +22,14 @@ import org.jetbrains.kotlin.ir.declarations.IrModule
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi2ir.generators.IrGeneratorContext
import org.jetbrains.kotlin.psi2ir.generators.IrModuleGenerator
import org.jetbrains.kotlin.psi2ir.transformations.collapseDesugaredBlocks
import org.jetbrains.kotlin.psi2ir.transformations.foldStringConcatenation
import org.jetbrains.kotlin.psi2ir.transformations.inlineDesugaredBlocks
import org.jetbrains.kotlin.resolve.BindingContext
class Psi2IrTranslator(val configuration: Configuration = Configuration()) {
class Configuration(
val shouldCollapseDesugaredBlocks: Boolean = true
val shouldInlineDesugaredBlocks: Boolean = true,
val shouldFoldStringConcatenation: Boolean = true
)
fun generateModule(moduleDescriptor: ModuleDescriptor, ktFiles: List<KtFile>, bindingContext: BindingContext): IrModule {
@@ -38,6 +40,7 @@ class Psi2IrTranslator(val configuration: Configuration = Configuration()) {
}
private fun postprocess(irElement: IrElement) {
if (configuration.shouldCollapseDesugaredBlocks) collapseDesugaredBlocks(irElement)
if (configuration.shouldInlineDesugaredBlocks) inlineDesugaredBlocks(irElement)
if (configuration.shouldFoldStringConcatenation) foldStringConcatenation(irElement)
}
}
@@ -40,7 +40,9 @@ val KT_OPERATOR_TO_IR_OPERATOR = hashMapOf(
KtTokens.PLUS to IrOperator.PLUS,
KtTokens.MINUS to IrOperator.MINUS,
KtTokens.MUL to IrOperator.MUL,
KtTokens.DIV to IrOperator.DIV
KtTokens.DIV to IrOperator.DIV,
KtTokens.PERC to IrOperator.PERC,
KtTokens.RANGE to IrOperator.RANGE
)
val AUGMENTED_ASSIGNMENTS = KtTokens.AUGMENTED_ASSIGNMENTS
@@ -55,10 +57,17 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
return when (ktOperator) {
KtTokens.EQ -> generateAssignment(expression)
in AUGMENTED_ASSIGNMENTS -> generateAugmentedAssignment(expression, ktOperator)
in BINARY_OPERATORS_WITH_CALLS -> generateBinaryOperatorWithConventionalCall(expression, ktOperator)
else -> createDummyExpression(expression, ktOperator.toString())
}
}
private fun generateBinaryOperatorWithConventionalCall(expression: KtBinaryExpression, ktOperator: IElementType): IrExpression {
val irOperator = getIrOperator(ktOperator)
val operatorCall = getResolvedCall(expression)!!
return IrCallGenerator(irStatementGenerator).generateCall(expression, operatorCall, irOperator)
}
private fun generateAugmentedAssignment(expression: KtBinaryExpression, ktOperator: IElementType): IrExpression {
val ktLeft = expression.left!!
@@ -0,0 +1,78 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.psi2ir.transformations
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.detach
import org.jetbrains.kotlin.ir.expressions.IrCallExpression
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrStringConcatenationExpression
import org.jetbrains.kotlin.ir.expressions.IrStringConcatenationExpressionImpl
import org.jetbrains.kotlin.ir.replaceWith
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.util.OperatorNameConventions
import java.util.*
fun foldStringConcatenation(element: IrElement) {
element.accept(FoldStringConcatenation(), null)
}
class FoldStringConcatenation : IrElementVisitor<Unit, Nothing?> {
override fun visitElement(element: IrElement, data: Nothing?) {
element.acceptChildren(this, data)
}
override fun visitCallExpression(expression: IrCallExpression, data: Nothing?) {
if (!isStringPlus(expression.descriptor)) {
visitElement(expression, data)
return
}
val arguments = ArrayList<IrExpression>()
collectStringConcatenationArguments(expression, arguments)
val irStringConcatenation = IrStringConcatenationExpressionImpl(expression.startOffset, expression.endOffset, expression.type)
arguments.forEach { irStringConcatenation.addArgument(it) }
expression.replaceWith(irStringConcatenation)
}
private fun collectStringConcatenationArguments(expression: IrExpression, arguments: ArrayList<IrExpression>) {
when {
expression is IrCallExpression && isStringPlus(expression.descriptor)-> {
collectStringConcatenationArguments(expression.dispatchReceiver!!, arguments)
collectStringConcatenationArguments(expression.getArgument(0)!!, arguments)
}
expression is IrStringConcatenationExpression -> {
arguments.addAll(expression.arguments)
expression.arguments.forEach { it.detach() }
}
else -> {
arguments.add(expression)
expression.detach()
}
}
}
private fun isStringPlus(descriptor: CallableDescriptor): Boolean {
if (descriptor.name != OperatorNameConventions.PLUS) return false
val dispatchReceiverType = descriptor.dispatchReceiverParameter?.type ?: return false
if (!KotlinBuiltIns.isString(dispatchReceiverType)) return false
return true
}
}
@@ -23,11 +23,11 @@ import org.jetbrains.kotlin.ir.expressions.IrBlockExpressionImpl
import org.jetbrains.kotlin.ir.replaceWith
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
fun collapseDesugaredBlocks(element: IrElement) {
element.accept(CollapseDesugaredBlocks(), null)
fun inlineDesugaredBlocks(element: IrElement) {
element.accept(InlineDesugaredBlocks(), null)
}
class CollapseDesugaredBlocks : IrElementVisitor<Unit, Nothing?> {
class InlineDesugaredBlocks : IrElementVisitor<Unit, Nothing?> {
override fun visitElement(element: IrElement, data: Nothing?) {
element.acceptChildren(this, data)
}
@@ -48,7 +48,7 @@ sealed class IrOperator(val debugName: String) {
object MINUS : IrOperator("MINUS")
object MUL : IrOperator("MUL")
object DIV : IrOperator("DIV")
object MOD : IrOperator("MOD")
object PERC : IrOperator("PERC")
object EQ : IrOperator("EQ")
object PLUSEQ : IrOperator("PLUSEQ")
@@ -55,7 +55,7 @@ class IrStringConcatenationExpressionImpl(
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitStringTemplate(this, data)
visitor.visitStringConcatenation(this, data)
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
arguments.forEach { it.accept(visitor, data) }
@@ -99,6 +99,9 @@ class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
"SET_PROPERTY ${if (expression.isSafe) "?." else "."}${expression.descriptor.name}" +
"type=${expression.renderType()}"
override fun visitStringConcatenation(expression: IrStringConcatenationExpression, data: Nothing?): String =
"STRING_CONCATENATION type=${expression.renderType()}"
override fun visitTypeOperatorExpression(expression: IrTypeOperatorExpression, data: Nothing?): String {
return "TYPE_OP operator=${expression.operator} typeOperand=${expression.typeOperand.render()}"
}
@@ -43,7 +43,7 @@ interface IrElementVisitor<out R, in D> {
fun <T> visitLiteral(expression: IrLiteralExpression<T>, data: D): R = visitExpression(expression, data)
fun visitReturnExpression(expression: IrReturnExpression, data: D): R = visitExpression(expression, data)
fun visitBlockExpression(expression: IrBlockExpression, data: D): R = visitExpression(expression, data)
fun visitStringTemplate(expression: IrStringConcatenationExpression, data: D) = visitExpression(expression, data)
fun visitStringConcatenation(expression: IrStringConcatenationExpression, data: D) = visitExpression(expression, data)
fun visitThisExpression(expression: IrThisExpression, data: D) = visitExpression(expression, data)
fun visitDeclarationReference(expression: IrDeclarationReference, data: D) = visitExpression(expression, data)