translator: add function extensions

This commit is contained in:
Alexey Stepanov
2016-07-21 19:06:12 +03:00
parent b223b4f9ae
commit 270fab189f
18 changed files with 103 additions and 28 deletions
@@ -68,6 +68,7 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM
is KtIfExpression -> evaluateIfOperator(expr.firstChild as LeafPsiElement, scopeDepth + 1, expr)
is KtStringTemplateExpression -> evaluateStringTemplateExpression(expr)
is KtReturnExpression -> evaluateReturnInstruction(expr.firstChild, scopeDepth)
is KtThisExpression -> evaluateThisExpression(expr, scopeDepth)
is PsiWhiteSpace -> null
is PsiElement -> evaluatePsiElement(expr, scopeDepth)
null -> null
@@ -75,6 +76,10 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM
}
}
private fun evaluateThisExpression(expr: KtThisExpression, scopeDepth: Int): LLVMSingleValue? {
return variableManager.getLLVMvalue("this")
}
fun evaluateStringTemplateExpression(expr: KtStringTemplateExpression): LLVMSingleValue? {
val receiveValue = state.bindingContext.get(BindingContext.COMPILE_TIME_VALUE, expr)
val type = (receiveValue as TypedCompileTimeConstant).type
@@ -87,11 +92,12 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM
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())
return LLVMInstanceOfStandardType(expr.text.substring(2), kotlinType, LLVMVariableScope())
}
private fun evaluateDotExpression(expr: KtDotQualifiedExpression, scopeDepth: Int): LLVMSingleValue? {
val receiverName = expr.receiverExpression.text
val receiverExpr = expr.receiverExpression
val receiverName = receiverExpr.text
val selectorExpr = expr.selectorExpression!!
var receiver = variableManager.getLLVMvalue(receiverName)
@@ -99,13 +105,37 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM
if (receiver.pointer == 2) {
receiver = codeBuilder.loadAndGetVariable(receiver)
}
return evaluateMemberMethodOrField(receiver, selectorExpr.text, scopeDepth, expr.lastChild)
when (receiver.type) {
is LLVMReferenceType -> return evaluateMemberMethodOrField(receiver, selectorExpr.text, scopeDepth, expr.lastChild)
else -> return evaluateExtensionExpression(receiverExpr, selectorExpr as KtCallExpression, scopeDepth)
}
}
val clazz = state.classes[receiverName] ?: return null
val clazz = state.classes[receiverName] ?: return evaluateExtensionExpression(receiverExpr, selectorExpr as KtCallExpression, scopeDepth)
return evaluateClassScopedDotExpression(clazz, selectorExpr, scopeDepth)
}
private fun evaluateExtensionExpression(receiver: KtExpression, selector: KtCallExpression, scopeDepth: Int): LLVMSingleValue? {
val receiverType = state.bindingContext.get(BindingContext.EXPRESSION_TYPE_INFO, receiver)
val standartType = LLVMMapStandardType(receiverType!!.type!!)
val function = selector.firstChild.firstChild.text
val names = parseArgList(selector, scopeDepth)
val extensionCodegen = state.extensionFunctions[standartType.toString()]!![function]!!
val receiverExpression = evaluateExpression(receiver, scopeDepth + 1)!!
val typeThisArgument = when (standartType) {
is LLVMReferenceType -> LLVMVariable("type", standartType, pointer = 1)
else -> LLVMVariable("type", standartType, pointer = 0)
}
val args = mutableListOf<LLVMSingleValue>(loadArgumentIfRequired(receiverExpression, typeThisArgument))
args.addAll(loadArgsIfRequired(names, extensionCodegen.args))
return evaluateFunctionCallExpression(LLVMVariable(extensionCodegen.fullName, extensionCodegen.returnType!!.type, scope = LLVMVariableScope()), args)
}
private fun evaluateClassScopedDotExpression(clazz: ClassCodegen, selector: KtExpression, scopeDepth: Int): LLVMSingleValue? = when (selector) {
is KtCallExpression -> evaluateCallExpression(selector, scopeDepth, clazz)
@@ -266,16 +296,21 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM
return null
}
private fun loadArgsIfRequired(names: List<LLVMSingleValue>, args: List<LLVMVariable>) = names.mapIndexed(fun(i: Int, value: LLVMSingleValue): LLVMSingleValue {
private fun loadArgumentIfRequired(value: LLVMSingleValue, argument: LLVMVariable): LLVMSingleValue {
var result = value
if (result.pointer > 0 && args[i].pointer == 0) {
result = codeBuilder.getNewVariable(args[i].type)
if (result.pointer > 0 && argument.pointer == 0) {
result = codeBuilder.getNewVariable(argument.type)
codeBuilder.loadVariable(result, value as LLVMVariable)
}
return result
}).toList()
}
private fun loadArgsIfRequired(names: List<LLVMSingleValue>, args: List<LLVMVariable>) =
names.mapIndexed(fun(i: Int, value: LLVMSingleValue): LLVMSingleValue {
return loadArgumentIfRequired(value, args[i])
}).toList()
private fun evaluateConstructorCallExpression(function: LLVMVariable, names: List<LLVMSingleValue>): LLVMSingleValue? {
val store = codeBuilder.getNewVariable(function.type)
@@ -457,7 +492,7 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM
codeBuilder.addComment("start when expression")
val whenExpression = expr.subjectExpression
val kotlinType = state.bindingContext.get(BindingContext.EXPRESSION_TYPE_INFO, expr)!!.type!!
val expressionType = LLVMMapStandardType("type", kotlinType, LLVMVariableScope()).type
val expressionType = LLVMMapStandardType(kotlinType)
val targetExpression = evaluateExpression(whenExpression, scopeDepth + 1)!!
@@ -524,7 +559,7 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM
private fun executeIfExpression(condition: KtBinaryExpression, thenExpression: PsiElement, elseExpression: PsiElement?, ifExpression: KtIfExpression, scopeDepth: Int): LLVMVariable? {
val conditionResult: LLVMVariable = evaluateBinaryExpression(condition, scopeDepth + 1)
val kotlinType = state.bindingContext.get(BindingContext.EXPRESSION_TYPE_INFO, ifExpression)!!.type!!
val expressionType = LLVMMapStandardType("type", kotlinType, LLVMVariableScope()).type
val expressionType = LLVMInstanceOfStandardType("type", kotlinType, LLVMVariableScope()).type
val resultVariable = codeBuilder.getNewVariable(expressionType, pointer = 1)
codeBuilder.allocStackPointedVarAsValue(resultVariable)
val thenLabel = codeBuilder.getNewLabel(prefix = "if")
@@ -586,7 +621,7 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM
}
is LLVMConstant -> {
if (assignExpression.type is LLVMNullType) {
val reference = LLVMMapStandardType(identifier, variable.type)
val reference = LLVMInstanceOfStandardType(identifier, variable.type)
if (state.classes.containsKey(variable.type.toString().dropLast(1))) {
(reference.type as LLVMReferenceType).prefix = "class"
}
@@ -1,6 +1,7 @@
package org.kotlinnative.translator
import org.jetbrains.kotlin.psi.*
import org.kotlinnative.translator.debug.printFile
class FileTranslator(val state: TranslationState, val file: KtFile) {
@@ -2,6 +2,7 @@ package org.kotlinnative.translator
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.psiUtil.getNextSiblingIgnoringWhitespaceAndComments
import org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration
import org.jetbrains.kotlin.resolve.BindingContext
import org.kotlinnative.translator.llvm.*
import org.kotlinnative.translator.llvm.types.LLVMFunctionType
@@ -20,15 +21,18 @@ class FunctionCodegen(override val state: TranslationState,
var name = function.fqName.toString()
var args = LinkedList<LLVMVariable>()
val isExtensionDeclaration = function.isExtensionDeclaration()
var functionNamePrefix = ""
val fullName: String
get() = functionNamePrefix + name
init {
val descriptor = state.bindingContext.get(BindingContext.FUNCTION, function)!!
args.addAll(descriptor.valueParameters.map {
LLVMMapStandardType(it.name.toString(), it.type)
LLVMInstanceOfStandardType(it.name.toString(), it.type)
})
returnType = LLVMMapStandardType("instance", descriptor.returnType!!)
returnType = LLVMInstanceOfStandardType("instance", descriptor.returnType!!)
val retType = returnType!!.type
when (retType) {
is LLVMReferenceType -> {
@@ -88,13 +92,28 @@ class FunctionCodegen(override val state: TranslationState,
actualArgs.add(returnType!!)
}
if (isExtensionDeclaration) {
val receiverParameter = state.bindingContext.get(BindingContext.FUNCTION, function)!!.extensionReceiverParameter!!
val receiverType = receiverParameter.type
val translatorType = LLVMMapStandardType(receiverType)
val extensionFunctionsOfThisType = state.extensionFunctions.getOrDefault(translatorType, HashMap())
extensionFunctionsOfThisType.put(name, this)
state.extensionFunctions.put(translatorType.toString(), extensionFunctionsOfThisType)
val classVal = LLVMVariable("classvariable.this", translatorType, pointer = 0)
variableManager.addVariable("this", classVal, 0)
actualArgs.add(classVal)
functionNamePrefix += translatorType.toString() + "."
}
if (this_type != null) {
actualArgs.add(this_type)
}
actualArgs.addAll(args)
codeBuilder.addLLVMCode(LLVMFunctionDescriptor(function.fqName.toString(), actualArgs, actualReturnType, external, state.arm))
codeBuilder.addLLVMCode(LLVMFunctionDescriptor(fullName, actualArgs, actualReturnType, external, state.arm))
return external
}
@@ -1,8 +1,5 @@
package org.kotlinnative.translator
import org.jetbrains.kotlin.psi.*
import org.kotlinnative.translator.llvm.LLVMBuilder
class ProjectTranslator(val state: TranslationState) {
private var codeBuilder = state.codeBuilder
@@ -25,7 +22,11 @@ class ProjectTranslator(val state: TranslationState) {
clazz.generate()
}
for (function in state.functions.values) {
for (function in state.functions.values.filter { it.isExtensionDeclaration }) {
function.generate()
}
for (function in state.functions.values.filter { !it.isExtensionDeclaration }) {
function.generate()
}
}
@@ -4,7 +4,7 @@ import org.jetbrains.kotlin.js.descriptorUtils.nameIfStandardType
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.resolve.BindingContext
import org.kotlinnative.translator.llvm.LLVMBuilder
import org.kotlinnative.translator.llvm.LLVMMapStandardType
import org.kotlinnative.translator.llvm.LLVMInstanceOfStandardType
import org.kotlinnative.translator.llvm.LLVMVariable
import org.kotlinnative.translator.llvm.LLVMVariableScope
@@ -17,7 +17,7 @@ class PropertyCodegen(val state: TranslationState, val variableManager: Variable
val kotlinType = varInfo.type
val value = varInfo.value
if (kotlinType.nameIfStandardType != null) {
val variableType = LLVMMapStandardType(property.name ?: return, kotlinType).type
val variableType = LLVMInstanceOfStandardType(property.name ?: return, kotlinType).type
val variable = LLVMVariable(property.name.toString(), variableType, property.name.toString(), LLVMVariableScope(), pointer = 1)
variableManager.addGlobalVariable(property.name.toString(), variable)
codeBuilder.declareGlobalVariable(variable, variableType.parseArg(value.toString()))
@@ -33,7 +33,7 @@ abstract class StructCodegen(open val state: TranslationState,
var methods = HashMap<String, FunctionCodegen>()
abstract val structName: String
val fullName: String
get() = "${if (type.location.size > 0) "${type.location.joinToString(".")}." else ""}$structName"
get() = "${if (type.location.size > 0) "${type.location.joinToString(".")}." else ""}$structName"
fun generate(declarations: List<KtDeclaration>) {
@@ -49,7 +49,7 @@ abstract class StructCodegen(open val state: TranslationState,
}
}
val classVal = LLVMVariable("classvariable.this", type, pointer = 1)
val classVal = LLVMVariable("classvariable.this", type, pointer = if (type.isPrimitive()) 0 else 1)
variableManager.addVariable("this", classVal, 0)
for (function in methods.values) {
@@ -156,7 +156,7 @@ abstract class StructCodegen(open val state: TranslationState,
protected fun resolveType(field: KtNamedDeclaration, ktType: KotlinType): LLVMClassVariable {
val annotations = parseFieldAnnotations(field)
val result = LLVMMapStandardType(field.name!!, ktType, LLVMRegisterScope())
val result = LLVMInstanceOfStandardType(field.name!!, ktType, LLVMRegisterScope())
if (result.type is LLVMReferenceType) {
val type = result.type as LLVMReferenceType
@@ -30,6 +30,7 @@ class TranslationState(val environment: KotlinCoreEnvironment, val bindingContex
var objects = HashMap<String, ObjectCodegen>()
var properties = HashMap<String, PropertyCodegen>()
val codeBuilder = LLVMBuilder(arm)
val extensionFunctions = HashMap<String, HashMap<String, FunctionCodegen>>()
}
fun parseAndAnalyze(sources: List<String>, disposer: Disposable, arm: Boolean = false): TranslationState {
@@ -12,7 +12,7 @@ fun LLVMFunctionDescriptor(name: String, argTypes: List<LLVMVariable>?, returnTy
"${s.getType()} ${if (s.type is LLVMReferenceType && !(s.type as LLVMReferenceType).byRef) "byval" else ""} %${s.label}"
}?.joinToString()}) ${if (arm) "#0" else ""}"
fun LLVMMapStandardType(name: String, type: KotlinType, scope: LLVMScope = LLVMRegisterScope()): LLVMVariable = when {
fun LLVMInstanceOfStandardType(name: String, type: KotlinType, scope: LLVMScope = LLVMRegisterScope()): LLVMVariable = when {
type.isFunctionTypeOrSubtype -> LLVMVariable(name, LLVMFunctionType(type), name, scope, pointer = 1)
type.toString() == "Int" -> LLVMVariable(name, LLVMIntType(), name, scope)
type.toString() == "Double" -> LLVMVariable(name, LLVMDoubleType(), name, scope)
@@ -22,4 +22,7 @@ fun LLVMMapStandardType(name: String, type: KotlinType, scope: LLVMScope = LLVMR
type.isUnit() -> LLVMVariable("", LLVMVoidType(), name, scope)
type.isMarkedNullable -> LLVMVariable(name, LLVMReferenceType(type.toString().dropLast(1)), name, scope, pointer = 1)
else -> LLVMVariable(name, LLVMReferenceType(type.toString()), name, scope, pointer = 1)
}
}
fun LLVMMapStandardType(type: KotlinType): LLVMType =
LLVMInstanceOfStandardType("type", type, LLVMRegisterScope()).type
@@ -45,6 +45,7 @@ class LLVMBooleanType() : LLVMType() {
override val align = 4
override var size: Int = 1
override val defaultValue = "0"
override fun isPrimitive() = true
override fun toString() = "i1"
}
@@ -26,4 +26,5 @@ class LLVMByteType() : LLVMType() {
override var size: Int = 1
override fun toString(): String = "i8"
override val defaultValue = "0"
override fun isPrimitive() = true
}
@@ -26,4 +26,5 @@ class LLVMCharType() : LLVMType() {
override var size: Int = 1
override fun toString(): String = "i8"
override val defaultValue = "0"
override fun isPrimitive() = true
}
@@ -22,4 +22,5 @@ class LLVMDoubleType() : LLVMType() {
override var size: Int = 8
override fun toString() = "double"
override val defaultValue = "0.0"
override fun isPrimitive() = true
}
@@ -1,7 +1,7 @@
package org.kotlinnative.translator.llvm.types
import org.jetbrains.kotlin.types.KotlinType
import org.kotlinnative.translator.llvm.LLVMMapStandardType
import org.kotlinnative.translator.llvm.LLVMInstanceOfStandardType
import org.kotlinnative.translator.llvm.LLVMVariable
class LLVMFunctionType(type: KotlinType) : LLVMType() {
@@ -14,7 +14,7 @@ class LLVMFunctionType(type: KotlinType) : LLVMType() {
val returnType: LLVMVariable
init {
val types = type.arguments.map { LLVMMapStandardType("", it.type) }.toList()
val types = type.arguments.map { LLVMInstanceOfStandardType("", it.type) }.toList()
returnType = types.last()
arguments = types.dropLast(1)
}
@@ -60,4 +60,5 @@ class LLVMIntType() : LLVMType() {
override val defaultValue = "0"
override fun toString() = "i32"
override fun isPrimitive() = true
}
@@ -27,4 +27,5 @@ class LLVMShortType() : LLVMType() {
override val defaultValue = "0"
override fun toString(): String = "i16"
override fun isPrimitive() = true
}
@@ -28,6 +28,7 @@ abstract class LLVMType() : Cloneable {
abstract val align: Int
abstract var size: Int
abstract val defaultValue: String
open fun isPrimitive(): Boolean = false
}
fun parseLLVMType(type: String): LLVMType = when (type) {
@@ -0,0 +1 @@
function_extensions_1(118) == 291
@@ -0,0 +1,7 @@
fun Int.compareTo(x: Int) : Int{
return this + x + 5
}
fun function_extensions_1(x : Int): Int {
return x.compareTo(1) + 39.compareTo(123)
}