translator: reference reassignment, elvis operator, tests

This commit is contained in:
e5l
2016-07-21 17:22:38 +03:00
parent 3a02c42d50
commit 74a22ed4f9
4 changed files with 59 additions and 39 deletions
@@ -94,8 +94,11 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM
val receiverName = expr.receiverExpression.text val receiverName = expr.receiverExpression.text
val selectorExpr = expr.selectorExpression!! val selectorExpr = expr.selectorExpression!!
val receiver = variableManager.getLLVMvalue(receiverName) var receiver = variableManager.getLLVMvalue(receiverName)
if (receiver != null) { if (receiver != null) {
if (receiver.pointer == 2) {
receiver = codeBuilder.loadAndGetVariable(receiver)
}
return evaluateMemberMethodOrField(receiver, selectorExpr.text, scopeDepth, expr.lastChild) return evaluateMemberMethodOrField(receiver, selectorExpr.text, scopeDepth, expr.lastChild)
} }
@@ -110,7 +113,7 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM
else -> throw UnsupportedOperationException() else -> throw UnsupportedOperationException()
} }
private fun evaluatenameReferenceExpression(expr: KtNameReferenceExpression, scopeDepth: Int, classScope: ClassCodegen? = null): LLVMSingleValue? { private fun evaluateNameReferenceExpression(expr: KtNameReferenceExpression, scopeDepth: Int, classScope: ClassCodegen? = null): LLVMSingleValue? {
val fieldName = state.bindingContext.get(BindingContext.REFERENCE_TARGET, expr)!!.name.toString() val fieldName = state.bindingContext.get(BindingContext.REFERENCE_TARGET, expr)!!.name.toString()
val field = classScope!!.companionFieldsIndex[fieldName] val field = classScope!!.companionFieldsIndex[fieldName]
@@ -175,8 +178,8 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM
private fun evaluateReferenceExpression(expr: KtReferenceExpression, scopeDepth: Int, classScope: ClassCodegen? = null): LLVMSingleValue? = when (expr) { private fun evaluateReferenceExpression(expr: KtReferenceExpression, scopeDepth: Int, classScope: ClassCodegen? = null): LLVMSingleValue? = when (expr) {
is KtArrayAccessExpression -> evaluateArrayAccessExpression(expr, scopeDepth + 1) is KtArrayAccessExpression -> evaluateArrayAccessExpression(expr, scopeDepth + 1)
else -> if ((expr is KtNameReferenceExpression) && (classScope != null)) evaluatenameReferenceExpression(expr, scopeDepth + 1, classScope) else -> if ((expr is KtNameReferenceExpression) && (classScope != null)) evaluateNameReferenceExpression(expr, scopeDepth + 1, classScope)
else variableManager.getLLVMvalue(expr.firstChild.text) else variableManager.getLLVMvalue(expr.firstChild.text)
} }
private fun evaluateCallExpression(expr: KtCallExpression, scopeDepth: Int, classScope: ClassCodegen? = null): LLVMSingleValue? { private fun evaluateCallExpression(expr: KtCallExpression, scopeDepth: Int, classScope: ClassCodegen? = null): LLVMSingleValue? {
@@ -275,12 +278,19 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM
}).toList() }).toList()
private fun evaluateConstructorCallExpression(function: LLVMVariable, names: List<LLVMSingleValue>): LLVMSingleValue? { private fun evaluateConstructorCallExpression(function: LLVMVariable, names: List<LLVMSingleValue>): LLVMSingleValue? {
val store = codeBuilder.getNewVariable(function.type)
codeBuilder.allocStaticVar(store)
store.pointer++
val result = codeBuilder.getNewVariable(function.type) val result = codeBuilder.getNewVariable(function.type)
result.pointer++
codeBuilder.allocStaticVar(result) codeBuilder.allocStaticVar(result)
result.pointer += 1 result.pointer++
codeBuilder.storeVariable(result, store)
val args = ArrayList<LLVMSingleValue>() val args = ArrayList<LLVMSingleValue>()
args.add(result) args.add(store)
args.addAll(names) args.addAll(names)
codeBuilder.addLLVMCode(LLVMCall( codeBuilder.addLLVMCode(LLVMCall(
@@ -316,46 +326,38 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM
return executeBinaryExpression(operator, expr.operationReference, left, right, scopeDepth) return executeBinaryExpression(operator, expr.operationReference, left, right, scopeDepth)
} }
private fun executeBinaryExpression(operator: IElementType, referenceName: KtSimpleNameExpression?, left: LLVMSingleValue, right: LLVMSingleValue, scopeDepth: Int): LLVMVariable { private fun executeBinaryExpression(operator: IElementType, referenceName: KtSimpleNameExpression?, left: LLVMSingleValue, right: LLVMSingleValue, scopeDepth: Int)
val result = addPrimitiveBinaryOperation(operator, referenceName, left, right) = addPrimitiveBinaryOperation(operator, referenceName, left, right)
if (left.type is LLVMReferenceType && left.pointer > 0 && right.pointer > 0) {
variableManager.addVariable((left as LLVMVariable).kotlinName!!, result, scopeDepth)
}
return result
}
private fun evaluateElvisOperator(expr: KtBinaryExpression, scopeDepth: Int): LLVMVariable { private fun evaluateElvisOperator(expr: KtBinaryExpression, scopeDepth: Int): LLVMVariable {
val left = evaluateExpression(expr.firstChild, scopeDepth) ?: throw UnsupportedOperationException("Wrong binary exception") val left = evaluateExpression(expr.firstChild, scopeDepth) ?: throw UnsupportedOperationException("Wrong binary exception")
val condition = left.type!!.operatorEq(left, LLVMVariable("", LLVMNullType())) val lptr = codeBuilder.loadAndGetVariable(left as LLVMVariable)
val condition = lptr.type.operatorEq(lptr, LLVMVariable("", LLVMNullType()))
val conditionResult = codeBuilder.getNewVariable(condition.variableType) val conditionResult = codeBuilder.getNewVariable(condition.variableType)
codeBuilder.addAssignment(conditionResult, condition) codeBuilder.addAssignment(conditionResult, condition)
val elvisResult = codeBuilder.getNewVariable(left.type!!, pointer = left.pointer)
codeBuilder.allocStackVar(elvisResult)
elvisResult.pointer++
val thenLabel = codeBuilder.getNewLabel(prefix = "elvis") val thenLabel = codeBuilder.getNewLabel(prefix = "elvis")
val elseLabel = codeBuilder.getNewLabel(prefix = "elvis") val elseLabel = codeBuilder.getNewLabel(prefix = "elvis")
val endLabel = codeBuilder.getNewLabel(prefix = "elvis") val endLabel = codeBuilder.getNewLabel(prefix = "elvis")
codeBuilder.addCondition(conditionResult, thenLabel, elseLabel) codeBuilder.addCondition(conditionResult, elseLabel, thenLabel)
codeBuilder.markWithLabel(thenLabel) codeBuilder.markWithLabel(thenLabel)
codeBuilder.storeVariable(elvisResult, left)
codeBuilder.addUnconditionalJump(endLabel) codeBuilder.addUnconditionalJump(endLabel)
codeBuilder.markWithLabel(elseLabel) codeBuilder.markWithLabel(elseLabel)
val right = evaluateExpression(expr.lastChild, scopeDepth + 1) var right = evaluateExpression(expr.lastChild, scopeDepth + 1)
if (right != null) { if (right != null) {
codeBuilder.storeVariable(elvisResult, right) right = codeBuilder.loadAndGetVariable(right as LLVMVariable)
codeBuilder.storeVariable(left, right)
} }
codeBuilder.addUnconditionalJump(endLabel) codeBuilder.addUnconditionalJump(endLabel)
codeBuilder.markWithLabel(endLabel) codeBuilder.markWithLabel(endLabel)
return elvisResult return left
} }
private fun addPrimitiveBinaryOperation(operator: IElementType, referenceName: KtSimpleNameExpression?, firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMVariable { private fun addPrimitiveBinaryOperation(operator: IElementType, referenceName: KtSimpleNameExpression?, firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMVariable {
@@ -371,7 +373,7 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM
KtTokens.GTEQ -> firstOp.type!!.operatorGeq(firstNativeOp, secondNativeOp) KtTokens.GTEQ -> firstOp.type!!.operatorGeq(firstNativeOp, secondNativeOp)
KtTokens.EQEQ -> KtTokens.EQEQ ->
if (firstOp.type is LLVMReferenceType) if (firstOp.type is LLVMReferenceType)
firstOp.type!!.operatorEq(firstOp, secondOp) firstOp.type!!.operatorEq(firstNativeOp, secondOp)
else else
firstOp.type!!.operatorEq(firstNativeOp, secondNativeOp) firstOp.type!!.operatorEq(firstNativeOp, secondNativeOp)
KtTokens.EXCLEQ -> firstOp.type!!.operatorNeq(firstNativeOp, secondNativeOp) KtTokens.EXCLEQ -> firstOp.type!!.operatorNeq(firstNativeOp, secondNativeOp)
@@ -385,10 +387,6 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM
return result return result
} }
if (firstOp.type is LLVMReferenceType && firstOp.pointer > 0 && secondOp.pointer > 0) {
return secondOp as LLVMVariable
}
val result = firstOp as LLVMVariable val result = firstOp as LLVMVariable
codeBuilder.storeVariable(result, secondNativeOp) codeBuilder.storeVariable(result, secondNativeOp)
return result return result
@@ -564,10 +562,6 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM
return null return null
} }
private fun copyVariable(from: LLVMVariable, to: LLVMVariable) = when (from.type) {
is LLVMStringType -> codeBuilder.storeString(to, from, 0)
else -> codeBuilder.copyVariableValue(to, from)
}
private fun evaluateValExpression(element: KtProperty, scopeDepth: Int): LLVMVariable? { private fun evaluateValExpression(element: KtProperty, scopeDepth: Int): LLVMVariable? {
val variable = state.bindingContext.get(BindingContext.VARIABLE, element)!! val variable = state.bindingContext.get(BindingContext.VARIABLE, element)!!
@@ -584,7 +578,7 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM
allocVar.kotlinName = identifier allocVar.kotlinName = identifier
variableManager.addVariable(identifier, allocVar, scopeDepth) variableManager.addVariable(identifier, allocVar, scopeDepth)
copyVariable(assignExpression, allocVar) codeBuilder.copyVariable(assignExpression, allocVar)
} else { } else {
assignExpression.kotlinName = identifier assignExpression.kotlinName = identifier
variableManager.addVariable(identifier, assignExpression, scopeDepth) variableManager.addVariable(identifier, assignExpression, scopeDepth)
@@ -601,9 +595,8 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM
reference.pointer += 1 reference.pointer += 1
codeBuilder.storeNull(reference) codeBuilder.storeNull(reference)
val result = codeBuilder.loadAndGetVariable(reference)
variableManager.addVariable(identifier, result, scopeDepth) variableManager.addVariable(identifier, reference, scopeDepth)
return null return null
} }
@@ -620,12 +613,16 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM
private fun evaluateReturnInstruction(element: PsiElement, scopeDepth: Int): LLVMVariable? { private fun evaluateReturnInstruction(element: PsiElement, scopeDepth: Int): LLVMVariable? {
val next = element.getNextSiblingIgnoringWhitespaceAndComments() val next = element.getNextSiblingIgnoringWhitespaceAndComments()
val retVar = evaluateExpression(next, scopeDepth) var retVar = evaluateExpression(next, scopeDepth)
val type = retVar?.type ?: LLVMVoidType() val type = retVar?.type ?: LLVMVoidType()
when (type) { when (type) {
is LLVMReferenceType -> { is LLVMReferenceType -> {
codeBuilder.storeVariable(returnType!!, retVar!!) if (retVar!!.pointer == 2) {
retVar = codeBuilder.loadAndGetVariable(retVar as LLVMVariable)
}
codeBuilder.storeVariable(returnType!!, retVar)
codeBuilder.addAnyReturn(LLVMVoidType()) codeBuilder.addAnyReturn(LLVMVoidType())
} }
is LLVMVoidType -> { is LLVMVoidType -> {
@@ -147,6 +147,11 @@ class LLVMBuilder(val arm: Boolean) {
localCode.appendln("store ${target.type} $from, ${target.getType()} $target, align ${from.type.align}") localCode.appendln("store ${target.type} $from, ${target.getType()} $target, align ${from.type.align}")
} }
fun copyVariable(from: LLVMVariable, to: LLVMVariable) = when (from.type) {
is LLVMStringType -> storeString(to, from, 0)
else -> copyVariableValue(to, from)
}
fun loadArgument(llvmVariable: LLVMVariable, store: Boolean = true): LLVMVariable { fun loadArgument(llvmVariable: LLVMVariable, store: Boolean = true): LLVMVariable {
val allocVar = LLVMVariable("${llvmVariable.label}.addr", llvmVariable.type, llvmVariable.kotlinName, LLVMRegisterScope(), pointer = llvmVariable.pointer + 1) val allocVar = LLVMVariable("${llvmVariable.label}.addr", llvmVariable.type, llvmVariable.kotlinName, LLVMRegisterScope(), pointer = llvmVariable.pointer + 1)
addVariableByRef(allocVar, llvmVariable, store) addVariableByRef(allocVar, llvmVariable, store)
@@ -0,0 +1,2 @@
elvis_test_1(0) == 0
elvis_test_1(2) == 1
@@ -0,0 +1,16 @@
class MyClass(val i: Int)
fun elvis_test_1(x: Int): Int {
var z: MyClass? = null
if (x > 1) {
z = MyClass(1)
} else {
}
val y = z ?: return 0
return 1
}