From df89bcc4905e7f8caf59e1fae4c89bbdd938beec Mon Sep 17 00:00:00 2001 From: Alexey Stepanov Date: Thu, 21 Jul 2016 13:12:58 +0300 Subject: [PATCH] translator: add when block expression --- translator/src/main/kotlin/main.kt | 4 +- .../kotlinnative/translator/BlockCodegen.kt | 73 +++++++++++++++++-- .../translator/llvm/LLVMBuilder.kt | 12 ++- .../kotlin/tests/input/when_expression_1.txt | 4 + .../kotlin/tests/kotlin/when_expression_1.kt | 8 ++ 5 files changed, 89 insertions(+), 12 deletions(-) create mode 100644 translator/src/test/kotlin/tests/input/when_expression_1.txt create mode 100644 translator/src/test/kotlin/tests/kotlin/when_expression_1.kt diff --git a/translator/src/main/kotlin/main.kt b/translator/src/main/kotlin/main.kt index fe8006bf071..2a3bc8babb9 100644 --- a/translator/src/main/kotlin/main.kt +++ b/translator/src/main/kotlin/main.kt @@ -15,8 +15,8 @@ fun main(args: Array) { val analyzedFiles = ArrayList() val kotlib = ClassLoader.getSystemClassLoader().getResources("kotlib/kotlin") - for (resourse in kotlib) { - for (app in File(resourse.toURI()).listFiles()) { + for (resource in kotlib) { + for (app in File(resource.toURI()).listFiles()) { analyzedFiles.add(app.absoluteFile.toString()) } } diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt index e363ea451dd..49e09948129 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt @@ -3,6 +3,7 @@ package org.kotlinnative.translator import com.intellij.psi.PsiElement import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.impl.source.tree.LeafPsiElement +import com.intellij.psi.tree.IElementType import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* @@ -60,6 +61,7 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM is KtBinaryExpression -> evaluateBinaryExpression(expr, scopeDepth) is KtConstantExpression -> evaluateConstantExpression(expr) is KtCallExpression -> evaluateCallExpression(expr, scopeDepth) + is KtWhenExpression -> evaluateWhenExpression(expr, scopeDepth) is KtCallableReferenceExpression -> evaluateCallableReferenceExpression(expr) is KtDotQualifiedExpression -> evaluateDotExpression(expr, scopeDepth) is KtReferenceExpression -> evaluateReferenceExpression(expr, scopeDepth) @@ -132,7 +134,7 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM } val typePath = type.location.joinToString(".") - val methodName = "${if (typePath.length > 0) "$typePath." else "" }${clazz.structName}.${selectorName.substringBefore('(')}" + val methodName = "${if (typePath.length > 0) "$typePath." else ""}${clazz.structName}.${selectorName.substringBefore('(')}" val method = clazz.methods[methodName]!! val returnType = clazz.methods[methodName]!!.returnType!!.type @@ -173,8 +175,9 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM private fun evaluateReferenceExpression(expr: KtReferenceExpression, scopeDepth: Int, classScope: ClassCodegen? = null): LLVMSingleValue? = when (expr) { is KtArrayAccessExpression -> evaluateArrayAccessExpression(expr, scopeDepth + 1) else -> if ((expr is KtNameReferenceExpression) && (classScope != null)) evaluatenameReferenceExpression(expr, scopeDepth + 1, classScope) - else variableManager.getLLVMvalue(expr.firstChild.text) + else variableManager.getLLVMvalue(expr.firstChild.text) } + private fun evaluateCallExpression(expr: KtCallExpression, scopeDepth: Int, classScope: ClassCodegen? = null): LLVMSingleValue? { val function = expr.firstChild.firstChild.text val names = parseArgList(expr, scopeDepth) @@ -307,7 +310,11 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM val right = evaluateExpression(expr.lastChild, scopeDepth) ?: throw UnsupportedOperationException("Wrong binary exception") val operator = expr.operationToken - val result = codeBuilder.addPrimitiveBinaryOperation(operator, expr.operationReference, left, right) + return executeBinaryExpression(operator, expr.operationReference, left, right, scopeDepth) + } + + private fun executeBinaryExpression(operator: IElementType, referenceName: KtSimpleNameExpression?, left: LLVMSingleValue, right: LLVMSingleValue, scopeDepth: Int): LLVMVariable { + val result = codeBuilder.addPrimitiveBinaryOperation(operator, referenceName, left, right) if (left.type is LLVMReferenceType && left.pointer > 0 && right.pointer > 0) { variableManager.addVariable((left as LLVMVariable).kotlinName!!, result, scopeDepth) @@ -348,6 +355,56 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM } } + private fun evaluateWhenItem(item: KtWhenEntry, target: LLVMSingleValue, resultVariable: LLVMVariable, elseLabel: LLVMLabel, endLabel: LLVMLabel, isElse: Boolean, scopeDepth: Int) { + val successConditionsLabel = codeBuilder.getNewLabel(prefix = "when_condition_success") + var nextLabel = codeBuilder.getNewLabel(prefix = "when_condition_condition") + codeBuilder.addUnconditionalJump(nextLabel) + for (condition in item.conditions) { + codeBuilder.markWithLabel(nextLabel) + nextLabel = codeBuilder.getNewLabel(prefix = "when_condition_condition") + + val currentConditionExpression = evaluateExpression(condition.firstChild, scopeDepth + 1)!! + val conditionResult = executeBinaryExpression(KtTokens.EQEQ, null, target, currentConditionExpression, scopeDepth) + + codeBuilder.addCondition(conditionResult, successConditionsLabel, nextLabel) + } + codeBuilder.markWithLabel(nextLabel) + codeBuilder.addComment("last condition item") + codeBuilder.addUnconditionalJump(if (isElse) successConditionsLabel else elseLabel) + codeBuilder.markWithLabel(successConditionsLabel) + val successExpression = evaluateExpression(item.expression, scopeDepth + 1) + codeBuilder.storeVariable(resultVariable, successExpression ?: return) + codeBuilder.addUnconditionalJump(endLabel) + codeBuilder.addComment("end last condition item") + } + + private fun evaluateWhenExpression(expr: KtWhenExpression, scopeDepth: Int): LLVMVariable? { + codeBuilder.addComment("start when expression") + val whenExpression = expr.subjectExpression + + val targetExpression = evaluateExpression(whenExpression, scopeDepth + 1)!! + + val resultVariable = codeBuilder.getNewVariable(LLVMIntType(), pointer = 1) + codeBuilder.allocStackVarInPointer(resultVariable) + + var nextLabel = codeBuilder.getNewLabel(prefix = "when_start") + val endLabel = codeBuilder.getNewLabel(prefix = "when_end") + codeBuilder.addUnconditionalJump(nextLabel) + for (item in expr.entries) { + codeBuilder.addComment("start new when item") + codeBuilder.markWithLabel(nextLabel) + nextLabel = codeBuilder.getNewLabel(prefix = "when_item") + evaluateWhenItem(item, targetExpression, resultVariable, nextLabel, endLabel, item.isElse, scopeDepth + 1) + codeBuilder.addComment("end new when item") + } + codeBuilder.addComment("else branch of when expression") + codeBuilder.markWithLabel(nextLabel) + codeBuilder.addUnconditionalJump(endLabel) + codeBuilder.markWithLabel(endLabel) + codeBuilder.addComment("end when expression") + return resultVariable + } + private fun evaluateWhileOperator(element: LeafPsiElement, scopeDepth: Int): LLVMVariable? { var getBrackets = element.getNextSiblingIgnoringWhitespaceAndComments() ?: return null val condition = getBrackets.getNextSiblingIgnoringWhitespaceAndComments() ?: return null @@ -389,8 +446,8 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM private fun executeIfExpression(condition: KtBinaryExpression, thenExpression: PsiElement, elseExpression: PsiElement?, scopeDepth: Int): LLVMVariable? { val conditionResult: LLVMVariable = evaluateBinaryExpression(condition, scopeDepth + 1) - val variable = codeBuilder.getNewVariable(LLVMIntType(), pointer = 1) - codeBuilder.allocStackVar(variable) + val resultVariable = codeBuilder.getNewVariable(LLVMIntType(), pointer = 1) + codeBuilder.allocStackVar(resultVariable) val thenLabel = codeBuilder.getNewLabel(prefix = "if") val elseLabel = codeBuilder.getNewLabel(prefix = "if") val endLabel = codeBuilder.getNewLabel(prefix = "if") @@ -398,14 +455,14 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM codeBuilder.addCondition(conditionResult, thenLabel, elseLabel) codeBuilder.markWithLabel(thenLabel) val thenResultExpression = evaluateExpression(thenExpression, scopeDepth + 1) - codeBuilder.storeVariable(variable, thenResultExpression ?: return null) + codeBuilder.storeVariable(resultVariable, thenResultExpression ?: return null) codeBuilder.addUnconditionalJump(endLabel) codeBuilder.markWithLabel(elseLabel) val elseResultExpression = evaluateExpression(elseExpression, scopeDepth + 1) - codeBuilder.storeVariable(variable, elseResultExpression ?: return null) + codeBuilder.storeVariable(resultVariable, elseResultExpression ?: return null) codeBuilder.addUnconditionalJump(endLabel) codeBuilder.markWithLabel(endLabel) - return variable + return resultVariable } private fun executeIfBlock(condition: KtBinaryExpression, thenExpression: PsiElement, elseExpression: PsiElement?, scopeDepth: Int): LLVMVariable? { diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt index 564de179813..7756cc5e068 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt @@ -70,7 +70,7 @@ class LLVMBuilder(val arm: Boolean) { } } - fun addPrimitiveBinaryOperation(operation: IElementType, referenceName: KtSimpleNameExpression, firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMVariable { + fun addPrimitiveBinaryOperation(operation: IElementType, referenceName: KtSimpleNameExpression?, firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMVariable { val firstNativeOp = receiveNativeValue(firstOp) val secondNativeOp = receiveNativeValue(secondOp) val llvmExpression = when (operation) { @@ -105,7 +105,7 @@ class LLVMBuilder(val arm: Boolean) { storeVariable(result, secondNativeOp) return result } - else -> addPrimitiveReferenceOperation(referenceName, firstNativeOp, secondNativeOp) + else -> addPrimitiveReferenceOperation(referenceName!!, firstNativeOp, secondNativeOp) } val resultOp = getNewVariable(llvmExpression.variableType) addAssignment(resultOp, llvmExpression) @@ -172,6 +172,10 @@ class LLVMBuilder(val arm: Boolean) { localCode.appendln(code) } + fun addComment(comment: String) { + localCode.appendln("; " + comment) + } + fun loadVariableOffset(target: LLVMVariable, source: LLVMVariable, index: LLVMConstant) { val code = "$target = getelementptr inbounds ${source.type} $source, ${index.type} ${index.value}" localCode.appendln(code) @@ -201,6 +205,10 @@ class LLVMBuilder(val arm: Boolean) { localCode.appendln("$target = alloca ${target.getType()}, align ${target.type.align}") } + fun allocStackVarInPointer(target: LLVMVariable) { + localCode.appendln("$target = alloca ${target.type}, align ${target.type.align}") + } + fun allocStaticVar(target: LLVMVariable) { val allocedVar = getNewVariable(LLVMCharType(), pointer = 1) diff --git a/translator/src/test/kotlin/tests/input/when_expression_1.txt b/translator/src/test/kotlin/tests/input/when_expression_1.txt new file mode 100644 index 00000000000..b850499b9f0 --- /dev/null +++ b/translator/src/test/kotlin/tests/input/when_expression_1.txt @@ -0,0 +1,4 @@ +when_expression_1(21234) == 20 +when_expression_1(55555) == 50 +when_expression_1(345626) == 100 +when_expression_1(756754) == 100 diff --git a/translator/src/test/kotlin/tests/kotlin/when_expression_1.kt b/translator/src/test/kotlin/tests/kotlin/when_expression_1.kt new file mode 100644 index 00000000000..a5eb8226b8e --- /dev/null +++ b/translator/src/test/kotlin/tests/kotlin/when_expression_1.kt @@ -0,0 +1,8 @@ +fun when_expression_1(x: Int): Int { + val z = when (x) { + 21234 -> 20 + 55555 -> 50 + else -> 100 + } + return z +} \ No newline at end of file