From 7f90be6c0a67992fb1da46680062a49df3558f88 Mon Sep 17 00:00:00 2001 From: Alexey Stepanov Date: Wed, 20 Jul 2016 18:39:08 +0300 Subject: [PATCH] translator: add companion objects with methods --- .../kotlinnative/translator/BlockCodegen.kt | 22 +++++++++++++++++++ .../kotlinnative/translator/ClassCodegen.kt | 19 ++++++++++++++-- .../translator/FunctionCodegen.kt | 7 ++++-- .../kotlinnative/translator/ObjectCodegen.kt | 15 ++++++++----- .../kotlinnative/translator/StructCodegen.kt | 8 +++++-- .../main/resources/kotlib/kotlin/ByteArray.kt | 2 +- .../kotlin/tests/input/companion_object_1.txt | 1 + .../kotlin/tests/kotlin/companion_object_1.kt | 14 ++++++++++++ 8 files changed, 76 insertions(+), 12 deletions(-) create mode 100644 translator/src/test/kotlin/tests/input/companion_object_1.txt create mode 100644 translator/src/test/kotlin/tests/kotlin/companion_object_1.kt diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt index f81e55ffdb6..ea8c7ef7e99 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt @@ -101,6 +101,7 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM } private fun evaluateClassScopedDotExpression(clazz: ClassCodegen, selector: KtExpression, scopeDepth: Int): LLVMSingleValue? = when (selector) { + is KtCallExpression -> evaluateCallExpression(selector, scopeDepth, clazz) else -> throw UnsupportedOperationException() } @@ -182,6 +183,27 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM return evaluateFunctionCallExpression(LLVMVariable(function, type.returnType.type, scope = LLVMRegisterScope()), args) } + if (state.classes.containsKey(classScope?.structName)) { + val classDescriptor = state.classes[classScope?.structName] ?: return null + val methodShortName = classScope?.structName + "." + function + if (classDescriptor.companionMethods.containsKey(methodShortName)) { + val descriptor = classDescriptor.companionMethods[methodShortName] ?: return null + val parentDescriptor = descriptor.parentCodegen!! + val receiver = variableManager.getLLVMvalue(parentDescriptor.structName)!! + val methodFullName = descriptor.name + + val returnType = descriptor.returnType!!.type + + val loadedArgs = loadArgsIfRequired(names, descriptor.args) + val callArgs = mutableListOf(receiver) + callArgs.addAll(loadedArgs) + + return evaluateFunctionCallExpression(LLVMVariable(methodFullName, returnType, scope = LLVMVariableScope()), callArgs) + + } + + } + val nestedConstructor = classScope?.nestedClasses?.get(expr.calleeExpression!!.text) if (nestedConstructor != null) { val args = loadArgsIfRequired(names, nestedConstructor.constructorFields) diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt index 4242a1e9f31..8556c1567fb 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt @@ -23,10 +23,11 @@ class ClassCodegen(override val state: TranslationState, override var size: Int = 0 override val structName: String - override val type: LLVMReferenceType = LLVMReferenceType(clazz.name.toString(), "class", byRef = true) + override val type: LLVMReferenceType init { - structName = clazz.name!! + structName = (if (parentCodegen != null) parentCodegen.structName + "." else "") + clazz.name!! + type = LLVMReferenceType(structName, "class", byRef = true) val descriptor = state.bindingContext.get(BindingContext.CLASS, clazz) ?: throw TranslationException() val parameterList = clazz.getPrimaryConstructorParameterList()?.parameters ?: listOf() @@ -76,6 +77,20 @@ class ClassCodegen(override val state: TranslationState, generate(clazz.declarations) nestedClasses.forEach { x, classCodegen -> classCodegen.generate() } + + val descriptor = state.bindingContext.get(BindingContext.CLASS, clazz) ?: throw TranslationException() + val companionObjectDescriptor = descriptor.companionObjectDescriptor + if (companionObjectDescriptor != null) { + val companionObject = clazz.getCompanionObjects().first() + val property = ObjectCodegen(state, variableManager, companionObject, codeBuilder, this) + val companionObjectName = structName + "." + companionObject.name + property.generate() + + for (method in property.methods) { + val methodName = method.key.removePrefix(companionObjectName + ".") + companionMethods.put(structName + "." + methodName, method.value) + } + } } } diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt index 5fe1a85da04..f8204a2cd42 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt @@ -11,8 +11,11 @@ import org.kotlinnative.translator.llvm.types.LLVMVoidType import java.util.* -class FunctionCodegen(override val state: TranslationState, override val variableManager: VariableManager, val function: KtNamedFunction, - override val codeBuilder: LLVMBuilder) : +class FunctionCodegen(override val state: TranslationState, + override val variableManager: VariableManager, + val function: KtNamedFunction, + override val codeBuilder: LLVMBuilder, + val parentCodegen: StructCodegen? = null) : BlockCodegen(state, variableManager, codeBuilder) { var name = function.fqName.toString() diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/ObjectCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/ObjectCodegen.kt index 94aec5115bc..6787e85bce9 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/ObjectCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/ObjectCodegen.kt @@ -8,21 +8,26 @@ import org.kotlinnative.translator.llvm.LLVMVariable import org.kotlinnative.translator.llvm.LLVMVariableScope import org.kotlinnative.translator.llvm.types.LLVMReferenceType -class ObjectCodegen(override val state: TranslationState, override val variableManager: VariableManager, val objectDeclaration: KtObjectDeclaration, override val codeBuilder: LLVMBuilder) : +class ObjectCodegen(override val state: TranslationState, + override val variableManager: VariableManager, + val objectDeclaration: KtObjectDeclaration, + override val codeBuilder: LLVMBuilder, + override val parentCodegen: StructCodegen? = null) : StructCodegen(state, variableManager, objectDeclaration, state.bindingContext.get(BindingContext.CLASS, objectDeclaration) ?: throw TranslationException(), - codeBuilder) { + codeBuilder, parentCodegen = parentCodegen) { override var size: Int = 0 override val structName: String - override val type: LLVMReferenceType = LLVMReferenceType(objectDeclaration.name.toString(), "class", byRef = true) + override val type: LLVMReferenceType init { - structName = objectDeclaration.name!! + structName = (if (parentCodegen != null) parentCodegen.structName + "." else "") + objectDeclaration.name!! + type = LLVMReferenceType(structName, "class", byRef = true) generateInnerFields(objectDeclaration.declarations) } fun generate() { generate(objectDeclaration.declarations) - val classInstance = LLVMVariable("object.instance.$structName", type, objectDeclaration.name, LLVMVariableScope(), pointer=1) + val classInstance = LLVMVariable("object.instance.$structName", type, objectDeclaration.name, LLVMVariableScope(), pointer = 1) codeBuilder.addGlobalIntialize(classInstance, type) variableManager.addGlobalVariable(structName, classInstance) } diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/StructCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/StructCodegen.kt index afefe2adea6..51293005bdd 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/StructCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/StructCodegen.kt @@ -16,11 +16,12 @@ abstract class StructCodegen(open val state: TranslationState, open val classOrObject: KtClassOrObject, val classDescriptor: ClassDescriptor, open val codeBuilder: LLVMBuilder, - val owner: StructCodegen? = null) { + open val parentCodegen: StructCodegen? = null) { val fields = ArrayList() val fieldsIndex = HashMap() val nestedClasses = HashMap() + val companionMethods = HashMap() val constructorFields = ArrayList() @@ -31,6 +32,7 @@ abstract class StructCodegen(open val state: TranslationState, val fullName: String get() = "${if (type.location.size > 0) "${type.location.joinToString(".")}." else ""}$structName" + fun generate(declarations: List) { generateStruct() generatePrimaryConstructor() @@ -38,13 +40,15 @@ abstract class StructCodegen(open val state: TranslationState, for (declaration in declarations) { when (declaration) { is KtNamedFunction -> { - val function = FunctionCodegen(state, variableManager, declaration, codeBuilder) + val function = FunctionCodegen(state, variableManager, declaration, codeBuilder, this) methods.put(function.name, function) } } } + val classVal = LLVMVariable("classvariable.this", type, pointer = 1) variableManager.addVariable("this", classVal, 0) + for (function in methods.values) { function.generate(classVal) } diff --git a/translator/src/main/resources/kotlib/kotlin/ByteArray.kt b/translator/src/main/resources/kotlib/kotlin/ByteArray.kt index 0626e5bb6f0..fddd12f76a1 100644 --- a/translator/src/main/resources/kotlib/kotlin/ByteArray.kt +++ b/translator/src/main/resources/kotlib/kotlin/ByteArray.kt @@ -37,4 +37,4 @@ class ByteArray(var size: Int) { return newInstance } -} \ No newline at end of file +} diff --git a/translator/src/test/kotlin/tests/input/companion_object_1.txt b/translator/src/test/kotlin/tests/input/companion_object_1.txt new file mode 100644 index 00000000000..f66e0b5dacb --- /dev/null +++ b/translator/src/test/kotlin/tests/input/companion_object_1.txt @@ -0,0 +1 @@ +companion_object_1() == 5 diff --git a/translator/src/test/kotlin/tests/kotlin/companion_object_1.kt b/translator/src/test/kotlin/tests/kotlin/companion_object_1.kt new file mode 100644 index 00000000000..a24f8fd6d1a --- /dev/null +++ b/translator/src/test/kotlin/tests/kotlin/companion_object_1.kt @@ -0,0 +1,14 @@ +class companion_object { + companion object Factory { + val fieldCompanion: Int = 5790 + + fun create(): Int { + return 5 + } + } +} + + +fun companion_object_1(): Int { + return companion_object.create() +} \ No newline at end of file