From 8500f5ddb2eeb9754d109ea64f518b9af1bd2270 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Fri, 19 Aug 2016 16:09:00 +0300 Subject: [PATCH] Preliminary work on loops. --- .../psi2ir/generators/DeclarationGenerator.kt | 8 +- .../generators/FunctionBodyGenerator.kt | 40 +++++ .../{Generator.kt => IrGenerator.kt} | 0 .../psi2ir/generators/StatementGenerator.kt | 5 +- .../src/org/jetbrains/kotlin/ir/IrSlots.kt | 4 +- .../kotlin/ir/expressions/IrLoopExpression.kt | 137 ++++++++++++++++++ .../kotlin/ir/visitors/IrElementVisitor.kt | 5 + 7 files changed, 190 insertions(+), 9 deletions(-) create mode 100644 compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/FunctionBodyGenerator.kt rename compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/{Generator.kt => IrGenerator.kt} (100%) create mode 100644 compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrLoopExpression.kt diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DeclarationGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DeclarationGenerator.kt index a4b312d4f5c..8d4ea34b2b6 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DeclarationGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DeclarationGenerator.kt @@ -22,11 +22,7 @@ import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset -import org.jetbrains.kotlin.psi2ir.toExpectedType import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.utils.SmartList -import org.jetbrains.kotlin.utils.addIfNotNull -import org.jetbrains.kotlin.utils.addToStdlib.singletonList class DeclarationGenerator(override val context: GeneratorContext) : IrGenerator { fun generateAnnotationEntries(annotationEntries: List) { @@ -140,9 +136,7 @@ class DeclarationGenerator(override val context: GeneratorContext) : IrGenerator } private fun generateExpressionWithinContext(ktExpression: KtExpression, scopeOwner: DeclarationDescriptor): IrExpression = - StatementGenerator(context, scopeOwner, TemporaryVariableFactory(scopeOwner)) - .generateExpression(ktExpression) - .toExpectedType(getExpectedTypeForLastInferredCall(ktExpression)) + FunctionBodyGenerator(context).generateFunctionBody(scopeOwner, ktExpression) private fun generateFunctionBody(scopeOwner: CallableDescriptor, ktBody: KtExpression): IrBody { val irRhs = generateExpressionWithinContext(ktBody, scopeOwner) diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/FunctionBodyGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/FunctionBodyGenerator.kt new file mode 100644 index 00000000000..1c887ce8bf0 --- /dev/null +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/FunctionBodyGenerator.kt @@ -0,0 +1,40 @@ +/* + * 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.generators + +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.psi2ir.toExpectedType + +class FunctionBodyGenerator(override val context: GeneratorContext): IrGenerator { + fun generateFunctionBody(scopeOwner: DeclarationDescriptor, ktExpression: KtExpression): IrExpression { + resetInternalContext() + val irExpression = StatementGenerator(context, scopeOwner, this) + .generateExpression(ktExpression) + .toExpectedType(getExpectedTypeForLastInferredCall(ktExpression)) + postprocessFunctionBody() + return irExpression + } + + private fun resetInternalContext() { + } + + private fun postprocessFunctionBody() { + } +} + diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/Generator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrGenerator.kt similarity index 100% rename from compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/Generator.kt rename to compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrGenerator.kt diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt index 8103ae7aac4..982a16b3cb2 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt @@ -44,8 +44,9 @@ import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils class StatementGenerator( override val context: GeneratorContext, val scopeOwner: DeclarationDescriptor, - val temporaryVariableFactory: TemporaryVariableFactory + val functionBodyGenerator: FunctionBodyGenerator ) : KtVisitor(), IrGenerator { + val temporaryVariableFactory: TemporaryVariableFactory = TemporaryVariableFactory(scopeOwner) fun generateExpression(ktExpression: KtExpression): IrExpression = ktExpression.genExpr() @@ -292,4 +293,6 @@ class StatementGenerator( override fun visitWhenExpression(expression: KtWhenExpression, data: Nothing?): IrStatement = WhenExpressionGenerator(this).generate(expression) + + } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrSlots.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrSlots.kt index 7314bd833b0..b8a31dbe78a 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrSlots.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrSlots.kt @@ -27,4 +27,6 @@ const val MODULE_SLOT = 0 const val INITIALIZER_SLOT = 0 const val WHEN_SUBJECT_VARIABLE_SLOT = -1 const val WHEN_ELSE_EXPRESSION_SLOT = -2 -const val BRANCH_RESULT_SLOT = -1 \ No newline at end of file +const val BRANCH_RESULT_SLOT = -1 +const val LOOP_BODY_SLOT = -1 +const val LOOP_CONDITION_SLOT = -2 \ No newline at end of file diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrLoopExpression.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrLoopExpression.kt new file mode 100644 index 00000000000..b3c88fff907 --- /dev/null +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrLoopExpression.kt @@ -0,0 +1,137 @@ +/* + * 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.ir.expressions + +import org.jetbrains.kotlin.ir.* +import org.jetbrains.kotlin.ir.visitors.IrElementVisitor + +interface IrLoopExpression : IrExpression { + var body: IrExpression +} + +interface IrConditionalLoopExpression : IrLoopExpression { + var condition: IrExpression +} + +interface IrWhileLoopExpression : IrConditionalLoopExpression + +interface IrDoWhileLoopExpression : IrConditionalLoopExpression + +abstract class IrLoopExpressionBase( + startOffset: Int, + endOffset: Int +) : IrExpressionBase(startOffset, endOffset, null), IrLoopExpression { + + + private var bodyImpl: IrExpression? = null + override var body: IrExpression + get() = bodyImpl!! + set(value) { + value.assertDetached() + bodyImpl?.detach() + bodyImpl = value + value.setTreeLocation(this, LOOP_BODY_SLOT) + } + + override fun getChild(slot: Int): IrElement? = + when (slot) { + LOOP_BODY_SLOT -> body + else -> null + } + + override fun replaceChild(slot: Int, newChild: IrElement) { + when (slot) { + LOOP_BODY_SLOT -> body = newChild.assertCast() + } + } +} + +abstract class IrConditionalLoopExpressionBase( + startOffset: Int, + endOffset: Int +) : IrLoopExpressionBase(startOffset, endOffset), IrConditionalLoopExpression { + private var conditionImpl: IrExpression? = null + override var condition: IrExpression + get() = conditionImpl!! + set(value) { + value.assertDetached() + conditionImpl?.detach() + conditionImpl = value + value.setTreeLocation(this, LOOP_CONDITION_SLOT) + } + + override fun getChild(slot: Int): IrElement? = + when (slot) { + LOOP_CONDITION_SLOT -> condition + else -> super.getChild(slot) + } + + override fun replaceChild(slot: Int, newChild: IrElement) { + when (slot) { + LOOP_CONDITION_SLOT -> condition = newChild.assertCast() + else -> super.replaceChild(slot, newChild) + } + } +} + +class IrWhileLoopExpressionImpl( + startOffset: Int, + endOffset: Int +) : IrConditionalLoopExpressionBase(startOffset, endOffset), IrWhileLoopExpression { + constructor( + startOffset: Int, + endOffset: Int, + condition: IrExpression, + body: IrExpression + ) : this(startOffset, endOffset) { + this.condition = condition + this.body = body + } + + override fun accept(visitor: IrElementVisitor, data: D): R { + return visitor.visitWhileLoop(this, data) + } + + override fun acceptChildren(visitor: IrElementVisitor, data: D) { + condition.accept(visitor, data) + body.accept(visitor, data) + } +} + +class IrDoWhileLoopExpressionImpl( + startOffset: Int, + endOffset: Int +) : IrConditionalLoopExpressionBase(startOffset, endOffset), IrDoWhileLoopExpression { + constructor( + startOffset: Int, + endOffset: Int, + body: IrExpression, + condition: IrExpression + ) : this(startOffset, endOffset) { + this.condition = condition + this.body = body + } + + override fun accept(visitor: IrElementVisitor, data: D): R { + return visitor.visitDoWhileLoop(this, data) + } + + override fun acceptChildren(visitor: IrElementVisitor, data: D) { + body.accept(visitor, data) + condition.accept(visitor, data) + } +} \ No newline at end of file diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/visitors/IrElementVisitor.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/visitors/IrElementVisitor.kt index b3e1d2cb4b6..b085a1472b6 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/visitors/IrElementVisitor.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/visitors/IrElementVisitor.kt @@ -66,7 +66,12 @@ interface IrElementVisitor { fun visitWhenExpression(expression: IrWhenExpression, data: D) = visitExpression(expression, data) fun visitBranch(branch: IrBranch, data: D): R = visitElement(branch, data) + fun visitLoop(loop: IrLoopExpression, data: D) = visitExpression(loop, data) + fun visitWhileLoop(loop: IrWhileLoopExpression, data: D) = visitLoop(loop, data) + fun visitDoWhileLoop(loop: IrDoWhileLoopExpression, data: D) = visitLoop(loop, data) + // NB Use it only for testing purposes; will be removed as soon as all Kotlin expression types are covered fun visitDummyDeclaration(declaration: IrDummyDeclaration, data: D) = visitDeclaration(declaration, data) fun visitDummyExpression(expression: IrDummyExpression, data: D) = visitExpression(expression, data) + }