From 22890b0cea8f07ef54c3ba87f09564d8e0d78509 Mon Sep 17 00:00:00 2001 From: Alexey Stepanov Date: Tue, 19 Jul 2016 16:20:59 +0300 Subject: [PATCH] translator: add init section, refactor FunctionCodegen, add BlockCodegen --- .../kotlinnative/translator/BlockCodegen.kt | 416 +++++++++++++++++ .../kotlinnative/translator/ClassCodegen.kt | 3 +- .../translator/FunctionCodegen.kt | 422 +----------------- .../kotlinnative/translator/ObjectCodegen.kt | 3 +- .../kotlinnative/translator/StructCodegen.kt | 21 +- .../tests/input/class_init_section_1.txt | 1 + .../tests/kotlin/class_init_section_1.kt | 14 + 7 files changed, 465 insertions(+), 415 deletions(-) create mode 100644 translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt create mode 100644 translator/src/test/kotlin/tests/input/class_init_section_1.txt create mode 100644 translator/src/test/kotlin/tests/kotlin/class_init_section_1.kt diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt new file mode 100644 index 00000000000..dacd836d6c2 --- /dev/null +++ b/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt @@ -0,0 +1,416 @@ +package org.kotlinnative.translator + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiWhiteSpace +import com.intellij.psi.impl.source.tree.LeafPsiElement +import org.jetbrains.kotlin.KtNodeTypes +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getNextSiblingIgnoringWhitespaceAndComments +import org.jetbrains.kotlin.psi.psiUtil.siblings +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.calls.callUtil.getValueArgumentsInParentheses +import org.jetbrains.kotlin.resolve.constants.TypedCompileTimeConstant +import org.kotlinnative.translator.llvm.* +import org.kotlinnative.translator.llvm.types.* +import java.util.* + + +abstract class BlockCodegen(open val state: TranslationState, open val variableManager: VariableManager, open val codeBuilder: LLVMBuilder) { + + val topLevel = 2 + var returnType: LLVMVariable? = null + var wasReturnOnTopLevel = false + + + protected fun evaluateCodeBlock(expr: PsiElement?, startLabel: LLVMLabel? = null, finishLabel: LLVMLabel? = null, scopeDepth: Int = 0) { + codeBuilder.markWithLabel(startLabel) + expressionWalker(expr, scopeDepth) + codeBuilder.addUnconditionalJump(finishLabel ?: return) + } + + private fun expressionWalker(expr: PsiElement?, scopeDepth: Int) { + when (expr) { + is KtBlockExpression -> expressionWalker(expr.firstChild, scopeDepth + 1) + is KtProperty -> evaluateValExpression(expr, scopeDepth) + is KtBinaryExpression -> evaluateBinaryExpression(expr, scopeDepth) + is KtCallExpression -> evaluateCallExpression(expr, scopeDepth) + is KtDoWhileExpression -> evaluateDoWhileExpression(expr.firstChild, scopeDepth + 1) + is PsiElement -> evaluateExpression(expr.firstChild, scopeDepth + 1) + null -> { + variableManager.pullUpwardsLevel(scopeDepth) + return + } + else -> UnsupportedOperationException() + } + + expressionWalker(expr.getNextSiblingIgnoringWhitespaceAndComments(), scopeDepth) + } + + private fun evaluateDoWhileExpression(element: PsiElement, scopeDepth: Int) { + val bodyExpression = element.getNextSiblingIgnoringWhitespaceAndComments() ?: return + val condition = bodyExpression.siblings(withItself = false).filter { it is KtContainerNode }.firstOrNull() ?: return + + executeWhileBlock(condition.firstChild as KtBinaryExpression, bodyExpression.firstChild, scopeDepth, checkConditionBeforeExecute = false) + } + + private fun evaluateExpression(expr: PsiElement?, scopeDepth: Int): LLVMSingleValue? { + return when (expr) { + is KtBinaryExpression -> evaluateBinaryExpression(expr, scopeDepth) + is KtConstantExpression -> evaluateConstantExpression(expr) + is KtCallExpression -> evaluateCallExpression(expr, scopeDepth) + is KtCallableReferenceExpression -> evaluateCallableReferenceExpression(expr) + is KtReferenceExpression -> evaluateReferenceExpression(expr, scopeDepth) + is KtIfExpression -> evaluateIfOperator(expr.firstChild as LeafPsiElement, scopeDepth + 1, true) + is KtDotQualifiedExpression -> evaluateDotExpression(expr, scopeDepth) + is KtStringTemplateExpression -> evaluateStringTemplateExpression(expr) + is PsiWhiteSpace -> null + is PsiElement -> evaluatePsiElement(expr, scopeDepth) + null -> null + else -> throw UnsupportedOperationException() + } + } + + fun evaluateStringTemplateExpression(expr: KtStringTemplateExpression): LLVMSingleValue? { + val receiveValue = state.bindingContext.get(BindingContext.COMPILE_TIME_VALUE, expr) + val type = (receiveValue as TypedCompileTimeConstant).type + val value = receiveValue.getValue(type) ?: return null + val variable = variableManager.receiveVariable(".str", LLVMStringType(value.toString().length), LLVMVariableScope(), pointer = 0) + + codeBuilder.addStringConstant(variable, value.toString()) + return variable + } + + private fun evaluateCallableReferenceExpression(expr: KtCallableReferenceExpression): LLVMSingleValue? { + val kotlinType = state.bindingContext.get(BindingContext.EXPRESSION_TYPE_INFO, expr)!!.type!! + return LLVMMapStandardType(expr.text.substring(2), kotlinType, LLVMVariableScope()) + } + + private fun evaluateDotExpression(expr: KtDotQualifiedExpression, scopeDepth: Int): LLVMSingleValue? { + val receiverName = expr.receiverExpression.text + val selectorName = expr.selectorExpression!!.text + + val receiver = variableManager.getLLVMvalue(receiverName)!! + + val clazz = state.classes[(receiver.type as LLVMReferenceType).type] ?: state.objects[(receiver.type as LLVMReferenceType).type]!! + val field = clazz.fieldsIndex[selectorName] + if (field != null) { + val result = codeBuilder.getNewVariable(field.type, pointer = 1) + codeBuilder.loadClassField(result, receiver, field.offset) + return result + } else { + val methodName = clazz.structName + '.' + selectorName.substringBefore('(') + val method = clazz.methods[methodName]!! + val returnType = clazz.methods[methodName]!!.returnType!!.type + val methodArgs = mutableListOf(receiver) + + val names = parseArgList(expr.lastChild as KtCallExpression, scopeDepth) + methodArgs.addAll(names) + + return evaluateFunctionCallExpression(LLVMVariable(methodName, returnType, scope = LLVMVariableScope()), loadArgsIfRequired(methodArgs, method.args)) + } + } + + fun evaluateArrayAccessExpression(expr: KtArrayAccessExpression, scope: Int): LLVMSingleValue? { + val arrayNameVariable = evaluateReferenceExpression(expr.arrayExpression as KtReferenceExpression, scope) as LLVMVariable + val arrayIndex = evaluateConstantExpression(expr.indexExpressions.first() as KtConstantExpression) + val arrayReceivedVariable = codeBuilder.loadAndGetVariable(arrayNameVariable) + val arrayElementType = (arrayNameVariable.type as LLVMArray).basicType() + val indexVariable = codeBuilder.getNewVariable(arrayElementType, pointer = 1) + codeBuilder.loadVariableOffset(indexVariable, arrayReceivedVariable, arrayIndex) + return indexVariable + } + + private fun evaluateReferenceExpression(expr: KtReferenceExpression, scopeDepth: Int): LLVMSingleValue? = when (expr) { + is KtArrayAccessExpression -> evaluateArrayAccessExpression(expr, scopeDepth + 1) + else -> variableManager.getLLVMvalue(expr.firstChild.text) + } + + private fun evaluateCallExpression(expr: KtCallExpression, scopeDepth: Int): LLVMSingleValue? { + val function = expr.firstChild.firstChild.text + val names = parseArgList(expr, scopeDepth) + + if (state.functions.containsKey(function)) { + val descriptor = state.functions[function] ?: return null + val args = loadArgsIfRequired(names, descriptor.args) + return evaluateFunctionCallExpression(LLVMVariable(function, descriptor.returnType!!.type, scope = LLVMVariableScope()), args) + } + + if (state.classes.containsKey(function)) { + val descriptor = state.classes[function] ?: return null + val args = loadArgsIfRequired(names, descriptor.fields) + return evaluateConstructorCallExpression(LLVMVariable(function, descriptor.type, scope = LLVMVariableScope()), args) + } + + val localFunction = variableManager.getLLVMvalue(function) + if (localFunction != null) { + val type = localFunction.type as LLVMFunctionType + val args = loadArgsIfRequired(names, type.arguments) + return evaluateFunctionCallExpression(LLVMVariable(function, type.returnType.type, scope = LLVMRegisterScope()), args) + } + + return null + } + + private fun evaluateFunctionCallExpression(function: LLVMVariable, names: List): LLVMSingleValue? { + val returnType = function.type + when (returnType) { + is LLVMVoidType -> { + codeBuilder.addLLVMCode(LLVMCall(LLVMVoidType(), function.toString(), names).toString()) + } + is LLVMReferenceType -> { + val result = codeBuilder.getNewVariable(returnType, pointer = 1) + codeBuilder.allocStaticVar(result) + + val args = ArrayList() + args.add(result) + args.addAll(names) + + codeBuilder.addLLVMCode(LLVMCall(LLVMVoidType(), function.toString(), args).toString()) + + return result + } + else -> { + val result = codeBuilder.getNewVariable(returnType) + codeBuilder.addAssignment(result, LLVMCall(returnType, function.toString(), names)) + + val resultPtr = codeBuilder.getNewVariable(returnType) + codeBuilder.allocStackVar(resultPtr) + resultPtr.pointer = 1 + codeBuilder.storeVariable(resultPtr, result) + return resultPtr + } + } + + return null + } + + private fun loadArgsIfRequired(names: List, args: List) = names.mapIndexed(fun(i: Int, value: LLVMSingleValue): LLVMSingleValue { + var result = value + + if (result.pointer > 0 && args[i].pointer == 0) { + result = codeBuilder.getNewVariable(args[i].type) + codeBuilder.loadVariable(result, value as LLVMVariable) + } + + return result + }).toList() + + private fun evaluateConstructorCallExpression(function: LLVMVariable, names: List): LLVMSingleValue? { + val result = codeBuilder.getNewVariable(function.type, pointer = 1) + codeBuilder.allocStaticVar(result) + + val args = ArrayList() + args.add(result) + args.addAll(names) + + codeBuilder.addLLVMCode(LLVMCall( + LLVMVoidType(), + function.toString(), + args + ).toString()) + + return result + } + + private fun parseArgList(expr: KtCallExpression, scopeDepth: Int): ArrayList { + val args = expr.getValueArgumentsInParentheses() + val result = ArrayList() + + for (arg in args) { + val currentExpression = evaluateExpression(arg.getArgumentExpression(), scopeDepth) as LLVMSingleValue + result.add(currentExpression) + } + + return result + } + + private fun evaluateBinaryExpression(expr: KtBinaryExpression, scopeDepth: Int): LLVMVariable { + val left = evaluateExpression(expr.firstChild, scopeDepth) ?: throw UnsupportedOperationException("Wrong binary exception") + val right = evaluateExpression(expr.lastChild, scopeDepth) ?: throw UnsupportedOperationException("Wrong binary exception") + val operator = expr.operationToken + return codeBuilder.addPrimitiveBinaryOperation(operator, expr.operationReference, left, right) + } + + private fun evaluateConstantExpression(expr: KtConstantExpression): LLVMConstant { + val node = expr.node + + val type = when (node.elementType) { + KtNodeTypes.BOOLEAN_CONSTANT -> LLVMBooleanType() + KtNodeTypes.INTEGER_CONSTANT -> LLVMIntType() + KtNodeTypes.FLOAT_CONSTANT -> LLVMDoubleType() + KtNodeTypes.CHARACTER_CONSTANT -> LLVMCharType() + KtNodeTypes.NULL -> LLVMNullType() + else -> throw IllegalArgumentException("Unknown type") + } + return LLVMConstant(node.firstChildNode.text, type, pointer = 0) + } + + private fun evaluatePsiElement(element: PsiElement, scopeDepth: Int): LLVMSingleValue? { + return when (element) { + is LeafPsiElement -> evaluateLeafPsiElement(element, scopeDepth) + is KtConstantExpression -> evaluateConstantExpression(element) + KtTokens.INTEGER_LITERAL -> null + else -> null + } + } + + private fun evaluateLeafPsiElement(element: LeafPsiElement, scopeDepth: Int): LLVMVariable? { + return when (element.elementType) { + KtTokens.RETURN_KEYWORD -> evaluateReturnInstruction(element, scopeDepth) + KtTokens.IF_KEYWORD -> evaluateIfOperator(element, scopeDepth, containReturn = false) + KtTokens.WHILE_KEYWORD -> evaluateWhileOperator(element, scopeDepth) + else -> null + } + } + + private fun evaluateWhileOperator(element: LeafPsiElement, scopeDepth: Int): LLVMVariable? { + var getBrackets = element.getNextSiblingIgnoringWhitespaceAndComments() ?: return null + val condition = getBrackets.getNextSiblingIgnoringWhitespaceAndComments() ?: return null + getBrackets = condition.getNextSiblingIgnoringWhitespaceAndComments() ?: return null + val bodyExpression = getBrackets.getNextSiblingIgnoringWhitespaceAndComments() ?: return null + + return executeWhileBlock(condition.firstChild as KtBinaryExpression, bodyExpression.firstChild, scopeDepth, checkConditionBeforeExecute = true) + } + + private fun executeWhileBlock(condition: KtBinaryExpression, bodyExpression: PsiElement, scopeDepth: Int, checkConditionBeforeExecute: Boolean): LLVMVariable? { + val conditionLabel = codeBuilder.getNewLabel(prefix = "while") + val bodyLabel = codeBuilder.getNewLabel(prefix = "while") + val exitLabel = codeBuilder.getNewLabel(prefix = "while") + + codeBuilder.addUnconditionalJump(if (checkConditionBeforeExecute) conditionLabel else bodyLabel) + codeBuilder.markWithLabel(conditionLabel) + val conditionResult = evaluateBinaryExpression(condition, scopeDepth + 1) + + codeBuilder.addCondition(conditionResult, bodyLabel, exitLabel) + evaluateCodeBlock(bodyExpression, bodyLabel, conditionLabel, scopeDepth + 1) + codeBuilder.markWithLabel(exitLabel) + + return null + } + + private fun evaluateIfOperator(element: LeafPsiElement, scopeDepth: Int, containReturn: Boolean): LLVMVariable? { + var getBrackets = element.getNextSiblingIgnoringWhitespaceAndComments() ?: return null + val condition = getBrackets.getNextSiblingIgnoringWhitespaceAndComments() ?: return null + getBrackets = condition.getNextSiblingIgnoringWhitespaceAndComments() ?: return null + val thenExpression = getBrackets.getNextSiblingIgnoringWhitespaceAndComments() ?: return null + val elseKeyword = thenExpression.getNextSiblingIgnoringWhitespaceAndComments() ?: return null + val elseExpression = elseKeyword.getNextSiblingIgnoringWhitespaceAndComments() ?: return null + + return when (containReturn) { + false -> executeIfBlock(condition.firstChild as KtBinaryExpression, thenExpression.firstChild, elseExpression.firstChild, scopeDepth + 1) + true -> executeIfExpression(condition.firstChild as KtBinaryExpression, thenExpression.firstChild, elseExpression.firstChild, scopeDepth + 1) + } + } + + 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 thenLabel = codeBuilder.getNewLabel(prefix = "if") + val elseLabel = codeBuilder.getNewLabel(prefix = "if") + val endLabel = codeBuilder.getNewLabel(prefix = "if") + + codeBuilder.addCondition(conditionResult, thenLabel, elseLabel) + codeBuilder.markWithLabel(thenLabel) + val thenResultExpression = evaluateExpression(thenExpression, scopeDepth + 1) + codeBuilder.storeVariable(variable, thenResultExpression ?: return null) + codeBuilder.addUnconditionalJump(endLabel) + codeBuilder.markWithLabel(elseLabel) + val elseResultExpression = evaluateExpression(elseExpression, scopeDepth + 1) + codeBuilder.storeVariable(variable, elseResultExpression ?: return null) + codeBuilder.addUnconditionalJump(endLabel) + codeBuilder.markWithLabel(endLabel) + return variable + } + + private fun executeIfBlock(condition: KtBinaryExpression, thenExpression: PsiElement, elseExpression: PsiElement?, scopeDepth: Int): LLVMVariable? { + val conditionResult = evaluateBinaryExpression(condition, scopeDepth + 1) + val thenLabel = codeBuilder.getNewLabel(prefix = "if") + val elseLabel = codeBuilder.getNewLabel(prefix = "if") + val endLabel = codeBuilder.getNewLabel(prefix = "if") + + codeBuilder.addCondition(conditionResult, thenLabel, elseLabel) + + evaluateCodeBlock(thenExpression, thenLabel, endLabel, scopeDepth + 1) + evaluateCodeBlock(elseExpression, elseLabel, endLabel, scopeDepth + 1) + + codeBuilder.markWithLabel(endLabel) + + return null + } + + private fun copyVariable(from: LLVMVariable, to: LLVMVariable) = when (from.type) { + is LLVMStringType -> codeBuilder.storeString(to, from, 0) + else -> codeBuilder.copyVariableValue(to, from) + } + + private fun evaluateValExpression(element: KtProperty, scopeDepth: Int): LLVMVariable? { + val variable = state.bindingContext.get(BindingContext.VARIABLE, element)!! + val identifier = variable.name.toString() + + val assignExpression = evaluateExpression(element.delegateExpressionOrInitializer, scopeDepth) ?: return null + + when (assignExpression) { + is LLVMVariable -> { + if (assignExpression.pointer == 0) { + val allocVar = variableManager.receiveVariable(identifier, assignExpression.type, LLVMRegisterScope(), pointer = 0) + codeBuilder.allocStackVar(allocVar) + allocVar.pointer++ + variableManager.addVariable(identifier, allocVar, scopeDepth) + copyVariable(assignExpression, allocVar) + } else { + variableManager.addVariable(identifier, assignExpression, scopeDepth) + } + } + is LLVMConstant -> { + if (assignExpression.type is LLVMNullType) { + val reference = LLVMMapStandardType(identifier, variable.type) + if (state.classes.containsKey(variable.type.toString().dropLast(1))) { + (reference.type as LLVMReferenceType).prefix = "class" + } + + codeBuilder.allocStackVar(reference) + reference.pointer += 1 + + codeBuilder.storeNull(reference) + val result = codeBuilder.loadAndGetVariable(reference) + + variableManager.addVariable(identifier, result, scopeDepth) + return null + } + + val newVar = variableManager.receiveVariable(identifier, assignExpression.type!!, LLVMRegisterScope(), pointer = 1) + codeBuilder.addConstant(newVar, assignExpression) + variableManager.addVariable(identifier, newVar, scopeDepth) + } + else -> { + throw UnsupportedOperationException() + } + } + return null + } + + private fun evaluateReturnInstruction(element: LeafPsiElement, scopeDepth: Int): LLVMVariable? { + val next = element.getNextSiblingIgnoringWhitespaceAndComments() + val retVar = evaluateExpression(next, scopeDepth) as LLVMSingleValue + + when (returnType!!.type) { + is LLVMReferenceType -> { + val src = codeBuilder.bitcast(retVar as LLVMVariable, LLVMVariable("", LLVMCharType(), pointer = 1)) + val dst = codeBuilder.bitcast(returnType!!, LLVMVariable("", LLVMCharType(), pointer = 1)) + val size = state.classes[(retVar.type as LLVMReferenceType).type]!!.size + codeBuilder.memcpy(dst, src, size) + codeBuilder.addAnyReturn(LLVMVoidType()) + } + else -> { + val retNativeValue = codeBuilder.receiveNativeValue(retVar) + codeBuilder.addReturnOperator(retNativeValue) + } + } + if (scopeDepth == topLevel + 2) { + wasReturnOnTopLevel = true + } + return null + } +} \ No newline at end of file diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt index 9f8b8f6ade4..a58958eef81 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt @@ -13,7 +13,7 @@ import org.kotlinnative.translator.llvm.types.LLVMReferenceType import org.kotlinnative.translator.llvm.types.LLVMType class ClassCodegen(override val state: TranslationState, override val variableManager: VariableManager, val clazz: KtClass, override val codeBuilder: LLVMBuilder) : - StructCodegen(state, variableManager, state.bindingContext.get(BindingContext.CLASS, clazz) ?: throw TranslationException(), codeBuilder) { + StructCodegen(state, variableManager, clazz, state.bindingContext.get(BindingContext.CLASS, clazz) ?: throw TranslationException(), codeBuilder) { val annotation: Boolean @@ -68,7 +68,6 @@ class ClassCodegen(override val state: TranslationState, override val variableMa if (annotation) { return } - generate(clazz.declarations) } diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt index 6a15e6b1248..4a35f659b7a 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt @@ -1,28 +1,21 @@ package org.kotlinnative.translator -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiWhiteSpace -import com.intellij.psi.impl.source.tree.LeafPsiElement -import org.jetbrains.kotlin.KtNodeTypes -import org.jetbrains.kotlin.lexer.KtTokens -import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.psi.psiUtil.getNextSiblingIgnoringWhitespaceAndComments -import org.jetbrains.kotlin.psi.psiUtil.siblings import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.calls.callUtil.getValueArgumentsInParentheses -import org.jetbrains.kotlin.resolve.constants.TypedCompileTimeConstant import org.kotlinnative.translator.llvm.* -import org.kotlinnative.translator.llvm.types.* +import org.kotlinnative.translator.llvm.types.LLVMFunctionType +import org.kotlinnative.translator.llvm.types.LLVMReferenceType +import org.kotlinnative.translator.llvm.types.LLVMType +import org.kotlinnative.translator.llvm.types.LLVMVoidType import java.util.* -class FunctionCodegen(val state: TranslationState, val variableManager: VariableManager, val function: KtNamedFunction, val codeBuilder: LLVMBuilder) { +class FunctionCodegen(override val state: TranslationState, override val variableManager: VariableManager, val function: KtNamedFunction, override val codeBuilder: LLVMBuilder) : + BlockCodegen(state, variableManager, codeBuilder) { var name = function.fqName.toString() - var returnType: LLVMVariable var args = ArrayList() - val topLevel = 2 - var wasReturnOnTopLevel = false init { val descriptor = state.bindingContext.get(BindingContext.FUNCTION, function)!! @@ -31,7 +24,7 @@ class FunctionCodegen(val state: TranslationState, val variableManager: Variable }) returnType = LLVMMapStandardType("instance", descriptor.returnType!!) - val retType = returnType.type + val retType = returnType!!.type when (retType) { is LLVMReferenceType -> { if (state.classes.containsKey(retType.type)) { @@ -56,7 +49,7 @@ class FunctionCodegen(val state: TranslationState, val variableManager: Variable evaluateCodeBlock(function.bodyExpression, scopeDepth = topLevel) if (!wasReturnOnTopLevel) - codeBuilder.addAnyReturn(returnType.type) + codeBuilder.addAnyReturn(returnType!!.type) codeBuilder.addEndExpression() } @@ -84,12 +77,12 @@ class FunctionCodegen(val state: TranslationState, val variableManager: Variable keyword = keyword.getNextSiblingIgnoringWhitespaceAndComments() } - var actualReturnType: LLVMType = returnType.type + var actualReturnType: LLVMType = returnType!!.type val actualArgs = ArrayList() - if (returnType.pointer > 0) { + if (returnType!!.pointer > 0) { actualReturnType = LLVMVoidType() - actualArgs.add(returnType) + actualArgs.add(returnType!!) } actualArgs.addAll(args) @@ -114,395 +107,4 @@ class FunctionCodegen(val state: TranslationState, val variableManager: Variable } }) } - - private fun evaluateCodeBlock(expr: PsiElement?, startLabel: LLVMLabel? = null, finishLabel: LLVMLabel? = null, scopeDepth: Int = 0) { - codeBuilder.markWithLabel(startLabel) - expressionWalker(expr, scopeDepth) - codeBuilder.addUnconditionalJump(finishLabel ?: return) - } - - private fun expressionWalker(expr: PsiElement?, scopeDepth: Int) { - when (expr) { - is KtBlockExpression -> expressionWalker(expr.firstChild, scopeDepth + 1) - is KtProperty -> evaluateValExpression(expr, scopeDepth) - is KtBinaryExpression -> evaluateBinaryExpression(expr, scopeDepth) - is KtCallExpression -> evaluateCallExpression(expr, scopeDepth) - is KtDoWhileExpression -> evaluateDoWhileExpression(expr.firstChild, scopeDepth + 1) - is PsiElement -> evaluateExpression(expr.firstChild, scopeDepth + 1) - null -> { - variableManager.pullUpwardsLevel(scopeDepth) - return - } - else -> UnsupportedOperationException() - } - - expressionWalker(expr.getNextSiblingIgnoringWhitespaceAndComments(), scopeDepth) - } - - private fun evaluateDoWhileExpression(element: PsiElement, scopeDepth: Int) { - val bodyExpression = element.getNextSiblingIgnoringWhitespaceAndComments() ?: return - val condition = bodyExpression.siblings(withItself = false).filter { it is KtContainerNode }.firstOrNull() ?: return - - executeWhileBlock(condition.firstChild as KtBinaryExpression, bodyExpression.firstChild, scopeDepth, checkConditionBeforeExecute = false) - } - - private fun evaluateExpression(expr: PsiElement?, scopeDepth: Int): LLVMSingleValue? { - return when (expr) { - is KtBinaryExpression -> evaluateBinaryExpression(expr, scopeDepth) - is KtConstantExpression -> evaluateConstantExpression(expr) - is KtCallExpression -> evaluateCallExpression(expr, scopeDepth) - is KtCallableReferenceExpression -> evaluateCallableReferenceExpression(expr) - is KtReferenceExpression -> evaluateReferenceExpression(expr, scopeDepth) - is KtIfExpression -> evaluateIfOperator(expr.firstChild as LeafPsiElement, scopeDepth + 1, true) - is KtDotQualifiedExpression -> evaluateDotExpression(expr, scopeDepth) - is KtStringTemplateExpression -> evaluateStringTemplateExpression(expr) - is PsiWhiteSpace -> null - is PsiElement -> evaluatePsiElement(expr, scopeDepth) - null -> null - else -> throw UnsupportedOperationException() - } - } - - fun evaluateStringTemplateExpression(expr: KtStringTemplateExpression): LLVMSingleValue? { - val receiveValue = state.bindingContext.get(BindingContext.COMPILE_TIME_VALUE, expr) - val type = (receiveValue as TypedCompileTimeConstant).type - val value = receiveValue.getValue(type) ?: return null - val variable = variableManager.receiveVariable(".str", LLVMStringType(value.toString().length), LLVMVariableScope(), pointer = 0) - - codeBuilder.addStringConstant(variable, value.toString()) - return variable - } - - private fun evaluateCallableReferenceExpression(expr: KtCallableReferenceExpression): LLVMSingleValue? { - val kotlinType = state.bindingContext.get(BindingContext.EXPRESSION_TYPE_INFO, expr)!!.type!! - return LLVMMapStandardType(expr.text.substring(2), kotlinType, LLVMVariableScope()) - } - - private fun evaluateDotExpression(expr: KtDotQualifiedExpression, scopeDepth: Int): LLVMSingleValue? { - val receiverName = expr.receiverExpression.text - val selectorName = expr.selectorExpression!!.text - - val receiver = variableManager.getLLVMvalue(receiverName)!! - - val clazz = state.classes[(receiver.type as LLVMReferenceType).type] ?: state.objects[(receiver.type as LLVMReferenceType).type]!! - val field = clazz.fieldsIndex[selectorName] - if (field != null) { - val result = codeBuilder.getNewVariable(field.type, pointer = 1) - codeBuilder.loadClassField(result, receiver, field.offset) - return result - } else { - val methodName = clazz.structName + '.' + selectorName.substringBefore('(') - val method = clazz.methods[methodName]!! - val returnType = clazz.methods[methodName]!!.returnType.type - val methodArgs = mutableListOf(receiver) - - val names = parseArgList(expr.lastChild as KtCallExpression, scopeDepth) - methodArgs.addAll(names) - - return evaluateFunctionCallExpression(LLVMVariable(methodName, returnType, scope = LLVMVariableScope()), loadArgsIfRequired(methodArgs, method.args)) - } - } - - fun evaluateArrayAccessExpression(expr: KtArrayAccessExpression, scope: Int): LLVMSingleValue? { - val arrayNameVariable = evaluateReferenceExpression(expr.arrayExpression as KtReferenceExpression, scope) as LLVMVariable - val arrayIndex = evaluateConstantExpression(expr.indexExpressions.first() as KtConstantExpression) - val arrayReceivedVariable = codeBuilder.loadAndGetVariable(arrayNameVariable) - val arrayElementType = (arrayNameVariable.type as LLVMArray).basicType() - val indexVariable = codeBuilder.getNewVariable(arrayElementType, pointer = 1) - codeBuilder.loadVariableOffset(indexVariable, arrayReceivedVariable, arrayIndex) - return indexVariable - } - - private fun evaluateReferenceExpression(expr: KtReferenceExpression, scopeDepth: Int): LLVMSingleValue? = when (expr) { - is KtArrayAccessExpression -> evaluateArrayAccessExpression(expr, scopeDepth + 1) - else -> variableManager.getLLVMvalue(expr.firstChild.text) - } - - private fun evaluateCallExpression(expr: KtCallExpression, scopeDepth: Int): LLVMSingleValue? { - val function = expr.firstChild.firstChild.text - val names = parseArgList(expr, scopeDepth) - - if (state.functions.containsKey(function)) { - val descriptor = state.functions[function] ?: return null - val args = loadArgsIfRequired(names, descriptor.args) - return evaluateFunctionCallExpression(LLVMVariable(function, descriptor.returnType.type, scope = LLVMVariableScope()), args) - } - - if (state.classes.containsKey(function)) { - val descriptor = state.classes[function] ?: return null - val args = loadArgsIfRequired(names, descriptor.fields) - return evaluateConstructorCallExpression(LLVMVariable(function, descriptor.type, scope = LLVMVariableScope()), args) - } - - val localFunction = variableManager.getLLVMvalue(function) - if (localFunction != null) { - val type = localFunction.type as LLVMFunctionType - val args = loadArgsIfRequired(names, type.arguments) - return evaluateFunctionCallExpression(LLVMVariable(function, type.returnType.type, scope = LLVMRegisterScope()), args) - } - - return null - } - - private fun evaluateFunctionCallExpression(function: LLVMVariable, names: List): LLVMSingleValue? { - val returnType = function.type - when (returnType) { - is LLVMVoidType -> { - codeBuilder.addLLVMCode(LLVMCall(LLVMVoidType(), function.toString(), names).toString()) - } - is LLVMReferenceType -> { - val result = codeBuilder.getNewVariable(returnType, pointer = 1) - codeBuilder.allocStaticVar(result) - - val args = ArrayList() - args.add(result) - args.addAll(names) - - codeBuilder.addLLVMCode(LLVMCall(LLVMVoidType(), function.toString(), args).toString()) - - return result - } - else -> { - val result = codeBuilder.getNewVariable(returnType) - codeBuilder.addAssignment(result, LLVMCall(returnType, function.toString(), names)) - - val resultPtr = codeBuilder.getNewVariable(returnType) - codeBuilder.allocStackVar(resultPtr) - resultPtr.pointer = 1 - codeBuilder.storeVariable(resultPtr, result) - return resultPtr - } - } - - return null - } - - private fun loadArgsIfRequired(names: List, args: List) = names.mapIndexed(fun(i: Int, value: LLVMSingleValue): LLVMSingleValue { - var result = value - - if (result.pointer > 0 && args[i].pointer == 0) { - result = codeBuilder.getNewVariable(args[i].type) - codeBuilder.loadVariable(result, value as LLVMVariable) - } - - return result - }).toList() - - private fun evaluateConstructorCallExpression(function: LLVMVariable, names: List): LLVMSingleValue? { - val result = codeBuilder.getNewVariable(function.type, pointer = 1) - codeBuilder.allocStaticVar(result) - - val args = ArrayList() - args.add(result) - args.addAll(names) - - codeBuilder.addLLVMCode(LLVMCall( - LLVMVoidType(), - function.toString(), - args - ).toString()) - - return result - } - - private fun parseArgList(expr: KtCallExpression, scopeDepth: Int): ArrayList { - val args = expr.getValueArgumentsInParentheses() - val result = ArrayList() - - for (arg in args) { - val currentExpression = evaluateExpression(arg.getArgumentExpression(), scopeDepth) as LLVMSingleValue - result.add(currentExpression) - } - - return result - } - - private fun evaluateBinaryExpression(expr: KtBinaryExpression, scopeDepth: Int): LLVMVariable { - val left = evaluateExpression(expr.firstChild, scopeDepth) ?: throw UnsupportedOperationException("Wrong binary exception") - val right = evaluateExpression(expr.lastChild, scopeDepth) ?: throw UnsupportedOperationException("Wrong binary exception") - val operator = expr.operationToken - return codeBuilder.addPrimitiveBinaryOperation(operator, expr.operationReference, left, right) - } - - private fun evaluateConstantExpression(expr: KtConstantExpression): LLVMConstant { - val node = expr.node - - val type = when (node.elementType) { - KtNodeTypes.BOOLEAN_CONSTANT -> LLVMBooleanType() - KtNodeTypes.INTEGER_CONSTANT -> LLVMIntType() - KtNodeTypes.FLOAT_CONSTANT -> LLVMDoubleType() - KtNodeTypes.CHARACTER_CONSTANT -> LLVMCharType() - KtNodeTypes.NULL -> LLVMNullType() - else -> throw IllegalArgumentException("Unknown type") - } - return LLVMConstant(node.firstChildNode.text, type, pointer = 0) - } - - private fun evaluatePsiElement(element: PsiElement, scopeDepth: Int): LLVMSingleValue? { - return when (element) { - is LeafPsiElement -> evaluateLeafPsiElement(element, scopeDepth) - is KtConstantExpression -> evaluateConstantExpression(element) - KtTokens.INTEGER_LITERAL -> null - else -> null - } - } - - private fun evaluateLeafPsiElement(element: LeafPsiElement, scopeDepth: Int): LLVMVariable? { - return when (element.elementType) { - KtTokens.RETURN_KEYWORD -> evaluateReturnInstruction(element, scopeDepth) - KtTokens.IF_KEYWORD -> evaluateIfOperator(element, scopeDepth, containReturn = false) - KtTokens.WHILE_KEYWORD -> evaluateWhileOperator(element, scopeDepth) - else -> null - } - } - - private fun evaluateWhileOperator(element: LeafPsiElement, scopeDepth: Int): LLVMVariable? { - var getBrackets = element.getNextSiblingIgnoringWhitespaceAndComments() ?: return null - val condition = getBrackets.getNextSiblingIgnoringWhitespaceAndComments() ?: return null - getBrackets = condition.getNextSiblingIgnoringWhitespaceAndComments() ?: return null - val bodyExpression = getBrackets.getNextSiblingIgnoringWhitespaceAndComments() ?: return null - - return executeWhileBlock(condition.firstChild as KtBinaryExpression, bodyExpression.firstChild, scopeDepth, checkConditionBeforeExecute = true) - } - - private fun executeWhileBlock(condition: KtBinaryExpression, bodyExpression: PsiElement, scopeDepth: Int, checkConditionBeforeExecute: Boolean): LLVMVariable? { - val conditionLabel = codeBuilder.getNewLabel(prefix = "while") - val bodyLabel = codeBuilder.getNewLabel(prefix = "while") - val exitLabel = codeBuilder.getNewLabel(prefix = "while") - - codeBuilder.addUnconditionalJump(if (checkConditionBeforeExecute) conditionLabel else bodyLabel) - codeBuilder.markWithLabel(conditionLabel) - val conditionResult = evaluateBinaryExpression(condition, scopeDepth + 1) - - codeBuilder.addCondition(conditionResult, bodyLabel, exitLabel) - evaluateCodeBlock(bodyExpression, bodyLabel, conditionLabel, scopeDepth + 1) - codeBuilder.markWithLabel(exitLabel) - - return null - } - - private fun evaluateIfOperator(element: LeafPsiElement, scopeDepth: Int, containReturn: Boolean): LLVMVariable? { - var getBrackets = element.getNextSiblingIgnoringWhitespaceAndComments() ?: return null - val condition = getBrackets.getNextSiblingIgnoringWhitespaceAndComments() ?: return null - getBrackets = condition.getNextSiblingIgnoringWhitespaceAndComments() ?: return null - val thenExpression = getBrackets.getNextSiblingIgnoringWhitespaceAndComments() ?: return null - val elseKeyword = thenExpression.getNextSiblingIgnoringWhitespaceAndComments() ?: return null - val elseExpression = elseKeyword.getNextSiblingIgnoringWhitespaceAndComments() ?: return null - - return when (containReturn) { - false -> executeIfBlock(condition.firstChild as KtBinaryExpression, thenExpression.firstChild, elseExpression.firstChild, scopeDepth + 1) - true -> executeIfExpression(condition.firstChild as KtBinaryExpression, thenExpression.firstChild, elseExpression.firstChild, scopeDepth + 1) - } - } - - 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 thenLabel = codeBuilder.getNewLabel(prefix = "if") - val elseLabel = codeBuilder.getNewLabel(prefix = "if") - val endLabel = codeBuilder.getNewLabel(prefix = "if") - - codeBuilder.addCondition(conditionResult, thenLabel, elseLabel) - codeBuilder.markWithLabel(thenLabel) - val thenResultExpression = evaluateExpression(thenExpression, scopeDepth + 1) - codeBuilder.storeVariable(variable, thenResultExpression ?: return null) - codeBuilder.addUnconditionalJump(endLabel) - codeBuilder.markWithLabel(elseLabel) - val elseResultExpression = evaluateExpression(elseExpression, scopeDepth + 1) - codeBuilder.storeVariable(variable, elseResultExpression ?: return null) - codeBuilder.addUnconditionalJump(endLabel) - codeBuilder.markWithLabel(endLabel) - return variable - } - - private fun executeIfBlock(condition: KtBinaryExpression, thenExpression: PsiElement, elseExpression: PsiElement?, scopeDepth: Int): LLVMVariable? { - val conditionResult = evaluateBinaryExpression(condition, scopeDepth + 1) - val thenLabel = codeBuilder.getNewLabel(prefix = "if") - val elseLabel = codeBuilder.getNewLabel(prefix = "if") - val endLabel = codeBuilder.getNewLabel(prefix = "if") - - codeBuilder.addCondition(conditionResult, thenLabel, elseLabel) - - evaluateCodeBlock(thenExpression, thenLabel, endLabel, scopeDepth + 1) - evaluateCodeBlock(elseExpression, elseLabel, endLabel, scopeDepth + 1) - - codeBuilder.markWithLabel(endLabel) - - return null - } - - private fun copyVariable(from: LLVMVariable, to: LLVMVariable) = when (from.type) { - is LLVMStringType -> codeBuilder.storeString(to, from, 0) - else -> codeBuilder.copyVariableValue(to, from) - } - - private fun evaluateValExpression(element: KtProperty, scopeDepth: Int): LLVMVariable? { - val variable = state.bindingContext.get(BindingContext.VARIABLE, element)!! - val identifier = variable.name.toString() - - val assignExpression = evaluateExpression(element.delegateExpressionOrInitializer, scopeDepth) ?: return null - - when (assignExpression) { - is LLVMVariable -> { - if (assignExpression.pointer == 0) { - val allocVar = variableManager.receiveVariable(identifier, assignExpression.type, LLVMRegisterScope(), pointer = 0) - codeBuilder.allocStackVar(allocVar) - allocVar.pointer++ - variableManager.addVariable(identifier, allocVar, scopeDepth) - copyVariable(assignExpression, allocVar) - } else { - variableManager.addVariable(identifier, assignExpression, scopeDepth) - } - } - is LLVMConstant -> { - if (assignExpression.type is LLVMNullType) { - val reference = LLVMMapStandardType(identifier, variable.type) - if (state.classes.containsKey(variable.type.toString().dropLast(1))) { - (reference.type as LLVMReferenceType).prefix = "class" - } - - codeBuilder.allocStackVar(reference) - reference.pointer += 1 - - codeBuilder.storeNull(reference) - val result = codeBuilder.loadAndGetVariable(reference) - - variableManager.addVariable(identifier, result, scopeDepth) - return null - } - - val newVar = variableManager.receiveVariable(identifier, assignExpression.type!!, LLVMRegisterScope(), pointer = 1) - codeBuilder.addConstant(newVar, assignExpression) - variableManager.addVariable(identifier, newVar, scopeDepth) - } - else -> { - throw UnsupportedOperationException() - } - } - return null - } - - private fun evaluateReturnInstruction(element: LeafPsiElement, scopeDepth: Int): LLVMVariable? { - val next = element.getNextSiblingIgnoringWhitespaceAndComments() - val retVar = evaluateExpression(next, scopeDepth) as LLVMSingleValue - - when (returnType.type) { - is LLVMReferenceType -> { - val src = codeBuilder.bitcast(retVar as LLVMVariable, LLVMVariable("", LLVMCharType(), pointer = 1)) - val dst = codeBuilder.bitcast(returnType, LLVMVariable("", LLVMCharType(), pointer = 1)) - val size = state.classes[(retVar.type as LLVMReferenceType).type]!!.size - codeBuilder.memcpy(dst, src, size) - codeBuilder.addAnyReturn(LLVMVoidType()) - } - else -> { - val retNativeValue = codeBuilder.receiveNativeValue(retVar) - codeBuilder.addReturnOperator(retNativeValue) - } - } - if (scopeDepth == topLevel + 2) { - wasReturnOnTopLevel = true - } - return null - } } \ No newline at end of file diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/ObjectCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/ObjectCodegen.kt index d34292d6097..e9d65ec581a 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/ObjectCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/ObjectCodegen.kt @@ -10,7 +10,8 @@ import org.kotlinnative.translator.llvm.types.LLVMReferenceType import org.kotlinnative.translator.llvm.types.LLVMType class ObjectCodegen(override val state: TranslationState, override val variableManager: VariableManager, val objectDeclaration: KtObjectDeclaration, override val codeBuilder: LLVMBuilder) : - StructCodegen(state, variableManager, state.bindingContext.get(BindingContext.CLASS, objectDeclaration) ?: throw TranslationException(), codeBuilder) { + StructCodegen(state, variableManager, objectDeclaration, state.bindingContext.get(BindingContext.CLASS, objectDeclaration) ?: throw TranslationException(), + codeBuilder) { override val size: Int = 0 override val structName: String override val type: LLVMType = LLVMReferenceType(objectDeclaration.name.toString(), "class", byRef = true) diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/StructCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/StructCodegen.kt index 847acfb94ed..58a5c13a278 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/StructCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/StructCodegen.kt @@ -1,6 +1,8 @@ package org.kotlinnative.translator +import com.intellij.psi.PsiElement import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.psi.KtParameter @@ -12,7 +14,9 @@ import org.kotlinnative.translator.llvm.types.LLVMType import org.kotlinnative.translator.llvm.types.LLVMVoidType import java.util.* -abstract class StructCodegen(open val state: TranslationState, open val variableManager: VariableManager, open val classDescriptor: ClassDescriptor, open val codeBuilder: LLVMBuilder) { +abstract class StructCodegen(open val state: TranslationState, open val variableManager: VariableManager, open val classOrObject: KtClassOrObject, + val classDescriptor: ClassDescriptor, + open val codeBuilder: LLVMBuilder) { val plain: Boolean = false // TODO val fields = ArrayList() @@ -22,8 +26,8 @@ abstract class StructCodegen(open val state: TranslationState, open val variable var methods = HashMap() abstract val structName: String - fun generate(declarationList: List) { + generateStruct() generatePrimaryConstructor() @@ -65,6 +69,7 @@ abstract class StructCodegen(open val state: TranslationState, open val variable codeBuilder.addStartExpression() generateLoadArguments(classVal) generateAssignments() + genClassInitializers() generateReturn() codeBuilder.addAnyReturn(LLVMVoidType()) codeBuilder.addEndExpression() @@ -144,4 +149,16 @@ abstract class StructCodegen(open val state: TranslationState, open val variable return result } + + protected fun genClassInitializers() { + for (init in classOrObject.getAnonymousInitializers()) { + val blockCodegen = object : BlockCodegen(state, variableManager, codeBuilder) { + fun generate(expr: PsiElement?) { + evaluateCodeBlock(expr, scopeDepth = topLevel) + } + } + blockCodegen.generate(init.body) + } + + } } diff --git a/translator/src/test/kotlin/tests/input/class_init_section_1.txt b/translator/src/test/kotlin/tests/input/class_init_section_1.txt new file mode 100644 index 00000000000..df0e702a438 --- /dev/null +++ b/translator/src/test/kotlin/tests/input/class_init_section_1.txt @@ -0,0 +1 @@ +class_init_section(523) == 12868 \ No newline at end of file diff --git a/translator/src/test/kotlin/tests/kotlin/class_init_section_1.kt b/translator/src/test/kotlin/tests/kotlin/class_init_section_1.kt new file mode 100644 index 00000000000..c072acd3d22 --- /dev/null +++ b/translator/src/test/kotlin/tests/kotlin/class_init_section_1.kt @@ -0,0 +1,14 @@ +class className(var z: Int) { + init { + this.z = this.z + 12345 + } + + fun getVal(): Int { + return this.z + } +} + +fun class_init_section_1(x: Int): Int { + val z = className(x) + return z.getVal() +} \ No newline at end of file