translator: safe access tests
This commit is contained in:
@@ -5,7 +5,6 @@ import com.intellij.psi.PsiWhiteSpace
|
|||||||
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||||
import com.intellij.psi.tree.IElementType
|
import com.intellij.psi.tree.IElementType
|
||||||
import org.jetbrains.kotlin.KtNodeTypes
|
import org.jetbrains.kotlin.KtNodeTypes
|
||||||
import org.jetbrains.kotlin.cfg.UnreachableCode
|
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getNextSiblingIgnoringWhitespaceAndComments
|
import org.jetbrains.kotlin.psi.psiUtil.getNextSiblingIgnoringWhitespaceAndComments
|
||||||
@@ -92,6 +91,7 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM
|
|||||||
is KtStringTemplateExpression -> evaluateStringTemplateExpression(expr)
|
is KtStringTemplateExpression -> evaluateStringTemplateExpression(expr)
|
||||||
is KtReturnExpression -> evaluateReturnInstruction(expr.firstChild, scopeDepth)
|
is KtReturnExpression -> evaluateReturnInstruction(expr.firstChild, scopeDepth)
|
||||||
is KtThisExpression -> evaluateThisExpression()
|
is KtThisExpression -> evaluateThisExpression()
|
||||||
|
is KtSafeQualifiedExpression -> evaluateSafeAccessExpression(expr, scopeDepth)
|
||||||
is PsiWhiteSpace -> null
|
is PsiWhiteSpace -> null
|
||||||
is PsiElement -> evaluatePsiElement(expr, scopeDepth)
|
is PsiElement -> evaluatePsiElement(expr, scopeDepth)
|
||||||
null -> null
|
null -> null
|
||||||
@@ -119,11 +119,56 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM
|
|||||||
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? {
|
||||||
|
val receiver = expr.receiverExpression
|
||||||
|
val selector = expr.selectorExpression
|
||||||
|
|
||||||
|
val left = evaluateExpression(receiver, scopeDepth)!!
|
||||||
|
val loadedLeft = codeBuilder.receiveNativeValue(left)
|
||||||
|
val expectedType = LLVMMapStandardType(state.bindingContext.get(BindingContext.EXPECTED_EXPRESSION_TYPE, expr)!!) as LLVMReferenceType
|
||||||
|
|
||||||
|
if (state.classes.containsKey(expectedType.type)) {
|
||||||
|
expectedType.prefix = "class"
|
||||||
|
}
|
||||||
|
|
||||||
|
val result = codeBuilder.getNewVariable(expectedType, pointer = 1)
|
||||||
|
codeBuilder.allocStaticVar(result)
|
||||||
|
result.pointer++
|
||||||
|
|
||||||
|
val condition = left.type!!.operatorEq(loadedLeft, LLVMVariable("", LLVMNullType()))
|
||||||
|
val thenLabel = codeBuilder.getNewLabel(prefix = "safe.access")
|
||||||
|
val elseLabel = codeBuilder.getNewLabel(prefix = "safe.access")
|
||||||
|
val endLabel = codeBuilder.getNewLabel(prefix = "safe.access")
|
||||||
|
|
||||||
|
val conditionResult = codeBuilder.getNewVariable(condition.variableType)
|
||||||
|
codeBuilder.addAssignment(conditionResult, condition)
|
||||||
|
|
||||||
|
codeBuilder.addCondition(conditionResult, thenLabel, elseLabel)
|
||||||
|
codeBuilder.markWithLabel(thenLabel)
|
||||||
|
codeBuilder.storeNull(result)
|
||||||
|
codeBuilder.addUnconditionalJump(endLabel)
|
||||||
|
|
||||||
|
codeBuilder.markWithLabel(elseLabel)
|
||||||
|
val right = evaluateDotBody(receiver, selector!!, scopeDepth)
|
||||||
|
val rightLoaded = codeBuilder.loadAndGetVariable(right as LLVMVariable)
|
||||||
|
codeBuilder.storeVariable(result, rightLoaded)
|
||||||
|
codeBuilder.addUnconditionalJump(endLabel)
|
||||||
|
|
||||||
|
codeBuilder.markWithLabel(endLabel)
|
||||||
|
|
||||||
|
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 receiverName = receiverExpr.text
|
|
||||||
val selectorExpr = expr.selectorExpression!!
|
val selectorExpr = expr.selectorExpression!!
|
||||||
|
|
||||||
|
return evaluateDotBody(receiverExpr, selectorExpr, scopeDepth)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun evaluateDotBody(receiverExpr: KtExpression, selectorExpr: KtExpression, scopeDepth: Int): LLVMSingleValue? {
|
||||||
|
val receiverName = receiverExpr.text
|
||||||
|
|
||||||
var receiver = when (receiverExpr) {
|
var receiver = when (receiverExpr) {
|
||||||
is KtCallExpression,
|
is KtCallExpression,
|
||||||
is KtBinaryExpression -> evaluateExpression(receiverExpr, scopeDepth) as LLVMVariable
|
is KtBinaryExpression -> evaluateExpression(receiverExpr, scopeDepth) as LLVMVariable
|
||||||
@@ -135,7 +180,7 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM
|
|||||||
receiver = codeBuilder.loadAndGetVariable(receiver)
|
receiver = codeBuilder.loadAndGetVariable(receiver)
|
||||||
}
|
}
|
||||||
when (receiver.type) {
|
when (receiver.type) {
|
||||||
is LLVMReferenceType -> return evaluateMemberMethodOrField(receiver, selectorExpr.text, scopeDepth, expr.lastChild)
|
is LLVMReferenceType -> return evaluateMemberMethodOrField(receiver, selectorExpr.text, scopeDepth, selectorExpr)
|
||||||
else -> return evaluateExtensionExpression(receiverExpr, selectorExpr as KtCallExpression, scopeDepth)
|
else -> return evaluateExtensionExpression(receiverExpr, selectorExpr as KtCallExpression, scopeDepth)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -192,7 +237,7 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM
|
|||||||
val field = clazz.fieldsIndex[selectorName]
|
val field = clazz.fieldsIndex[selectorName]
|
||||||
|
|
||||||
if (field != null) {
|
if (field != null) {
|
||||||
val result = codeBuilder.getNewVariable(field.type, 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
|
||||||
}
|
}
|
||||||
@@ -334,8 +379,8 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM
|
|||||||
private fun loadArgumentIfRequired(value: LLVMSingleValue, argument: LLVMVariable): LLVMSingleValue {
|
private fun loadArgumentIfRequired(value: LLVMSingleValue, argument: LLVMVariable): LLVMSingleValue {
|
||||||
var result = value
|
var result = value
|
||||||
|
|
||||||
if (result.pointer > 0 && argument.pointer == 0) {
|
while (argument.pointer < result.pointer) {
|
||||||
result = codeBuilder.getNewVariable(argument.type)
|
result = codeBuilder.getNewVariable(argument.type, pointer = result.pointer - 1)
|
||||||
codeBuilder.loadVariable(result, value as LLVMVariable)
|
codeBuilder.loadVariable(result, value as LLVMVariable)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,7 +476,6 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun executeBinaryExpression(operator: IElementType, referenceName: KtSimpleNameExpression?, left: LLVMSingleValue, right: LLVMSingleValue)
|
private fun executeBinaryExpression(operator: IElementType, referenceName: KtSimpleNameExpression?, left: LLVMSingleValue, right: LLVMSingleValue)
|
||||||
= addPrimitiveBinaryOperation(operator, referenceName, left, right)
|
= addPrimitiveBinaryOperation(operator, referenceName, left, right)
|
||||||
|
|
||||||
@@ -703,7 +747,6 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM
|
|||||||
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.name.toString()
|
val identifier = variable.name.toString()
|
||||||
@@ -754,7 +797,7 @@ 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()
|
||||||
var retVar = evaluateExpression(next, scopeDepth)
|
val retVar = evaluateExpression(next, scopeDepth)
|
||||||
val type = retVar?.type ?: LLVMVoidType()
|
val type = retVar?.type ?: LLVMVoidType()
|
||||||
|
|
||||||
when (type) {
|
when (type) {
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
test1() == 1
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
class Gen(val i: Int)
|
||||||
|
class MyClass(val i: Gen?)
|
||||||
|
|
||||||
|
fun test1(): Int {
|
||||||
|
val x: MyClass? = null
|
||||||
|
val y = MyClass(x?.i)
|
||||||
|
|
||||||
|
if (y == null) {
|
||||||
|
return 0
|
||||||
|
} else {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user