translator: refactor fucntion arguments, fix naming, use factory in TranslationState

This commit is contained in:
Alexey Stepanov
2016-09-01 20:39:42 +03:00
parent 391adc0e32
commit f2cc0337cd
18 changed files with 283 additions and 156 deletions
+5 -6
View File
@@ -3,13 +3,13 @@ package kotlin
external fun kotlinclib_boolean_size(): Int external fun kotlinclib_boolean_size(): Int
class BooleanArray(var size: Int) { class BooleanArray(var size: Int) {
val data: Int val dataRawPtr: Int
/** Returns the number of elements in the array. */ /** Returns the number of elements in the array. */
//size: Int //size: Int
init { init {
this.data = malloc_array(kotlinclib_boolean_size() * this.size) this.dataRawPtr = malloc_array(kotlinclib_boolean_size() * this.size)
var index = 0 var index = 0
while (index < this.size) { while (index < this.size) {
set(index, false) set(index, false)
@@ -19,7 +19,7 @@ class BooleanArray(var size: Int) {
/** Returns the array element at the given [index]. This method can be called using the index operator. */ /** Returns the array element at the given [index]. This method can be called using the index operator. */
operator fun get(index: Int): Boolean { operator fun get(index: Int): Boolean {
val res = kotlinclib_get_byte(this.data, index) == 1.toByte() val res = kotlinclib_get_byte(this.dataRawPtr, index) == 1.toByte()
return res return res
} }
@@ -27,13 +27,12 @@ class BooleanArray(var size: Int) {
/** Sets the element at the given [index] to the given [value]. This method can be called using the index operator. */ /** Sets the element at the given [index] to the given [value]. This method can be called using the index operator. */
operator fun set(index: Int, value: Boolean) { operator fun set(index: Int, value: Boolean) {
if (value == true) { if (value == true) {
kotlinclib_set_byte(this.data, index, 1.toByte()) kotlinclib_set_byte(this.dataRawPtr, index, 1.toByte())
} else { } else {
kotlinclib_set_byte(this.data, index, 0.toByte()) kotlinclib_set_byte(this.dataRawPtr, index, 0.toByte())
} }
} }
fun clone(): BooleanArray { fun clone(): BooleanArray {
val newInstance = BooleanArray(this.size) val newInstance = BooleanArray(this.size)
var index = 0 var index = 0
+4 -4
View File
@@ -7,13 +7,13 @@ external fun kotlinclib_byte_size(): Int
class ByteArray(var size: Int) { class ByteArray(var size: Int) {
val data: Int val dataRawPtr: Int
/** Returns the number of elements in the array. */ /** Returns the number of elements in the array. */
//size: Int //size: Int
init { init {
this.data = malloc_array(kotlinclib_byte_size() * this.size) this.dataRawPtr = malloc_array(kotlinclib_byte_size() * this.size)
var index = 0 var index = 0
while (index < this.size) { while (index < this.size) {
@@ -24,13 +24,13 @@ class ByteArray(var size: Int) {
/** Returns the array element at the given [index]. This method can be called using the index operator. */ /** Returns the array element at the given [index]. This method can be called using the index operator. */
operator fun get(index: Int): Byte { operator fun get(index: Int): Byte {
return kotlinclib_get_byte(this.data, index) return kotlinclib_get_byte(this.dataRawPtr, index)
} }
/** Sets the element at the given [index] to the given [value]. This method can be called using the index operator. */ /** Sets the element at the given [index] to the given [value]. This method can be called using the index operator. */
operator fun set(index: Int, value: Byte) { operator fun set(index: Int, value: Byte) {
kotlinclib_set_byte(this.data, index, value) kotlinclib_set_byte(this.dataRawPtr, index, value)
} }
+1
View File
@@ -8,6 +8,7 @@
* *
*/ */
// TODO get this out of native translator stdlib
// TODO: refactor correctness checks into readTag // TODO: refactor correctness checks into readTag
class CodedInputStream(val buffer: ByteArray) { class CodedInputStream(val buffer: ByteArray) {
val inputStream: KotlinInputStream val inputStream: KotlinInputStream
+4 -4
View File
@@ -6,13 +6,13 @@ external fun kotlinclib_int_size(): Int
class IntArray(var size: Int) { class IntArray(var size: Int) {
val data: Int val dataRawPtr: Int
/** Returns the number of elements in the array. */ /** Returns the number of elements in the array. */
//size: Int //size: Int
init { init {
this.data = malloc_array(kotlinclib_int_size() * this.size) this.dataRawPtr = malloc_array(kotlinclib_int_size() * this.size)
var index = 0 var index = 0
while (index < this.size) { while (index < this.size) {
set(index, 0) set(index, 0)
@@ -22,13 +22,13 @@ class IntArray(var size: Int) {
/** Returns the array element at the given [index]. This method can be called using the index operator. */ /** Returns the array element at the given [index]. This method can be called using the index operator. */
operator fun get(index: Int): Int { operator fun get(index: Int): Int {
return kotlinclib_get_int(this.data, index) return kotlinclib_get_int(this.dataRawPtr, index)
} }
/** Sets the element at the given [index] to the given [value]. This method can be called using the index operator. */ /** Sets the element at the given [index] to the given [value]. This method can be called using the index operator. */
operator fun set(index: Int, value: Int) { operator fun set(index: Int, value: Int) {
kotlinclib_set_int(this.data, index, value) kotlinclib_set_int(this.dataRawPtr, index, value)
} }
+4 -4
View File
@@ -6,13 +6,13 @@ external fun kotlinclib_long_size(): Int
class LongArray(var size: Int) { class LongArray(var size: Int) {
val data: Int val dataRawPtr: Int
/** Returns the number of elements in the array. */ /** Returns the number of elements in the array. */
//size: Int //size: Int
init { init {
this.data = malloc_array(kotlinclib_long_size() * this.size) this.dataRawPtr = malloc_array(kotlinclib_long_size() * this.size)
var index = 0 var index = 0
while (index < this.size) { while (index < this.size) {
set(index, 0) set(index, 0)
@@ -22,13 +22,13 @@ class LongArray(var size: Int) {
/** Returns the array element at the given [index]. This method can be called using the index operator. */ /** Returns the array element at the given [index]. This method can be called using the index operator. */
operator fun get(index: Int): Long { operator fun get(index: Int): Long {
return kotlinclib_get_long(this.data, index) return kotlinclib_get_long(this.dataRawPtr, index)
} }
/** Sets the element at the given [index] to the given [value]. This method can be called using the index operator. */ /** Sets the element at the given [index] to the given [value]. This method can be called using the index operator. */
operator fun set(index: Int, value: Long) { operator fun set(index: Int, value: Long) {
kotlinclib_set_long(this.data, index, value) kotlinclib_set_long(this.dataRawPtr, index, value)
} }
+4 -4
View File
@@ -6,13 +6,13 @@ external fun kotlinclib_short_size(): Int
class ShortArray(var size: Int) { class ShortArray(var size: Int) {
val data: Int val dataRawPtr: Int
/** Returns the number of elements in the array. */ /** Returns the number of elements in the array. */
//size: Int //size: Int
init { init {
this.data = malloc_array(kotlinclib_short_size() * this.size) this.dataRawPtr = malloc_array(kotlinclib_short_size() * this.size)
var index = 0 var index = 0
while (index < this.size) { while (index < this.size) {
set(index, 0) set(index, 0)
@@ -22,13 +22,13 @@ class ShortArray(var size: Int) {
/** Returns the array element at the given [index]. This method can be called using the index operator. */ /** Returns the array element at the given [index]. This method can be called using the index operator. */
operator fun get(index: Int): Short { operator fun get(index: Int): Short {
return kotlinclib_get_short(this.data, index) return kotlinclib_get_short(this.dataRawPtr, index)
} }
/** Sets the element at the given [index] to the given [value]. This method can be called using the index operator. */ /** Sets the element at the given [index] to the given [value]. This method can be called using the index operator. */
operator fun set(index: Int, value: Short) { operator fun set(index: Int, value: Short) {
kotlinclib_set_short(this.data, index, value) kotlinclib_set_short(this.dataRawPtr, index, value)
} }
@@ -18,7 +18,7 @@ class DefaultArguments(raw: RawArguments) : Arguments(raw, name = "default") {
val output = optionalParameter( val output = optionalParameter(
name = "output", name = "output",
description = "output file", description = "output file path",
shortNames = listOf('o') shortNames = listOf('o')
) )
@@ -29,6 +29,7 @@ class DefaultArguments(raw: RawArguments) : Arguments(raw, name = "default") {
shortNames = listOf('M') shortNames = listOf('M')
) )
//[TODO] files with [] or another marking
val sources = positionalArguments( val sources = positionalArguments(
name = "sources", name = "sources",
description = "source files", description = "source files",
+7 -4
View File
@@ -1,10 +1,11 @@
import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.Disposer
import com.jshmrsn.karg.parseArguments import com.jshmrsn.karg.parseArguments
import org.kotlinnative.translator.ProjectTranslator import org.kotlinnative.translator.ProjectTranslator
import org.kotlinnative.translator.parseAndAnalyze import org.kotlinnative.translator.TranslationState
import java.io.* import java.io.*
fun main(args: Array<String>) { fun main(args: Array<String>) {
// TODO make good help message (ex. is rm --help)
val arguments = parseArguments(args, ::DefaultArguments) val arguments = parseArguments(args, ::DefaultArguments)
val disposer = Disposer.newDisposable() val disposer = Disposer.newDisposable()
val analyzedFiles = arguments.sources.toMutableList() val analyzedFiles = arguments.sources.toMutableList()
@@ -14,9 +15,11 @@ fun main(args: Array<String>) {
analyzedFiles.addAll(libraryFiles) analyzedFiles.addAll(libraryFiles)
} }
val state = parseAndAnalyze(analyzedFiles, disposer, arguments.mainClass, arguments.arm) val translationState = TranslationState.createTranslationState(analyzedFiles, disposer, arguments.mainClass, arguments.arm)
val files = state.environment.getSourceFiles() val code:String = ProjectTranslator(
val code = ProjectTranslator(files, state).generateCode() translationState.environment.getSourceFiles(),
translationState
).generateCode()
if (arguments.output == null) { if (arguments.output == null) {
println(code) println(code)
@@ -23,18 +23,26 @@ import java.rmi.UnexpectedException
import kotlin.comparisons.compareBy import kotlin.comparisons.compareBy
abstract class BlockCodegen(val state: TranslationState, val variableManager: VariableManager, val codeBuilder: LLVMBuilder) { abstract class BlockCodegen(val state: TranslationState,
val variableManager: VariableManager,
val codeBuilder: LLVMBuilder) {
val topLevelScopeDepth = 2 val topLevelScopeDepth = 2
var returnType: LLVMVariable? = null var returnType: LLVMVariable? = null
var wasReturnOnTopLevel = false var wasReturnOnTopLevel = false
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) codeBuilder.markWithLabel(startLabel)
if (isBlock) { if (isBlock) {
expressionWalker(expr, breakLabel, scopeDepth) expressionWalker(expr, breakLabel, scopeDepth)
} else { } else {
var result = evaluateExpression(expr, scopeDepth) ?: throw UnexpectedException("Can't evaluate expression " + expr!!.text) var result = evaluateExpression(expr, scopeDepth)
?: throw UnexpectedException("Can't evaluate expression " + expr!!.text)
when (result) { when (result) {
is LLVMVariable -> { is LLVMVariable -> {
if (result.type is LLVMReferenceType) { if (result.type is LLVMReferenceType) {
@@ -52,7 +60,8 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
codeBuilder.addUnconditionalJump(nextIterationLabel ?: return) codeBuilder.addUnconditionalJump(nextIterationLabel ?: return)
} }
fun evaluateExpression(expr: PsiElement?, scopeDepth: Int): LLVMSingleValue? = fun evaluateExpression(expr: PsiElement?,
scopeDepth: Int): LLVMSingleValue? =
when (expr) { when (expr) {
is KtBlockExpression -> { is KtBlockExpression -> {
expressionWalker(expr.lBrace, breakLabel = null, scopeDepth = scopeDepth + 1) expressionWalker(expr.lBrace, breakLabel = null, scopeDepth = scopeDepth + 1)
@@ -78,26 +87,41 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
else -> throw UnsupportedOperationException() else -> throw UnsupportedOperationException()
} }
fun evaluateConstructorDelegationReferenceExpression(expr: KtConstructorDelegationReferenceExpression, structCodegen: StructCodegen, constructorArguments: List<LLVMVariable>, scopeDepth: Int): LLVMSingleValue? { fun evaluateConstructorDelegationReferenceExpression(expr: KtConstructorDelegationReferenceExpression,
structCodegen: StructCodegen,
constructorArguments: List<LLVMVariable>,
scopeDepth: Int): LLVMSingleValue? {
val targetCall = state.bindingContext.get(BindingContext.CALL, expr) val targetCall = state.bindingContext.get(BindingContext.CALL, expr)
val names = parseValueArguments(targetCall!!.valueArguments, scopeDepth) val names = parseValueArguments(targetCall!!.valueArguments, scopeDepth)
val args = codeBuilder.loadArgsIfRequired(names, constructorArguments) val args = codeBuilder.loadArgsIfRequired(names, constructorArguments)
return evaluateConstructorCallExpression(LLVMVariable(structCodegen.structName + LLVMType.mangleFunctionArguments(names), structCodegen.type, scope = LLVMVariableScope()), args) return evaluateConstructorCallExpression(
LLVMVariable(structCodegen.structName + LLVMType.mangleFunctionArguments(names),
structCodegen.type,
scope = LLVMVariableScope()),
args)
} }
fun evaluateMemberMethodOrField(receiver: LLVMVariable, selectorName: String, scopeDepth: Int, call: PsiElement? = null): LLVMSingleValue? { fun evaluateMemberMethodOrField(receiver: LLVMVariable,
selectorName: String,
scopeDepth: Int,
call: PsiElement? = null): LLVMSingleValue? {
val type = receiver.type as LLVMReferenceType val type = receiver.type as LLVMReferenceType
val clazz = resolveClassOrObjectLocation(type) ?: throw UnexpectedException(type.toString() + receiver.toString()) val clazz = resolveClassOrObjectLocation(type)
?: throw UnexpectedException(type.toString() + receiver.toString())
val field = clazz.fieldsIndex[selectorName] val field = clazz.fieldsIndex[selectorName]
if (field != null) { if (field != null) {
return evaluateClassField(receiver, field) return evaluateClassField(receiver, field)
} else { } else {
return evaluateMemberMethod(receiver, clazz, scopeDepth, call as? KtCallExpression ?: throw UnexpectedException("$receiver:$selectorName")) return evaluateMemberMethod(receiver, clazz, scopeDepth, call as? KtCallExpression
?: throw UnexpectedException("$receiver:$selectorName"))
} }
} }
fun addPrimitiveBinaryOperation(operator: IElementType, firstOp: LLVMSingleValue, secondOp: LLVMSingleValue, referenceName: KtSimpleNameExpression? = null): LLVMVariable { fun addPrimitiveBinaryOperation(operator: IElementType,
firstOp: LLVMSingleValue,
secondOp: LLVMSingleValue,
referenceName: KtSimpleNameExpression? = null): LLVMVariable {
val firstNativeOp = codeBuilder.receiveNativeValue(firstOp) val firstNativeOp = codeBuilder.receiveNativeValue(firstOp)
val secondNativeOp = codeBuilder.receiveNativeValue(secondOp) val secondNativeOp = codeBuilder.receiveNativeValue(secondOp)
@@ -159,7 +183,9 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
return codeBuilder.saveExpression(llvmExpression) return codeBuilder.saveExpression(llvmExpression)
} }
private fun expressionWalker(expr: PsiElement?, breakLabel: LLVMLabel?, scopeDepth: Int) { private fun expressionWalker(expr: PsiElement?,
breakLabel: LLVMLabel?,
scopeDepth: Int) {
when (expr) { when (expr) {
is KtBlockExpression -> expressionWalker(expr.lBrace, breakLabel, scopeDepth + 1) is KtBlockExpression -> expressionWalker(expr.lBrace, breakLabel, scopeDepth + 1)
is KtProperty -> evaluateValExpression(expr, scopeDepth) is KtProperty -> evaluateValExpression(expr, scopeDepth)
@@ -193,7 +219,11 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
fun evaluateStringTemplateExpression(expr: KtStringTemplateExpression): LLVMSingleValue? { fun evaluateStringTemplateExpression(expr: KtStringTemplateExpression): LLVMSingleValue? {
val receiveValue = state.bindingContext.get(BindingContext.COMPILE_TIME_VALUE, expr) as TypedCompileTimeConstant val receiveValue = state.bindingContext.get(BindingContext.COMPILE_TIME_VALUE, expr) as TypedCompileTimeConstant
val value = receiveValue.getValue(receiveValue.type) ?: return null val value = receiveValue.getValue(receiveValue.type) ?: return null
val variable = variableManager.receiveVariable(".str", LLVMStringType(value.toString().length, isLoaded = false), LLVMVariableScope(), pointer = 0) val variable =
variableManager.receiveVariable(".str",
LLVMStringType(value.toString().length, isLoaded = false),
LLVMVariableScope(),
pointer = 0)
codeBuilder.addStringConstant(variable, value.toString()) codeBuilder.addStringConstant(variable, value.toString())
return variable return variable
@@ -202,10 +232,15 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
private fun evaluateCallableReferenceExpression(expr: KtCallableReferenceExpression): LLVMSingleValue? { private fun evaluateCallableReferenceExpression(expr: KtCallableReferenceExpression): LLVMSingleValue? {
val kotlinType = state.bindingContext.get(BindingContext.EXPRESSION_TYPE_INFO, expr)!!.type!! val kotlinType = state.bindingContext.get(BindingContext.EXPRESSION_TYPE_INFO, expr)!!.type!!
val result = LLVMInstanceOfStandardType(expr.callableReference.text, kotlinType, LLVMVariableScope(), state) val result = LLVMInstanceOfStandardType(expr.callableReference.text, kotlinType, LLVMVariableScope(), state)
return LLVMVariable("${result.label}${(result.type as LLVMFunctionType).mangleArgs()}", result.type, result.kotlinName, result.scope, result.pointer) return LLVMVariable(result.label + (result.type as LLVMFunctionType).mangleArgs(),
result.type,
result.kotlinName,
result.scope,
result.pointer)
} }
private fun evaluateSafeAccessExpression(expr: KtSafeQualifiedExpression, scopeDepth: Int): LLVMSingleValue? { private fun evaluateSafeAccessExpression(expr: KtSafeQualifiedExpression,
scopeDepth: Int): LLVMSingleValue? {
val receiver = expr.receiverExpression val receiver = expr.receiverExpression
val selector = expr.selectorExpression val selector = expr.selectorExpression
@@ -239,14 +274,17 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
return result return result
} }
private fun evaluateDotExpression(expr: KtDotQualifiedExpression, scopeDepth: Int): LLVMSingleValue? { private fun evaluateDotExpression(expr: KtDotQualifiedExpression,
scopeDepth: Int): LLVMSingleValue? {
val receiverExpr = expr.receiverExpression val receiverExpr = expr.receiverExpression
val selectorExpr = expr.selectorExpression!! val selectorExpr = expr.selectorExpression!!
return evaluateDotBody(receiverExpr, selectorExpr, scopeDepth) return evaluateDotBody(receiverExpr, selectorExpr, scopeDepth)
} }
private fun evaluateDotBody(receiverExpr: KtExpression, selectorExpr: KtExpression, scopeDepth: Int): LLVMSingleValue? { private fun evaluateDotBody(receiverExpr: KtExpression,
selectorExpr: KtExpression,
scopeDepth: Int): LLVMSingleValue? {
var receiverName = receiverExpr.text var receiverName = receiverExpr.text
var receiver = when (receiverExpr) { var receiver = when (receiverExpr) {
is KtCallExpression, is KtCallExpression,
@@ -271,14 +309,16 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
else -> variableManager[receiverName] else -> variableManager[receiverName]
} }
val isExtension = selectorExpr is KtCallExpression && selectorExpr.getFunctionResolvedCallWithAssert(state.bindingContext).extensionReceiver != null val isExtension = selectorExpr is KtCallExpression &&
selectorExpr.getFunctionResolvedCallWithAssert(state.bindingContext).extensionReceiver != null
if (isExtension) { if (isExtension) {
return evaluateExtensionExpression(receiverExpr, receiver, selectorExpr as KtCallExpression, scopeDepth) return evaluateExtensionExpression(receiverExpr, receiver, selectorExpr as KtCallExpression, scopeDepth)
} }
val selectorName = when (selectorExpr) { val selectorName = when (selectorExpr) {
is KtNameReferenceExpression -> state.bindingContext.get(BindingContext.REFERENCE_TARGET, selectorExpr)?.fqNameSafe?.asString() ?: selectorExpr.text is KtNameReferenceExpression -> state.bindingContext.get(BindingContext.REFERENCE_TARGET, selectorExpr)
?.fqNameSafe?.asString() ?: selectorExpr.text
else -> selectorExpr.text else -> selectorExpr.text
} }
@@ -298,7 +338,10 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
return evaluateClassScopedDotExpression(clazz, selectorExpr, scopeDepth, receiver) return evaluateClassScopedDotExpression(clazz, selectorExpr, scopeDepth, receiver)
} }
private fun evaluateExtensionExpression(receiver: KtExpression, receiverExpressionArgument: LLVMVariable?, selector: KtCallExpression, scopeDepth: Int): LLVMSingleValue? { private fun evaluateExtensionExpression(receiver: KtExpression,
receiverExpressionArgument: LLVMVariable?,
selector: KtCallExpression,
scopeDepth: Int): LLVMSingleValue? {
val kotlinType = state.bindingContext.get(BindingContext.EXPRESSION_TYPE_INFO, receiver)!!.type!! val kotlinType = state.bindingContext.get(BindingContext.EXPRESSION_TYPE_INFO, receiver)!!.type!!
val receiverType = LLVMMapStandardType(kotlinType, state) val receiverType = LLVMMapStandardType(kotlinType, state)
@@ -326,20 +369,27 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
return evaluateFunctionCallExpression(LLVMVariable(extensionCodegen.fullName, extensionCodegen.returnType!!.type, scope = LLVMVariableScope()), args) return evaluateFunctionCallExpression(LLVMVariable(extensionCodegen.fullName, extensionCodegen.returnType!!.type, scope = LLVMVariableScope()), args)
} }
private fun evaluateClassScopedDotExpression(clazz: StructCodegen, selector: KtExpression, scopeDepth: Int, receiver: LLVMVariable? = null): LLVMSingleValue? = private fun evaluateClassScopedDotExpression(clazz: StructCodegen,
selector: KtExpression,
scopeDepth: Int,
receiver: LLVMVariable? = null): LLVMSingleValue? =
when (selector) { when (selector) {
is KtCallExpression -> evaluateCallExpression(selector, scopeDepth, clazz, caller = receiver) is KtCallExpression -> evaluateCallExpression(selector, scopeDepth, clazz, caller = receiver)
is KtReferenceExpression -> evaluateReferenceExpression(selector, scopeDepth, clazz) is KtReferenceExpression -> evaluateReferenceExpression(selector, scopeDepth, clazz)
else -> throw UnsupportedOperationException() else -> throw UnsupportedOperationException()
} }
private fun evaluateClassField(receiver: LLVMVariable, field: LLVMClassVariable): LLVMVariable { private fun evaluateClassField(receiver: LLVMVariable,
field: LLVMClassVariable): LLVMVariable {
val result = codeBuilder.getNewVariable(field.type, pointer = field.pointer + 1) val result = codeBuilder.getNewVariable(field.type, pointer = field.pointer + 1)
codeBuilder.loadClassField(result, receiver, field.offset) codeBuilder.loadClassField(result, receiver, field.offset)
return result return result
} }
private fun evaluateMemberMethod(receiver: LLVMVariable, clazz: StructCodegen, scopeDepth: Int, call: KtCallExpression): LLVMSingleValue? { private fun evaluateMemberMethod(receiver: LLVMVariable,
clazz: StructCodegen,
scopeDepth: Int,
call: KtCallExpression): LLVMSingleValue? {
val resolvedCall = call.getCall(state.bindingContext)!!.getResolvedCallWithAssert(state.bindingContext) val resolvedCall = call.getCall(state.bindingContext)!!.getResolvedCallWithAssert(state.bindingContext)
val functionDescriptor = resolvedCall.candidateDescriptor val functionDescriptor = resolvedCall.candidateDescriptor
val functionArguments = functionDescriptor.valueParameters.map { it -> it.type }.map { LLVMMapStandardType(it, state) } val functionArguments = functionDescriptor.valueParameters.map { it -> it.type }.map { LLVMMapStandardType(it, state) }
@@ -387,7 +437,8 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
return if (codegen?.structName == type.type) codegen else codegen?.nestedClasses?.get(type.type) return if (codegen?.structName == type.type) codegen else codegen?.nestedClasses?.get(type.type)
} }
private fun evaluateArrayAccessExpression(expr: KtArrayAccessExpression, scope: Int): LLVMSingleValue? { private fun evaluateArrayAccessExpression(expr: KtArrayAccessExpression,
scope: Int): LLVMSingleValue? {
val arrayNameVariable = evaluateExpression(expr.arrayExpression, scope) as LLVMVariable val arrayNameVariable = evaluateExpression(expr.arrayExpression, scope) as LLVMVariable
return when (arrayNameVariable.type) { return when (arrayNameVariable.type) {
is LLVMReferenceType -> { is LLVMReferenceType -> {
@@ -404,7 +455,8 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
val names = parseValueArguments(callMaker.valueArguments, scope) val names = parseValueArguments(callMaker.valueArguments, scope)
val methodName = "$targetClassName.$arrayActionType${LLVMType.mangleFunctionArguments(names)}" val methodName = "$targetClassName.$arrayActionType${LLVMType.mangleFunctionArguments(names)}"
val clazz = resolveClassOrObjectLocation(receiver.type) ?: throw UnexpectedException(receiver.type.toString()) val clazz = resolveClassOrObjectLocation(receiver.type)
?: throw UnexpectedException(receiver.type.toString())
val method = clazz.methods[methodName] ?: throw UnexpectedException(expr.text) val method = clazz.methods[methodName] ?: throw UnexpectedException(expr.text)
val returnType = method.returnType!!.type val returnType = method.returnType!!.type
@@ -429,13 +481,16 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
} }
} }
private fun evaluateReferenceExpression(expr: KtReferenceExpression, scopeDepth: Int, classScope: StructCodegen? = null): LLVMSingleValue? { private fun evaluateReferenceExpression(expr: KtReferenceExpression,
scopeDepth: Int,
classScope: StructCodegen? = null): LLVMSingleValue? {
val targetName = state.bindingContext.get(BindingContext.REFERENCE_TARGET, expr)?.fqNameSafe?.convertToNativeName() val targetName = state.bindingContext.get(BindingContext.REFERENCE_TARGET, expr)?.fqNameSafe?.convertToNativeName()
return when { return when {
expr is KtArrayAccessExpression -> evaluateArrayAccessExpression(expr, scopeDepth + 1) expr is KtArrayAccessExpression -> evaluateArrayAccessExpression(expr, scopeDepth + 1)
isEnumClassField(expr, classScope) -> resolveEnumClassField(expr, classScope) isEnumClassField(expr, classScope) -> resolveEnumClassField(expr, classScope)
(targetName != null) && variableManager.contains(targetName) -> variableManager[targetName] (targetName != null) && variableManager.contains(targetName) -> variableManager[targetName]
((expr is KtNameReferenceExpression) && (classScope != null)) -> evaluateNameReferenceExpression(targetName!!, classScope.parentCodegen!! as ClassCodegen) ((expr is KtNameReferenceExpression) && (classScope != null)) ->
evaluateNameReferenceExpression(targetName!!, classScope.parentCodegen!! as ClassCodegen)
else -> { else -> {
val clazz = classScope ?: resolveCodegen(expr) val clazz = classScope ?: resolveCodegen(expr)
val receiver = if (clazz != null) variableManager[clazz.structName] ?: variableManager["this"] else variableManager["this"] val receiver = if (clazz != null) variableManager[clazz.structName] ?: variableManager["this"] else variableManager["this"]
@@ -445,7 +500,8 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
} }
} }
private fun evaluateNameReferenceExpression(fieldName: String, classScope: ClassCodegen): LLVMSingleValue? { private fun evaluateNameReferenceExpression(fieldName: String,
classScope: ClassCodegen): LLVMSingleValue? {
val companionObject = classScope.companionObjectCodegen!! val companionObject = classScope.companionObjectCodegen!!
val field = companionObject.fieldsIndex[fieldName] ?: return null val field = companionObject.fieldsIndex[fieldName] ?: return null
val receiver = variableManager[companionObject.structName]!! val receiver = variableManager[companionObject.structName]!!
@@ -455,10 +511,12 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
return result return result
} }
private fun resolveEnumClassField(expr: KtReferenceExpression, classScope: StructCodegen?): LLVMSingleValue = private fun resolveEnumClassField(expr: KtReferenceExpression,
classScope: StructCodegen?): LLVMSingleValue =
(classScope ?: resolveCodegen(expr))!!.enumFields[expr.text]!! (classScope ?: resolveCodegen(expr))!!.enumFields[expr.text]!!
private fun isEnumClassField(expr: KtReferenceExpression, classScope: StructCodegen?): Boolean = private fun isEnumClassField(expr: KtReferenceExpression,
classScope: StructCodegen?): Boolean =
(classScope ?: resolveCodegen(expr))?.enumFields?.containsKey(expr.text) ?: false (classScope ?: resolveCodegen(expr))?.enumFields?.containsKey(expr.text) ?: false
private fun resolveCodegen(expr: KtExpression): StructCodegen? { private fun resolveCodegen(expr: KtExpression): StructCodegen? {
@@ -473,7 +531,10 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
private fun resolveCodegenByName(name: String): StructCodegen? = private fun resolveCodegenByName(name: String): StructCodegen? =
resolveClassOrObjectLocation(LLVMReferenceType(name, prefix = "class")) resolveClassOrObjectLocation(LLVMReferenceType(name, prefix = "class"))
private fun evaluateCallExpression(expr: KtCallExpression, scopeDepth: Int, classScope: StructCodegen? = null, caller: LLVMVariable? = null): LLVMSingleValue? { private fun evaluateCallExpression(expr: KtCallExpression,
scopeDepth: Int,
classScope: StructCodegen? = null,
caller: LLVMVariable? = null): LLVMSingleValue? {
var names = parseArgList(expr, scopeDepth) var names = parseArgList(expr, scopeDepth)
val targetFunction = state.bindingContext.get(BindingContext.CALL, expr.calleeExpression) val targetFunction = state.bindingContext.get(BindingContext.CALL, expr.calleeExpression)
var resolvedCall = state.bindingContext.get(BindingContext.RESOLVED_CALL, targetFunction) var resolvedCall = state.bindingContext.get(BindingContext.RESOLVED_CALL, targetFunction)
@@ -537,7 +598,8 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
return resolveCodegenByName(name) return resolveCodegenByName(name)
} }
private fun evaluateFunctionCallExpression(function: LLVMVariable, names: List<LLVMSingleValue>): LLVMSingleValue? { private fun evaluateFunctionCallExpression(function: LLVMVariable,
names: List<LLVMSingleValue>): LLVMSingleValue? {
val returnType = function.type val returnType = function.type
when (returnType) { when (returnType) {
is LLVMVoidType -> { is LLVMVoidType -> {
@@ -569,7 +631,8 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
} }
} }
private fun evaluateConstructorCallExpression(function: LLVMVariable, names: List<LLVMSingleValue>): LLVMSingleValue? { private fun evaluateConstructorCallExpression(function: LLVMVariable,
names: List<LLVMSingleValue>): LLVMSingleValue? {
val store = codeBuilder.getNewVariable(function.type, pointer = 1) val store = codeBuilder.getNewVariable(function.type, pointer = 1)
codeBuilder.allocStaticVar(store, pointer = true) codeBuilder.allocStaticVar(store, pointer = true)
@@ -589,7 +652,8 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
return result return result
} }
private fun parseArgList(expr: KtCallExpression, scopeDepth: Int): List<LLVMSingleValue> = private fun parseArgList(expr: KtCallExpression,
scopeDepth: Int): List<LLVMSingleValue> =
parseValueArguments(expr.getValueArgumentsInParentheses(), scopeDepth) parseValueArguments(expr.getValueArgumentsInParentheses(), scopeDepth)
private fun parseValueArguments(args: List<ValueArgument>, scopeDepth: Int): List<LLVMSingleValue> = private fun parseValueArguments(args: List<ValueArgument>, scopeDepth: Int): List<LLVMSingleValue> =
@@ -604,7 +668,8 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
} }
}).toList() }).toList()
private fun evaluateBinaryExpression(expr: KtBinaryExpression, scopeDepth: Int): LLVMVariable? { private fun evaluateBinaryExpression(expr: KtBinaryExpression,
scopeDepth: Int): LLVMVariable? {
val operator = expr.operationToken val operator = expr.operationToken
if (operator == KtTokens.ELVIS) { if (operator == KtTokens.ELVIS) {
@@ -626,21 +691,24 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
return addPrimitiveBinaryOperation(operator, left, right, expr.operationReference) return addPrimitiveBinaryOperation(operator, left, right, expr.operationReference)
} }
private fun evaluatePostfixExpression(expr: KtPostfixExpression, scopeDepth: Int): LLVMSingleValue? { private fun evaluatePostfixExpression(expr: KtPostfixExpression,
scopeDepth: Int): LLVMSingleValue? {
val operator = expr.operationToken val operator = expr.operationToken
val left = evaluateExpression(expr.baseExpression, scopeDepth) val left = evaluateExpression(expr.baseExpression, scopeDepth)
?: throw UnsupportedOperationException("Wrong binary expression: ${expr.text}") ?: throw UnsupportedOperationException("Wrong binary expression: ${expr.text}")
return addPrimitivePostfixOperation(operator, left as LLVMVariable) return addPrimitivePostfixOperation(operator, left as LLVMVariable)
} }
private fun evaluatePrefixExpression(expr: KtPrefixExpression, scopeDepth: Int): LLVMSingleValue? { private fun evaluatePrefixExpression(expr: KtPrefixExpression,
scopeDepth: Int): LLVMSingleValue? {
val operator = expr.operationToken val operator = expr.operationToken
val left = evaluateExpression(expr.baseExpression, scopeDepth) val left = evaluateExpression(expr.baseExpression, scopeDepth)
?: throw UnsupportedOperationException("Wrong binary expression") ?: throw UnsupportedOperationException("Wrong binary expression")
return addPrimitivePrefixOperation(operator, left) return addPrimitivePrefixOperation(operator, left)
} }
private fun addPrimitivePostfixOperation(operator: IElementType?, firstOp: LLVMVariable): LLVMSingleValue? = private fun addPrimitivePostfixOperation(operator: IElementType?,
firstOp: LLVMVariable): LLVMSingleValue? =
when (operator) { when (operator) {
KtTokens.PLUSPLUS, KtTokens.MINUSMINUS -> { KtTokens.PLUSPLUS, KtTokens.MINUSMINUS -> {
val firstNativeOp = codeBuilder.receiveNativeValue(firstOp) val firstNativeOp = codeBuilder.receiveNativeValue(firstOp)
@@ -677,7 +745,8 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
} }
private fun addPrimitivePrefixOperation(operator: IElementType?, firstOp: LLVMSingleValue): LLVMSingleValue? = private fun addPrimitivePrefixOperation(operator: IElementType?,
firstOp: LLVMSingleValue): LLVMSingleValue? =
when (operator) { when (operator) {
KtTokens.MINUS, KtTokens.MINUS,
KtTokens.PLUS -> addPrimitiveBinaryOperation(operator!!, LLVMConstant("0", firstOp.type), firstOp) KtTokens.PLUS -> addPrimitiveBinaryOperation(operator!!, LLVMConstant("0", firstOp.type), firstOp)
@@ -690,7 +759,8 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
} }
private fun evaluateElvisOperator(expr: KtBinaryExpression, scopeDepth: Int): LLVMVariable { private fun evaluateElvisOperator(expr: KtBinaryExpression,
scopeDepth: Int): LLVMVariable {
val left = evaluateExpression(expr.left, scopeDepth) val left = evaluateExpression(expr.left, scopeDepth)
?: throw UnsupportedOperationException("Wrong binary expression") ?: throw UnsupportedOperationException("Wrong binary expression")
val lptr = codeBuilder.loadAndGetVariable(left as LLVMVariable) val lptr = codeBuilder.loadAndGetVariable(left as LLVMVariable)
@@ -717,7 +787,9 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
return left return left
} }
private fun addPrimitiveReferenceOperationByName(operator: String, firstOp: LLVMSingleValue, secondNativeOp: LLVMSingleValue): LLVMExpression { private fun addPrimitiveReferenceOperationByName(operator: String,
firstOp: LLVMSingleValue,
secondNativeOp: LLVMSingleValue): LLVMExpression {
val firstNativeOp = codeBuilder.receiveNativeValue(firstOp) val firstNativeOp = codeBuilder.receiveNativeValue(firstOp)
return when (operator) { return when (operator) {
@@ -768,7 +840,8 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
return LLVMConstant(expressionValue?.toString().orEmpty(), type, pointer = 0) return LLVMConstant(expressionValue?.toString().orEmpty(), type, pointer = 0)
} }
private fun evaluatePsiElement(element: PsiElement, scopeDepth: Int): LLVMSingleValue? = private fun evaluatePsiElement(element: PsiElement,
scopeDepth: Int): LLVMSingleValue? =
when (element) { when (element) {
is LeafPsiElement -> evaluateLeafPsiElement(element, scopeDepth) is LeafPsiElement -> evaluateLeafPsiElement(element, scopeDepth)
is KtConstantExpression -> evaluateConstantExpression(element) is KtConstantExpression -> evaluateConstantExpression(element)
@@ -776,7 +849,8 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
} }
private fun evaluateLeafPsiElement(element: LeafPsiElement, scopeDepth: Int): LLVMVariable? { private fun evaluateLeafPsiElement(element: LeafPsiElement,
scopeDepth: Int): LLVMVariable? {
return when (element.elementType) { return when (element.elementType) {
KtTokens.RETURN_KEYWORD -> evaluateReturnInstruction(element, scopeDepth) KtTokens.RETURN_KEYWORD -> evaluateReturnInstruction(element, scopeDepth)
KtTokens.IF_KEYWORD -> evaluateIfOperator(element.context as KtIfExpression, scopeDepth, isExpression = false) KtTokens.IF_KEYWORD -> evaluateIfOperator(element.context as KtIfExpression, scopeDepth, isExpression = false)
@@ -786,7 +860,8 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
} }
} }
private fun evaluateForOperator(expr: KtForExpression, scopeDepth: Int): LLVMVariable? { private fun evaluateForOperator(expr: KtForExpression,
scopeDepth: Int): LLVMVariable? {
val range = evaluateExpression(expr.loopRange, scopeDepth + 1)!! val range = evaluateExpression(expr.loopRange, scopeDepth + 1)!!
val conditionLabel = codeBuilder.getNewLabel(prefix = "for_condition") val conditionLabel = codeBuilder.getNewLabel(prefix = "for_condition")
val bodyLabel = codeBuilder.getNewLabel(prefix = "for_body") val bodyLabel = codeBuilder.getNewLabel(prefix = "for_body")
@@ -820,13 +895,19 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
addPrimitiveBinaryOperation(KtTokens.EQ, allocVar, loopParameter, null) addPrimitiveBinaryOperation(KtTokens.EQ, allocVar, loopParameter, null)
evaluateCodeBlock(expr.body, null, conditionLabel, exitLabel, scopeDepth + 1) evaluateCodeBlock(expr.body, startLabel = null, nextIterationLabel = conditionLabel, breakLabel = exitLabel, scopeDepth = scopeDepth + 1)
codeBuilder.markWithLabel(exitLabel) codeBuilder.markWithLabel(exitLabel)
return null return null
} }
private fun evaluateWhenItem(item: KtWhenEntry, target: LLVMSingleValue, resultVariable: LLVMVariable, elseLabel: LLVMLabel, endLabel: LLVMLabel, isElse: Boolean, scopeDepth: Int) { private fun evaluateWhenItem(item: KtWhenEntry,
target: LLVMSingleValue,
resultVariable: LLVMVariable,
elseLabel: LLVMLabel,
endLabel: LLVMLabel,
isElse: Boolean,
scopeDepth: Int) {
val successConditionsLabel = codeBuilder.getNewLabel(prefix = "when_condition_success") val successConditionsLabel = codeBuilder.getNewLabel(prefix = "when_condition_success")
var nextLabel = codeBuilder.getNewLabel(prefix = "when_condition_condition") var nextLabel = codeBuilder.getNewLabel(prefix = "when_condition_condition")
@@ -836,7 +917,8 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
codeBuilder.markWithLabel(nextLabel) codeBuilder.markWithLabel(nextLabel)
nextLabel = codeBuilder.getNewLabel(prefix = "when_condition_condition") nextLabel = codeBuilder.getNewLabel(prefix = "when_condition_condition")
val currentConditionExpression = evaluateExpression((condition as KtWhenConditionWithExpression).expression, scopeDepth + 1)!! val currentConditionExpression =
evaluateExpression((condition as KtWhenConditionWithExpression).expression, scopeDepth + 1)!!
val conditionResult = addPrimitiveBinaryOperation(KtTokens.EQEQ, target, currentConditionExpression) val conditionResult = addPrimitiveBinaryOperation(KtTokens.EQEQ, target, currentConditionExpression)
codeBuilder.addCondition(conditionResult, successConditionsLabel, nextLabel) codeBuilder.addCondition(conditionResult, successConditionsLabel, nextLabel)
@@ -856,7 +938,8 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
codeBuilder.addUnconditionalJump(endLabel) codeBuilder.addUnconditionalJump(endLabel)
} }
private fun evaluateWhenExpression(expr: KtWhenExpression, scopeDepth: Int): LLVMVariable? { private fun evaluateWhenExpression(expr: KtWhenExpression,
scopeDepth: Int): LLVMVariable? {
codeBuilder.addComment("start when expression") codeBuilder.addComment("start when expression")
val whenExpression = expr.subjectExpression val whenExpression = expr.subjectExpression
val kotlinType = state.bindingContext.get(BindingContext.EXPRESSION_TYPE_INFO, expr)!!.type!! val kotlinType = state.bindingContext.get(BindingContext.EXPRESSION_TYPE_INFO, expr)!!.type!!
@@ -888,7 +971,8 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
return resultVariable return resultVariable
} }
private fun evaluateWhileOperator(expr: KtWhileExpression, scopeDepth: Int): LLVMVariable? = private fun evaluateWhileOperator(expr: KtWhileExpression,
scopeDepth: Int): LLVMVariable? =
executeWhileBlock(expr.condition!!, expr.body!!, scopeDepth, checkConditionBeforeExecute = true) executeWhileBlock(expr.condition!!, expr.body!!, scopeDepth, checkConditionBeforeExecute = true)
private fun executeWhileBlock(condition: KtExpression, bodyExpression: PsiElement, scopeDepth: Int, checkConditionBeforeExecute: Boolean): LLVMVariable? { private fun executeWhileBlock(condition: KtExpression, bodyExpression: PsiElement, scopeDepth: Int, checkConditionBeforeExecute: Boolean): LLVMVariable? {
@@ -902,13 +986,15 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
conditionResult = codeBuilder.receivePointedArgument(conditionResult, requirePointer = 0) conditionResult = codeBuilder.receivePointedArgument(conditionResult, requirePointer = 0)
codeBuilder.addCondition(conditionResult, bodyLabel, exitLabel) codeBuilder.addCondition(conditionResult, bodyLabel, exitLabel)
evaluateCodeBlock(bodyExpression, bodyLabel, conditionLabel, exitLabel, scopeDepth + 1) evaluateCodeBlock(bodyExpression, startLabel = bodyLabel, nextIterationLabel = conditionLabel, breakLabel = exitLabel, scopeDepth = scopeDepth + 1)
codeBuilder.markWithLabel(exitLabel) codeBuilder.markWithLabel(exitLabel)
return null return null
} }
private fun evaluateIfOperator(element: KtIfExpression, scopeDepth: Int, isExpression: Boolean = true): LLVMVariable? { private fun evaluateIfOperator(element: KtIfExpression,
scopeDepth: Int,
isExpression: Boolean = true): LLVMVariable? {
val conditionResult = evaluateExpression(element.condition, scopeDepth)!! val conditionResult = evaluateExpression(element.condition, scopeDepth)!!
val conditionNativeResult = codeBuilder.receivePointedArgument(conditionResult, requirePointer = 0) val conditionNativeResult = codeBuilder.receivePointedArgument(conditionResult, requirePointer = 0)
@@ -918,7 +1004,11 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
executeIfBlock(conditionNativeResult, element.then!!, element.`else`, scopeDepth + 1) executeIfBlock(conditionNativeResult, element.then!!, element.`else`, scopeDepth + 1)
} }
private fun executeIfExpression(conditionResult: LLVMSingleValue, thenExpression: KtExpression, elseExpression: PsiElement?, ifExpression: KtIfExpression, scopeDepth: Int): LLVMVariable? { private fun executeIfExpression(conditionResult: LLVMSingleValue,
thenExpression: KtExpression,
elseExpression: PsiElement?,
ifExpression: KtIfExpression,
scopeDepth: Int): LLVMVariable? {
val kotlinType = state.bindingContext.get(BindingContext.EXPRESSION_TYPE_INFO, ifExpression)!!.type!! val kotlinType = state.bindingContext.get(BindingContext.EXPRESSION_TYPE_INFO, ifExpression)!!.type!!
val expressionType = LLVMInstanceOfStandardType("type", kotlinType, LLVMVariableScope(), state).type val expressionType = LLVMInstanceOfStandardType("type", kotlinType, LLVMVariableScope(), state).type
val resultVariable = codeBuilder.getNewVariable(expressionType, pointer = 1) val resultVariable = codeBuilder.getNewVariable(expressionType, pointer = 1)
@@ -927,9 +1017,9 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
is LLVMReferenceType -> codeBuilder.allocStaticVar(resultVariable, asValue = true) is LLVMReferenceType -> codeBuilder.allocStaticVar(resultVariable, asValue = true)
else -> codeBuilder.allocStackVar(resultVariable, asValue = true) else -> codeBuilder.allocStackVar(resultVariable, asValue = true)
} }
val thenLabel = codeBuilder.getNewLabel(prefix = "if") val thenLabel = codeBuilder.getNewLabel(prefix = "if_then")
val elseLabel = codeBuilder.getNewLabel(prefix = "if") val elseLabel = codeBuilder.getNewLabel(prefix = "if_else")
val endLabel = codeBuilder.getNewLabel(prefix = "if") val endLabel = codeBuilder.getNewLabel(prefix = "if_end")
codeBuilder.addCondition(conditionResult, thenLabel, elseLabel) codeBuilder.addCondition(conditionResult, thenLabel, elseLabel)
codeBuilder.markWithLabel(thenLabel) codeBuilder.markWithLabel(thenLabel)
@@ -947,23 +1037,27 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
return resultVariable return resultVariable
} }
private fun executeIfBlock(conditionResult: LLVMSingleValue, thenExpression: PsiElement, elseExpression: PsiElement?, scopeDepth: Int): LLVMVariable? { private fun executeIfBlock(conditionResult: LLVMSingleValue,
thenExpression: PsiElement,
elseExpression: PsiElement?,
scopeDepth: Int): LLVMVariable? {
val thenLabel = codeBuilder.getNewLabel(prefix = "if") val thenLabel = codeBuilder.getNewLabel(prefix = "if")
val elseLabel = codeBuilder.getNewLabel(prefix = "if") val elseLabel = codeBuilder.getNewLabel(prefix = "if")
val endLabel = codeBuilder.getNewLabel(prefix = "if") val endLabel = codeBuilder.getNewLabel(prefix = "if")
codeBuilder.addCondition(conditionResult, thenLabel, if (elseExpression != null) elseLabel else endLabel) codeBuilder.addCondition(conditionResult, thenLabel, if (elseExpression != null) elseLabel else endLabel)
evaluateCodeBlock(thenExpression, thenLabel, endLabel, endLabel, scopeDepth + 1) evaluateCodeBlock(thenExpression, startLabel = thenLabel, nextIterationLabel = endLabel, breakLabel = endLabel, scopeDepth = scopeDepth + 1)
if (elseExpression != null) { if (elseExpression != null) {
evaluateCodeBlock(elseExpression, elseLabel, endLabel, endLabel, scopeDepth + 1) evaluateCodeBlock(elseExpression, startLabel = elseLabel, nextIterationLabel = endLabel, breakLabel = endLabel, scopeDepth = scopeDepth + 1)
} }
codeBuilder.markWithLabel(endLabel) codeBuilder.markWithLabel(endLabel)
return null return null
} }
private fun evaluateValExpression(element: KtProperty, scopeDepth: Int): LLVMVariable? { private fun evaluateValExpression(element: KtProperty,
scopeDepth: Int): LLVMVariable? {
val variable = state.bindingContext.get(BindingContext.VARIABLE, element)!! val variable = state.bindingContext.get(BindingContext.VARIABLE, element)!!
val identifier = variable.fqNameSafe.convertToNativeName() val identifier = variable.fqNameSafe.convertToNativeName()
@@ -986,7 +1080,8 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
return null return null
} }
private fun evaluateReturnInstruction(element: PsiElement, scopeDepth: Int): LLVMVariable? { private fun evaluateReturnInstruction(element: PsiElement,
scopeDepth: Int): LLVMVariable? {
val next = element.getNextSiblingIgnoringWhitespaceAndComments() val next = element.getNextSiblingIgnoringWhitespaceAndComments()
var retVar = evaluateExpression(next, scopeDepth) var retVar = evaluateExpression(next, scopeDepth)
val type = retVar?.type ?: LLVMVoidType() val type = retVar?.type ?: LLVMVoidType()
@@ -2,7 +2,8 @@ package org.kotlinnative.translator
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
class ProjectTranslator(val files: List<KtFile>, val state: TranslationState) { class ProjectTranslator(val files: List<KtFile>,
val state: TranslationState) {
private var codeBuilder = state.codeBuilder private var codeBuilder = state.codeBuilder
fun generateCode(): String { fun generateCode(): String {
@@ -9,7 +9,10 @@ import org.kotlinnative.translator.llvm.LLVMVariable
import org.kotlinnative.translator.llvm.LLVMVariableScope import org.kotlinnative.translator.llvm.LLVMVariableScope
class PropertyCodegen(val state: TranslationState, val variableManager: VariableManager, val property: KtProperty, val codeBuilder: LLVMBuilder) { class PropertyCodegen(val state: TranslationState,
val variableManager: VariableManager,
val property: KtProperty,
val codeBuilder: LLVMBuilder) {
fun generate() { fun generate() {
val varInfo = state.bindingContext.get(BindingContext.VARIABLE, property)?.compileTimeInitializer ?: return val varInfo = state.bindingContext.get(BindingContext.VARIABLE, property)?.compileTimeInitializer ?: return
@@ -12,13 +12,17 @@ import org.kotlinnative.translator.llvm.types.LLVMType
import org.kotlinnative.translator.llvm.types.LLVMVoidType import org.kotlinnative.translator.llvm.types.LLVMVoidType
import java.util.* import java.util.*
/*
* TODO make high level description of code generation process
* and structure of generated code.
*/
abstract class StructCodegen(val state: TranslationState, abstract class StructCodegen(val state: TranslationState,
val variableManager: VariableManager, val variableManager: VariableManager,
val classOrObject: KtClassOrObject, val classOrObject: KtClassOrObject,
val codeBuilder: LLVMBuilder, val codeBuilder: LLVMBuilder,
val parentCodegen: StructCodegen? = null) { val parentCodegen: StructCodegen? = null) {
val fields = ArrayList<LLVMVariable>() val fields = ArrayList<LLVMClassVariable>()
val fieldsIndex = HashMap<String, LLVMClassVariable>() val fieldsIndex = HashMap<String, LLVMClassVariable>()
val nestedClasses = HashMap<String, ClassCodegen>() val nestedClasses = HashMap<String, ClassCodegen>()
val enumFields = HashMap<String, LLVMVariable>() val enumFields = HashMap<String, LLVMVariable>()
@@ -208,8 +212,8 @@ abstract class StructCodegen(val state: TranslationState,
private fun generateReturn(src: LLVMVariable) { private fun generateReturn(src: LLVMVariable) {
val dst = LLVMVariable("classvariable.this", type, scope = LLVMRegisterScope(), pointer = 1) val dst = LLVMVariable("classvariable.this", type, scope = LLVMRegisterScope(), pointer = 1)
val castedDst = codeBuilder.bitcast(dst, LLVMVariable("", LLVMCharType(), pointer = 1)) val castedDst = codeBuilder.bitcast(dst, LLVMCharType(), pointer = 1)
val castedSrc = codeBuilder.bitcast(src, LLVMVariable("", LLVMCharType(), pointer = 1)) val castedSrc = codeBuilder.bitcast(src, LLVMCharType(), pointer = 1)
codeBuilder.memcpy(castedDst, castedSrc, size) codeBuilder.memcpy(castedDst, castedSrc, size)
} }
@@ -25,17 +25,14 @@ import org.kotlinnative.translator.llvm.LLVMBuilder
import org.kotlinnative.translator.llvm.LLVMVariable import org.kotlinnative.translator.llvm.LLVMVariable
import java.util.* import java.util.*
class TranslationState(val environment: KotlinCoreEnvironment, val bindingContext: BindingContext, val mainFunction: String, arm: Boolean) {
companion object {
var POINTER_ALIGN = 4
var POINTER_SIZE = 4
}
init {
POINTER_ALIGN = if (arm) 4 else 8
POINTER_SIZE = if (arm) 4 else 8
}
class TranslationState
private constructor
(
val environment: KotlinCoreEnvironment,
val bindingContext: BindingContext,
val mainFunction: String, arm: Boolean
) {
var externalFunctions = HashMap<String, FunctionCodegen>() var externalFunctions = HashMap<String, FunctionCodegen>()
var functions = HashMap<String, FunctionCodegen>() var functions = HashMap<String, FunctionCodegen>()
val globalVariableCollection = HashMap<String, LLVMVariable>() val globalVariableCollection = HashMap<String, LLVMVariable>()
@@ -45,60 +42,71 @@ class TranslationState(val environment: KotlinCoreEnvironment, val bindingContex
val codeBuilder = LLVMBuilder(arm) val codeBuilder = LLVMBuilder(arm)
val extensionFunctions = HashMap<String, HashMap<String, FunctionCodegen>>() val extensionFunctions = HashMap<String, HashMap<String, FunctionCodegen>>()
} init {
POINTER_ALIGN = if (arm) 4 else 8
fun parseAndAnalyze(sources: List<String>, disposer: Disposable, mainFunction: String, arm: Boolean = false): TranslationState { POINTER_SIZE = if (arm) 4 else 8
val configuration = CompilerConfiguration()
val messageCollector = object : MessageCollector {
private var hasError = false
override fun hasErrors(): Boolean = hasError
override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation) {
if (severity.isError) {
System.err.println("[${severity.toString()}]${location.path} ${location.line}:${location.column} $message")
hasError = true
}
}
} }
configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector) companion object {
configuration.put(JVMConfigurationKeys.MODULE_NAME, JvmAbi.DEFAULT_MODULE_NAME) var POINTER_ALIGN = 4
var POINTER_SIZE = 4
configuration.addKotlinSourceRoots(sources) fun createTranslationState(sources: List<String>, disposer: Disposable, mainFunction: String, arm: Boolean = false): TranslationState {
val environment = KotlinCoreEnvironment.createForProduction(disposer, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES) val configuration = CompilerConfiguration()
val bindingContext = analyze(environment)?.bindingContext ?: throw TranslationException("Can't initialize binding context for project") val messageCollector = object : MessageCollector {
private var hasError = false
return TranslationState(environment, bindingContext, mainFunction, arm) override fun hasErrors(): Boolean = hasError
}
fun analyze(environment: KotlinCoreEnvironment): AnalysisResult? { override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation) {
val collector = environment.configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) if (severity.isError) {
System.err.println("[${severity.toString()}]${location.path} ${location.line}:${location.column} $message")
hasError = true
}
}
}
val analyzer = AnalyzerWithCompilerReport(collector) configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
analyzer.analyzeAndReport(environment.getSourceFiles(), object : AnalyzerWithCompilerReport.Analyzer { configuration.put(JVMConfigurationKeys.MODULE_NAME, JvmAbi.DEFAULT_MODULE_NAME)
override fun analyze(): AnalysisResult {
val sharedTrace = CliLightClassGenerationSupport.NoScopeRecordCliBindingTrace()
val moduleContext = TopDownAnalyzerFacadeForJVM.createContextWithSealedModule(environment.project, environment.getModuleName())
return TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegrationWithCustomContext( configuration.addKotlinSourceRoots(sources)
moduleContext,
environment.getSourceFiles(), val environment = KotlinCoreEnvironment.createForProduction(disposer, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
sharedTrace, val bindingContext = analyze(environment)?.bindingContext ?: throw TranslationException("Can't initialize binding context for project")
environment.configuration.get(JVMConfigurationKeys.MODULES),
environment.configuration.get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS), return TranslationState(environment, bindingContext, mainFunction, arm)
JvmPackagePartProvider(environment))
} }
override fun reportEnvironmentErrors() { private fun analyze(environment: KotlinCoreEnvironment): AnalysisResult? {
val files = environment.configuration.jvmClasspathRoots val collector = environment.configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
val runtimes = files.map { it.canonicalFile }.filter { it.name == PathUtil.KOTLIN_JAVA_RUNTIME_JAR && it.exists() }
collector.report(CompilerMessageSeverity.ERROR, runtimes.joinToString { it.path }, CompilerMessageLocation.NO_LOCATION) val analyzer = AnalyzerWithCompilerReport(collector)
System.err.println(runtimes.joinToString { it.toString() }) analyzer.analyzeAndReport(environment.getSourceFiles(), object : AnalyzerWithCompilerReport.Analyzer {
} override fun analyze(): AnalysisResult {
}) val sharedTrace = CliLightClassGenerationSupport.NoScopeRecordCliBindingTrace()
val moduleContext = TopDownAnalyzerFacadeForJVM.createContextWithSealedModule(environment.project, environment.getModuleName())
return TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegrationWithCustomContext(
moduleContext,
environment.getSourceFiles(),
sharedTrace,
environment.configuration.get(JVMConfigurationKeys.MODULES),
environment.configuration.get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS),
JvmPackagePartProvider(environment))
}
override fun reportEnvironmentErrors() {
val files = environment.configuration.jvmClasspathRoots
val runtimes = files.map { it.canonicalFile }.filter { it.name == PathUtil.KOTLIN_JAVA_RUNTIME_JAR && it.exists() }
collector.report(CompilerMessageSeverity.ERROR, runtimes.joinToString { it.path }, CompilerMessageLocation.NO_LOCATION)
System.err.println(runtimes.joinToString { it.toString() })
}
})
return if (analyzer.hasErrors()) null else analyzer.analysisResult
}
}
return if (analyzer.hasErrors()) null else analyzer.analysisResult
} }
@@ -95,16 +95,16 @@ class LLVMBuilder(arm: Boolean = false) {
addLLVMCodeToLocalPlace("$target = bitcast ${allocated.pointedType} $allocated to ${if (asValue) target.type.toString() else target.pointedType}" + if (pointer) "" else "*") addLLVMCodeToLocalPlace("$target = bitcast ${allocated.pointedType} $allocated to ${if (asValue) target.type.toString() else target.pointedType}" + if (pointer) "" else "*")
} }
fun addGlobalInitialize(target: LLVMVariable, fields: ArrayList<LLVMVariable>, initializers: Map<LLVMVariable, String>, classType: LLVMType) { fun addGlobalInitialize(target: LLVMVariable, fields: ArrayList<LLVMClassVariable>, initializers: Map<LLVMVariable, String>, classType: LLVMType) {
val code = "$target = internal global $classType { ${ val code = "$target = internal global $classType { ${
fields.map { it.pointedType + " " + if (initializers.containsKey(it)) initializers[it] else "0" }.joinToString() fields.map { it.pointedType + " " + if (initializers.containsKey(it)) initializers[it] else "0" }.joinToString()
} }, align ${classType.align}" } }, align ${classType.align}"
addLLVMCodeToGlobalPlace(code) addLLVMCodeToGlobalPlace(code)
} }
fun bitcast(src: LLVMVariable, llvmType: LLVMVariable): LLVMVariable { fun bitcast(src: LLVMVariable, llvmType: LLVMType, pointer: Int): LLVMVariable {
val empty = getNewVariable(llvmType.type, pointer = llvmType.pointer) val empty = getNewVariable(llvmType, pointer = pointer)
addLLVMCodeToLocalPlace("$empty = bitcast ${src.pointedType} $src to ${llvmType.pointedType}") addLLVMCodeToLocalPlace("$empty = bitcast ${src.pointedType} $src to ${llvmType.toString() + "*".repeat(pointer)}")
return empty return empty
} }
@@ -2,7 +2,9 @@ package org.kotlinnative.translator.llvm
import org.kotlinnative.translator.llvm.types.LLVMType import org.kotlinnative.translator.llvm.types.LLVMType
class LLVMCall(val returnType: LLVMType, val name: String, val arguments: Collection<LLVMSingleValue>) : LLVMSingleValue(returnType) { class LLVMCall(val returnType: LLVMType,
val name: String,
val arguments: Collection<LLVMSingleValue>) : LLVMSingleValue(returnType) {
override fun toString() = "call $returnType $name(${arguments.joinToString { "${it.pointedType} ${it.toString()}" }})" override fun toString() = "call $returnType $name(${arguments.joinToString { "${it.pointedType} ${it.toString()}" }})"
@@ -2,4 +2,7 @@ package org.kotlinnative.translator.llvm
import org.kotlinnative.translator.llvm.types.LLVMType import org.kotlinnative.translator.llvm.types.LLVMType
class LLVMClassVariable(label: String, type: LLVMType, pointer: Int = 0, var offset: Int = 0) : LLVMVariable(label, type, pointer = pointer) class LLVMClassVariable(label: String,
type: LLVMType,
pointer: Int = 0,
var offset: Int = 0) : LLVMVariable(label, type, pointer = pointer)
@@ -10,13 +10,19 @@ import org.kotlinnative.translator.TranslationState
import org.kotlinnative.translator.llvm.types.* import org.kotlinnative.translator.llvm.types.*
fun LLVMFunctionDescriptor(name: String, argTypes: List<LLVMVariable>?, returnType: LLVMType, declare: Boolean = false) = fun LLVMFunctionDescriptor(name: String,
argTypes: List<LLVMVariable>?,
returnType: LLVMType,
declare: Boolean = false) =
"${if (declare) "declare" else "define weak"} $returnType @$name(${ "${if (declare) "declare" else "define weak"} $returnType @$name(${
argTypes?.mapIndexed { i: Int, s: LLVMVariable -> argTypes?.mapIndexed { i: Int, s: LLVMVariable ->
"${s.pointedType} ${if (s.type is LLVMReferenceType && !s.type.byRef) "byval" else ""} %${s.label}" "${s.pointedType} ${if (s.type is LLVMReferenceType && !s.type.byRef) "byval" else ""} %${s.label}"
}?.joinToString()}) #0" }?.joinToString()}) #0"
fun LLVMInstanceOfStandardType(name: String, type: KotlinType, scope: LLVMScope = LLVMRegisterScope(), state: TranslationState): LLVMVariable { fun LLVMInstanceOfStandardType(name: String,
type: KotlinType,
scope: LLVMScope = LLVMRegisterScope(),
state: TranslationState): LLVMVariable {
val typeName = type.toString().dropLastWhile { it == '?' } val typeName = type.toString().dropLastWhile { it == '?' }
val pointerMark = if (type.isMarkedNullable) 1 else 0 val pointerMark = if (type.isMarkedNullable) 1 else 0
return when { return when {
@@ -43,7 +49,8 @@ fun LLVMInstanceOfStandardType(name: String, type: KotlinType, scope: LLVMScope
} }
} }
fun LLVMMapStandardType(type: KotlinType, state: TranslationState) = fun LLVMMapStandardType(type: KotlinType,
state: TranslationState) =
LLVMInstanceOfStandardType("type", type, LLVMRegisterScope(), state).type LLVMInstanceOfStandardType("type", type, LLVMRegisterScope(), state).type
fun String.addBeforeIfNotEmpty(add: String): String = fun String.addBeforeIfNotEmpty(add: String): String =
@@ -4,7 +4,7 @@ import org.kotlinnative.translator.exceptions.UnimplementedException
import org.kotlinnative.translator.llvm.LLVMExpression import org.kotlinnative.translator.llvm.LLVMExpression
import org.kotlinnative.translator.llvm.LLVMSingleValue import org.kotlinnative.translator.llvm.LLVMSingleValue
abstract class LLVMType() : Cloneable { abstract class LLVMType() {
companion object { companion object {
fun mangleFunctionArguments(names: List<LLVMSingleValue>) = fun mangleFunctionArguments(names: List<LLVMSingleValue>) =