translator: add secondary constructors
This commit is contained in:
@@ -31,7 +31,7 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
|
||||
var returnType: LLVMVariable? = null
|
||||
var wasReturnOnTopLevel = false
|
||||
|
||||
protected fun evaluateCodeBlock(expr: PsiElement?, startLabel: LLVMLabel? = null, nextIterationLabel: LLVMLabel? = null, breakLabel: LLVMLabel? = null, scopeDepth: Int = 0, isBlock: Boolean = true) {
|
||||
fun evaluateCodeBlock(expr: PsiElement?, startLabel: LLVMLabel? = null, nextIterationLabel: LLVMLabel? = null, breakLabel: LLVMLabel? = null, scopeDepth: Int = 0, isBlock: Boolean = true) {
|
||||
codeBuilder.markWithLabel(startLabel)
|
||||
if (isBlock) {
|
||||
expressionWalker(expr, breakLabel, scopeDepth)
|
||||
@@ -116,6 +116,14 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
|
||||
}
|
||||
}
|
||||
|
||||
fun evaluateConstructorDelegationReferenceExpression(expr: KtConstructorDelegationReferenceExpression, structCodegen: StructCodegen, constructorArguments: List<LLVMVariable>, scopeDepth: Int): LLVMSingleValue? {
|
||||
val targetCall = state.bindingContext.get(BindingContext.CALL, expr)
|
||||
|
||||
val names = parseValueArguments(targetCall!!.valueArguments, scopeDepth)
|
||||
val args = loadArgsIfRequired(names, constructorArguments)
|
||||
return evaluateConstructorCallExpression(LLVMVariable(structCodegen.fullName + structCodegen.primaryConstructorIndex, structCodegen.type, scope = LLVMVariableScope()), args)
|
||||
}
|
||||
|
||||
private fun evaluateThisExpression(): LLVMSingleValue? {
|
||||
return variableManager["this"]
|
||||
}
|
||||
@@ -247,7 +255,7 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
|
||||
else -> LLVMVariable("type", standardType, pointer = 0)
|
||||
}
|
||||
|
||||
val args = mutableListOf(loadArgumentIfRequired(receiverExpression, typeThisArgument))
|
||||
val args = mutableListOf(codeBuilder.loadArgumentIfRequired(receiverExpression, typeThisArgument))
|
||||
args.addAll(loadArgsIfRequired(names, extensionCodegen.args))
|
||||
return evaluateFunctionCallExpression(LLVMVariable(extensionCodegen.fullName, extensionCodegen.returnType!!.type, scope = LLVMVariableScope()), args)
|
||||
}
|
||||
@@ -315,7 +323,7 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
|
||||
val arrayActionType = if (callMaker.callType == Call.CallType.ARRAY_SET_METHOD) "set" else "get"
|
||||
val explicitReceiver = callMaker.explicitReceiver as ExpressionReceiver
|
||||
val receiver = evaluateExpression(explicitReceiver.expression, scope)!! as LLVMVariable
|
||||
val pureReceiver = downLoadArgument(receiver, 1)
|
||||
val pureReceiver = codeBuilder.downLoadArgument(receiver, 1)
|
||||
|
||||
val targetClassName = (receiver.type as LLVMReferenceType).type
|
||||
|
||||
@@ -397,7 +405,6 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
|
||||
val names = parseArgList(expr, scopeDepth)
|
||||
var name = expr.firstChild.firstChild.text
|
||||
val external = state.externalFunctions.containsKey(name)
|
||||
|
||||
val function = "$name${if (names.size > 0 && !external) "_${names.joinToString(separator = "_", transform = { it.type!!.mangle() })}" else ""}"
|
||||
|
||||
if (state.functions.containsKey(function) || state.externalFunctions.containsKey(function)) {
|
||||
@@ -408,8 +415,9 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
|
||||
|
||||
if (state.classes.containsKey(name) || classScope?.structName == name) {
|
||||
val descriptor = state.classes[name] ?: classScope ?: return null
|
||||
val args = loadArgsIfRequired(names, descriptor.constructorFields)
|
||||
return evaluateConstructorCallExpression(LLVMVariable(descriptor.fullName, descriptor.type, scope = LLVMVariableScope()), args)
|
||||
val detectedConstructor = LLVMType.mangleFunctionArguments(names)
|
||||
val args = loadArgsIfRequired(names, descriptor.constructorFields[detectedConstructor]!!)
|
||||
return evaluateConstructorCallExpression(LLVMVariable(descriptor.fullName + detectedConstructor, descriptor.type, scope = LLVMVariableScope()), args)
|
||||
}
|
||||
|
||||
val localFunction = variableManager[name]
|
||||
@@ -437,7 +445,7 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
|
||||
|
||||
val nestedConstructor = classScope?.nestedClasses?.get(expr.calleeExpression!!.text)
|
||||
if (nestedConstructor != null) {
|
||||
val args = loadArgsIfRequired(names, nestedConstructor.constructorFields)
|
||||
val args = loadArgsIfRequired(names, nestedConstructor.constructorFields[nestedConstructor.primaryConstructorIndex]!!)
|
||||
return evaluateConstructorCallExpression(LLVMVariable(nestedConstructor.fullName, nestedConstructor.type, scope = LLVMVariableScope()), args)
|
||||
}
|
||||
|
||||
@@ -445,7 +453,6 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
|
||||
name = "${containingClass.fullName}.$function"
|
||||
val method = containingClass.methods[name]!!
|
||||
val args = mutableListOf<LLVMSingleValue>()
|
||||
val leftName = (expr.context as? KtDotQualifiedExpression)?.receiverExpression?.text
|
||||
|
||||
if (caller != null) {
|
||||
args.add(caller)
|
||||
@@ -467,7 +474,6 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
|
||||
if (location.size > 0) {
|
||||
val type = LLVMReferenceType(name, prefix = "class")
|
||||
type.location.addAll(location)
|
||||
|
||||
return resolveClassOrObjectLocation(type)
|
||||
}
|
||||
|
||||
@@ -510,34 +516,9 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
|
||||
return null
|
||||
}
|
||||
|
||||
private fun loadArgumentIfRequired(value: LLVMSingleValue, argument: LLVMVariable): LLVMSingleValue {
|
||||
var result = value
|
||||
|
||||
while (argument.pointer < result.pointer) {
|
||||
result = codeBuilder.getNewVariable(argument.type, pointer = result.pointer - 1)
|
||||
codeBuilder.loadVariable(result, value as LLVMVariable)
|
||||
}
|
||||
|
||||
when (value.type) {
|
||||
is LLVMStringType -> if (!(value.type as LLVMStringType).isLoaded) {
|
||||
val newVariable = codeBuilder.getNewVariable(value.type!!, pointer = result.pointer + 1)
|
||||
codeBuilder.allocStackVar(newVariable, asValue = true)
|
||||
codeBuilder.copyVariable(result as LLVMVariable, newVariable)
|
||||
|
||||
result = codeBuilder.getNewVariable(argument.type, pointer = newVariable.pointer - 1)
|
||||
codeBuilder.loadVariable(result, newVariable)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun downLoadArgument(value: LLVMSingleValue, pointer: Int): LLVMSingleValue =
|
||||
loadArgumentIfRequired(value, LLVMVariable("", value.type!!, pointer = pointer))
|
||||
|
||||
private fun loadArgsIfRequired(names: List<LLVMSingleValue>, args: List<LLVMVariable>) =
|
||||
names.mapIndexed(fun(i: Int, value: LLVMSingleValue): LLVMSingleValue {
|
||||
return loadArgumentIfRequired(value, args[i])
|
||||
return codeBuilder.loadArgumentIfRequired(value, args[i])
|
||||
}).toList()
|
||||
|
||||
private fun evaluateConstructorCallExpression(function: LLVMVariable, names: List<LLVMSingleValue>): LLVMSingleValue? {
|
||||
@@ -968,7 +949,7 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
|
||||
|
||||
private fun evaluateIfOperator(element: KtIfExpression, scopeDepth: Int, isExpression: Boolean = true): LLVMVariable? {
|
||||
val conditionResult = evaluateExpression(element.condition, scopeDepth)!!
|
||||
val conditionNativeResult = downLoadArgument(conditionResult, 0)
|
||||
val conditionNativeResult = codeBuilder.downLoadArgument(conditionResult, 0)
|
||||
|
||||
return if (isExpression)
|
||||
executeIfExpression(conditionNativeResult, element.then!!, element.`else`, element, scopeDepth + 1)
|
||||
|
||||
@@ -6,7 +6,10 @@ import org.jetbrains.kotlin.psi.KtParameter
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.kotlinnative.translator.exceptions.TranslationException
|
||||
import org.kotlinnative.translator.llvm.LLVMBuilder
|
||||
import org.kotlinnative.translator.llvm.LLVMVariable
|
||||
import org.kotlinnative.translator.llvm.types.LLVMReferenceType
|
||||
import org.kotlinnative.translator.llvm.types.LLVMType
|
||||
import java.util.*
|
||||
|
||||
class ClassCodegen(state: TranslationState,
|
||||
variableManager: VariableManager,
|
||||
@@ -49,15 +52,17 @@ class ClassCodegen(state: TranslationState,
|
||||
if (annotation) {
|
||||
return
|
||||
}
|
||||
|
||||
val currentConstructorFields = ArrayList<LLVMVariable>()
|
||||
for (field in parameters) {
|
||||
val item = resolveType(field, state.bindingContext.get(BindingContext.TYPE, field.typeReference)!!)
|
||||
item.offset = fields.size
|
||||
|
||||
constructorFields.add(item)
|
||||
currentConstructorFields.add(item)
|
||||
fields.add(item)
|
||||
fieldsIndex[item.label] = item
|
||||
}
|
||||
primaryConstructorIndex = LLVMType.mangleFunctionArguments(currentConstructorFields)
|
||||
constructorFields.put(primaryConstructorIndex!!, currentConstructorFields)
|
||||
}
|
||||
|
||||
override fun prepareForGenerate() {
|
||||
|
||||
@@ -7,6 +7,7 @@ import org.kotlinnative.translator.llvm.LLVMBuilder
|
||||
import org.kotlinnative.translator.llvm.LLVMVariable
|
||||
import org.kotlinnative.translator.llvm.LLVMVariableScope
|
||||
import org.kotlinnative.translator.llvm.types.LLVMReferenceType
|
||||
import org.kotlinnative.translator.llvm.types.LLVMType
|
||||
|
||||
class ObjectCodegen(state: TranslationState,
|
||||
variableManager: VariableManager,
|
||||
@@ -25,6 +26,9 @@ class ObjectCodegen(state: TranslationState,
|
||||
type.location.addAll(parentCodegen.type.location)
|
||||
type.location.add(parentCodegen.structName)
|
||||
}
|
||||
primaryConstructorIndex = LLVMType.mangleFunctionArguments(emptyList())
|
||||
constructorFields.put(primaryConstructorIndex!!, arrayListOf())
|
||||
|
||||
generateInnerFields(objectDeclaration.declarations)
|
||||
|
||||
calculateTypeSize()
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.kotlinnative.translator.llvm.*
|
||||
import org.kotlinnative.translator.llvm.types.LLVMCharType
|
||||
import org.kotlinnative.translator.llvm.types.LLVMReferenceType
|
||||
import org.kotlinnative.translator.llvm.types.LLVMType
|
||||
import org.kotlinnative.translator.llvm.types.LLVMVoidType
|
||||
import java.util.*
|
||||
|
||||
@@ -24,7 +25,8 @@ abstract class StructCodegen(val state: TranslationState,
|
||||
val nestedClasses = HashMap<String, ClassCodegen>()
|
||||
val enumFields = HashMap<String, LLVMVariable>()
|
||||
|
||||
val constructorFields = ArrayList<LLVMVariable>()
|
||||
val constructorFields = HashMap<String, ArrayList<LLVMVariable>>()
|
||||
var primaryConstructorIndex: String? = null
|
||||
val initializedFields = HashMap<LLVMVariable, KtExpression>()
|
||||
|
||||
abstract val type: LLVMReferenceType
|
||||
@@ -67,6 +69,9 @@ abstract class StructCodegen(val state: TranslationState,
|
||||
open fun generate() {
|
||||
generateEnumFields()
|
||||
generatePrimaryConstructor()
|
||||
for (secondaryConstructor in classOrObject.getSecondaryConstructors()) {
|
||||
generateSecondaryConstructor(secondaryConstructor)
|
||||
}
|
||||
|
||||
val classVal = LLVMVariable("classvariable.this", type, pointer = if (type.isPrimitive()) 0 else 1)
|
||||
variableManager.addVariable("this", classVal, 0)
|
||||
@@ -110,6 +115,7 @@ abstract class StructCodegen(val state: TranslationState,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun generateEnumFields() {
|
||||
val enumEntries = classOrObject.declarations.filter { it is KtEnumEntry }
|
||||
|
||||
@@ -121,7 +127,7 @@ abstract class StructCodegen(val state: TranslationState,
|
||||
val field = codeBuilder.getNewVariable(type, scope = LLVMVariableScope())
|
||||
val enumField = enumFields[name]!!
|
||||
|
||||
codeBuilder.defineGlobalVariable(field, codeBuilder.makeStructInitializer(constructorFields, arguments))
|
||||
codeBuilder.defineGlobalVariable(field, codeBuilder.makeStructInitializer(constructorFields[primaryConstructorIndex]!!, arguments))
|
||||
codeBuilder.defineGlobalVariable(LLVMVariable(enumField.label, enumField.type, enumField.kotlinName, enumField.scope, enumField.pointer - 1), "$field")
|
||||
}
|
||||
}
|
||||
@@ -130,24 +136,56 @@ abstract class StructCodegen(val state: TranslationState,
|
||||
codeBuilder.createClass(fullName, fields)
|
||||
}
|
||||
|
||||
private fun generateSecondaryConstructor(secondaryConstructor: KtSecondaryConstructor) {
|
||||
val thisCall = secondaryConstructor.getDelegationCall().calleeExpression
|
||||
val descriptor = state.bindingContext.get(BindingContext.CONSTRUCTOR, secondaryConstructor)
|
||||
|
||||
val argFields = ArrayList<LLVMVariable>()
|
||||
|
||||
val classVal = LLVMVariable("classvariable.this", type, pointer = 1)
|
||||
variableManager.addVariable("this", classVal, 0)
|
||||
|
||||
val secondaryConstructorArguments = descriptor!!.valueParameters.map {
|
||||
LLVMInstanceOfStandardType(it.name.toString(), it.type, state = state)
|
||||
}
|
||||
|
||||
argFields.add(classVal)
|
||||
argFields.addAll(secondaryConstructorArguments)
|
||||
val currentConstructorIndex = LLVMType.mangleFunctionArguments(secondaryConstructorArguments)
|
||||
constructorFields.put(currentConstructorIndex, argFields)
|
||||
codeBuilder.addLLVMCode(LLVMFunctionDescriptor(fullName + currentConstructorIndex, argFields, LLVMVoidType(), arm = state.arm))
|
||||
|
||||
codeBuilder.addStartExpression()
|
||||
|
||||
for (variable in secondaryConstructorArguments) {
|
||||
variableManager.addVariable(variable.label, variable, 2)
|
||||
}
|
||||
|
||||
val blockCodegen = object : BlockCodegen(state, variableManager, codeBuilder) {}
|
||||
val mainConstructorThis = blockCodegen.evaluateConstructorDelegationReferenceExpression(thisCall!!, this, secondaryConstructorArguments, 1) as LLVMVariable
|
||||
variableManager.addVariable("this", mainConstructorThis, 0)
|
||||
|
||||
blockCodegen.evaluateCodeBlock(secondaryConstructor.bodyExpression, scopeDepth = 1)
|
||||
generateReturn(codeBuilder.downLoadArgument(variableManager.get("this")!!, 1) as LLVMVariable)
|
||||
codeBuilder.addAnyReturn(LLVMVoidType())
|
||||
codeBuilder.addEndExpression()
|
||||
}
|
||||
|
||||
private fun generatePrimaryConstructor() {
|
||||
val argFields = ArrayList<LLVMVariable>()
|
||||
val refType = type.makeClone() as LLVMReferenceType
|
||||
refType.addParam("sret")
|
||||
refType.byRef = true
|
||||
|
||||
val classVal = LLVMVariable("classvariable.this", type, pointer = 1)
|
||||
variableManager.addVariable("this", classVal, 0)
|
||||
|
||||
argFields.add(classVal)
|
||||
argFields.addAll(constructorFields)
|
||||
argFields.addAll(constructorFields[primaryConstructorIndex]!!)
|
||||
|
||||
codeBuilder.addLLVMCode(LLVMFunctionDescriptor(fullName, argFields, LLVMVoidType(), arm = state.arm))
|
||||
codeBuilder.addLLVMCode(LLVMFunctionDescriptor(fullName + primaryConstructorIndex, argFields, LLVMVoidType(), arm = state.arm))
|
||||
|
||||
codeBuilder.addStartExpression()
|
||||
generateLoadArguments(classVal)
|
||||
generateAssignments()
|
||||
generateReturn()
|
||||
generateReturn(LLVMVariable("classvariable.this.addr", type, scope = LLVMRegisterScope(), pointer = 1))
|
||||
genClassInitializers()
|
||||
codeBuilder.addAnyReturn(LLVMVoidType())
|
||||
codeBuilder.addEndExpression()
|
||||
@@ -157,7 +195,7 @@ abstract class StructCodegen(val state: TranslationState,
|
||||
val thisVariable = LLVMVariable(thisField.label, thisField.type, thisField.label, LLVMRegisterScope(), pointer = 0)
|
||||
codeBuilder.loadArgument(thisVariable, false)
|
||||
|
||||
constructorFields.forEach {
|
||||
constructorFields[primaryConstructorIndex]!!.forEach {
|
||||
if (it.type !is LLVMReferenceType) {
|
||||
val loadVariable = LLVMVariable(it.label, it.type, it.label, LLVMRegisterScope())
|
||||
codeBuilder.loadArgument(loadVariable)
|
||||
@@ -166,7 +204,7 @@ abstract class StructCodegen(val state: TranslationState,
|
||||
}
|
||||
|
||||
private fun generateAssignments() {
|
||||
constructorFields.forEach {
|
||||
constructorFields[primaryConstructorIndex]!!.forEach {
|
||||
when (it.type) {
|
||||
is LLVMReferenceType -> {
|
||||
val classField = codeBuilder.getNewVariable(it.type, pointer = it.pointer + 1)
|
||||
@@ -200,9 +238,8 @@ abstract class StructCodegen(val state: TranslationState,
|
||||
codeBuilder.addComment("field initilizers ends")
|
||||
}
|
||||
|
||||
private fun generateReturn() {
|
||||
private fun generateReturn(src: LLVMVariable) {
|
||||
val dst = LLVMVariable("classvariable.this", type, scope = LLVMRegisterScope(), pointer = 1)
|
||||
val src = LLVMVariable("classvariable.this.addr", type, scope = LLVMRegisterScope(), pointer = 1)
|
||||
|
||||
val castedDst = codeBuilder.bitcast(dst, LLVMVariable("", LLVMCharType(), pointer = 1))
|
||||
val castedSrc = codeBuilder.bitcast(src, LLVMVariable("", LLVMCharType(), pointer = 1))
|
||||
|
||||
@@ -72,6 +72,31 @@ class LLVMBuilder(val arm: Boolean = false) {
|
||||
else -> throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
fun loadArgumentIfRequired(value: LLVMSingleValue, argument: LLVMVariable): LLVMSingleValue {
|
||||
var result = value
|
||||
|
||||
while (argument.pointer < result.pointer) {
|
||||
result = getNewVariable(argument.type, pointer = result.pointer - 1)
|
||||
loadVariable(result, value as LLVMVariable)
|
||||
}
|
||||
|
||||
when (value.type) {
|
||||
is LLVMStringType -> if (!(value.type as LLVMStringType).isLoaded) {
|
||||
val newVariable = getNewVariable(value.type!!, pointer = result.pointer + 1)
|
||||
allocStackVar(newVariable, asValue = true)
|
||||
copyVariable(result as LLVMVariable, newVariable)
|
||||
|
||||
result = getNewVariable(argument.type, pointer = newVariable.pointer - 1)
|
||||
loadVariable(result, newVariable)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
fun downLoadArgument(value: LLVMSingleValue, pointer: Int): LLVMSingleValue =
|
||||
loadArgumentIfRequired(value, LLVMVariable("", value.type!!, pointer = pointer))
|
||||
|
||||
fun clean() {
|
||||
localCode = StringBuilder()
|
||||
globalCode = StringBuilder()
|
||||
|
||||
@@ -15,16 +15,10 @@ class LLVMReferenceType(val type: String, var prefix: String = "", override var
|
||||
|
||||
override fun toString() = "%$typename"
|
||||
|
||||
private val params = ArrayList<String>()
|
||||
|
||||
val location = ArrayList<String>()
|
||||
|
||||
override fun mangle() = "Ref_$type"
|
||||
|
||||
fun addParam(param: String) {
|
||||
params.add(param)
|
||||
}
|
||||
|
||||
override fun operatorEq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression =
|
||||
LLVMExpression(LLVMBooleanType(), "icmp eq ${firstOp.getType()} $firstOp, ${if (secondOp.type is LLVMNullType) "null" else "$secondOp"}")
|
||||
|
||||
|
||||
@@ -26,8 +26,6 @@ abstract class LLVMType() : Cloneable {
|
||||
open fun operatorDec(firstOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
|
||||
open fun parseArg(inputArg: String) = inputArg
|
||||
|
||||
fun makeClone() = clone()
|
||||
|
||||
open fun convertFrom(source: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
|
||||
|
||||
abstract fun mangle(): String
|
||||
@@ -38,6 +36,12 @@ abstract class LLVMType() : Cloneable {
|
||||
abstract var size: Int
|
||||
abstract val defaultValue: String
|
||||
open fun isPrimitive(): Boolean = false
|
||||
|
||||
companion object {
|
||||
fun mangleFunctionArguments(names: List<LLVMSingleValue>) =
|
||||
"_${names.joinToString(separator = "_", transform = { it.type!!.mangle() })}"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun parseLLVMType(type: String): LLVMType = when (type) {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
secondary_constructor_1_Int(1389) == 1401
|
||||
@@ -0,0 +1,10 @@
|
||||
class secondary_constructor_1_class(var field1: Int) {
|
||||
constructor(field1: Int, field2: Int) : this(field1) {
|
||||
this.field1 = field1 + field2
|
||||
}
|
||||
}
|
||||
|
||||
fun secondary_constructor_1(x: Int): Int {
|
||||
val cls = secondary_constructor_1_class(12, x)
|
||||
return cls.field1
|
||||
}
|
||||
Reference in New Issue
Block a user