diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt index e6c600d3e76..f75d118beac 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.callUtil.getType import org.jetbrains.kotlin.resolve.calls.callUtil.getValueArgumentsInParentheses import org.jetbrains.kotlin.resolve.constants.TypedCompileTimeConstant +import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.kotlinnative.translator.llvm.* import org.kotlinnative.translator.llvm.types.* import java.util.* @@ -172,7 +173,7 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM var receiver = when (receiverExpr) { is KtCallExpression, is KtBinaryExpression -> evaluateExpression(receiverExpr, scopeDepth) as LLVMVariable - is KtNameReferenceExpression ->{ + is KtNameReferenceExpression -> { val referenceContext = state.bindingContext.get(BindingContext.REFERENCE_TARGET, receiverExpr) variableManager.get(receiverName) when (referenceContext) { @@ -280,12 +281,48 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM fun evaluateArrayAccessExpression(expr: KtArrayAccessExpression, scope: Int): LLVMSingleValue? { val arrayNameVariable = evaluateReferenceExpression(expr.arrayExpression as KtReferenceExpression, scope) as LLVMVariable - val arrayIndex = evaluateConstantExpression(expr.indexExpressions.first() as KtConstantExpression) - val arrayReceivedVariable = codeBuilder.loadAndGetVariable(arrayNameVariable) - val arrayElementType = (arrayNameVariable.type as LLVMArray).basicType() - val indexVariable = codeBuilder.getNewVariable(arrayElementType, pointer = 1) - codeBuilder.loadVariableOffset(indexVariable, arrayReceivedVariable, arrayIndex) - return indexVariable + return when (arrayNameVariable.type) { + is LLVMReferenceType -> { + val callMaker = state.bindingContext.get(BindingContext.CALL, expr) + when (callMaker!!.callType) { + Call.CallType.ARRAY_SET_METHOD, + Call.CallType.ARRAY_GET_METHOD -> { + val arrayActionType = if (callMaker.callType == Call.CallType.ARRAY_SET_METHOD) "set" else "get" + val explicitReceiver = callMaker.explicitReceiver as ExpressionReceiver + val expression = explicitReceiver.expression as KtReferenceExpression + + val receiver = evaluateReferenceExpression(expression, scope)!! as LLVMVariable + val pureReceiver = loadArgumentIfRequired(receiver, LLVMVariable("", receiver.type, pointer = 1)) + + val targetClassName = (receiver.type as LLVMReferenceType).type + + val names = parseValueArguments(callMaker.valueArguments, scope) + val methodName = "$targetClassName.$arrayActionType${if (names.size > 0) "_${names.joinToString(separator = "_", transform = { it.type!!.mangle() })}" else ""}" + val type = receiver.type as LLVMReferenceType + val clazz = resolveClassOrObjectLocation(type) + + val method = clazz.methods[methodName]!! + val returnType = clazz.methods[methodName]!!.returnType!!.type + + val loadedArgs = loadArgsIfRequired(names, method.args) + val callArgs = mutableListOf(pureReceiver) + callArgs.addAll(loadedArgs) + + return evaluateFunctionCallExpression(LLVMVariable(methodName, returnType, scope = LLVMVariableScope()), callArgs) + } + else -> throw IllegalStateException() + } + } + else -> { + val arrayIndex = evaluateConstantExpression(expr.indexExpressions.first() as KtConstantExpression) + val arrayReceivedVariable = codeBuilder.loadAndGetVariable(arrayNameVariable) + val arrayElementType = (arrayNameVariable.type as LLVMArray).basicType() + val indexVariable = codeBuilder.getNewVariable(arrayElementType, pointer = 1) + codeBuilder.loadVariableOffset(indexVariable, arrayReceivedVariable, arrayIndex) + indexVariable + } + } + } private fun evaluateReferenceExpression(expr: KtReferenceExpression, scopeDepth: Int, classScope: ClassCodegen? = null): LLVMSingleValue? = when { @@ -446,6 +483,10 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM private fun parseArgList(expr: KtCallExpression, scopeDepth: Int): ArrayList { val args = expr.getValueArgumentsInParentheses() + return parseValueArguments(args, scopeDepth) + } + + private fun parseValueArguments(args: List, scopeDepth: Int): ArrayList { val result = ArrayList() for (arg in args) { @@ -456,13 +497,18 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM return result } - private fun evaluateBinaryExpression(expr: KtBinaryExpression, scopeDepth: Int): LLVMVariable { + private fun evaluateBinaryExpression(expr: KtBinaryExpression, scopeDepth: Int): LLVMVariable? { val operator = expr.operationToken if (operator == KtTokens.ELVIS) { return evaluateElvisOperator(expr, scopeDepth) } + val left = evaluateExpression(expr.firstChild, scopeDepth) + if (expr.firstChild is KtArrayAccessExpression) { + return null + } else { + left ?: throw UnsupportedOperationException("Wrong binary exception") + } - val left = evaluateExpression(expr.firstChild, scopeDepth) ?: throw UnsupportedOperationException("Wrong binary exception") val right = evaluateExpression(expr.lastChild, scopeDepth) ?: throw UnsupportedOperationException("Wrong binary exception") return executeBinaryExpression(operator, expr.operationReference, left, right) @@ -707,7 +753,7 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM codeBuilder.addUnconditionalJump(if (checkConditionBeforeExecute) conditionLabel else bodyLabel) codeBuilder.markWithLabel(conditionLabel) - val conditionResult = evaluateBinaryExpression(condition, scopeDepth + 1) + val conditionResult = evaluateBinaryExpression(condition, scopeDepth + 1)!! codeBuilder.addCondition(conditionResult, bodyLabel, exitLabel) evaluateCodeBlock(bodyExpression, bodyLabel, conditionLabel, scopeDepth + 1) @@ -731,7 +777,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 conditionResult: LLVMVariable = evaluateBinaryExpression(condition, scopeDepth + 1)!! val kotlinType = state.bindingContext.get(BindingContext.EXPRESSION_TYPE_INFO, ifExpression)!!.type!! val expressionType = LLVMInstanceOfStandardType("type", kotlinType, LLVMVariableScope()).type val resultVariable = codeBuilder.getNewVariable(expressionType, pointer = 1) @@ -755,7 +801,7 @@ abstract class BlockCodegen(open val state: TranslationState, open val variableM } private fun executeIfBlock(condition: KtBinaryExpression, thenExpression: PsiElement, elseExpression: PsiElement?, scopeDepth: Int): LLVMVariable? { - val conditionResult = evaluateBinaryExpression(condition, scopeDepth + 1) + val conditionResult = evaluateBinaryExpression(condition, scopeDepth + 1)!! val thenLabel = codeBuilder.getNewLabel(prefix = "if") val elseLabel = codeBuilder.getNewLabel(prefix = "if") val endLabel = codeBuilder.getNewLabel(prefix = "if") diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/TranslationState.kt b/translator/src/main/kotlin/org/kotlinnative/translator/TranslationState.kt index d69693f3a8a..41d265943ed 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/TranslationState.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/TranslationState.kt @@ -46,7 +46,7 @@ fun parseAndAnalyze(sources: List, disposer: Disposable, arm: Boolean = override fun hasErrors(): Boolean = hasError override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation) { - println("[report] $message") + System.err.println("[report] $message") hasError = severity.isError || hasError } } @@ -90,4 +90,3 @@ fun analyze(environment: KotlinCoreEnvironment): AnalysisResult? { return if (analyzer.hasErrors()) null else analyzer.analysisResult } - diff --git a/translator/src/test/kotlin/tests/input/function_eq.txt b/translator/src/test/kotlin/tests/input/function_eq.txt index 5c4551d1178..d82c425eb18 100644 --- a/translator/src/test/kotlin/tests/input/function_eq.txt +++ b/translator/src/test/kotlin/tests/input/function_eq.txt @@ -1,3 +1,3 @@ -inc_Int(1) == 2 -dinc_Int(1) == 3 -sum_Int_Int(1, 1) == 2 \ No newline at end of file +function_eq_inc_Int(1) == 2 +function_eq_dinc_Int(1) == 3 +function_eq_sum_Int_Int(1, 1) == 2 \ No newline at end of file diff --git a/translator/src/test/kotlin/tests/input/get_set_operators_1.txt b/translator/src/test/kotlin/tests/input/get_set_operators_1.txt new file mode 100644 index 00000000000..3d5585514ca --- /dev/null +++ b/translator/src/test/kotlin/tests/input/get_set_operators_1.txt @@ -0,0 +1,2 @@ +get_set_operators_1_get_Int(210) == 218 +get_set_operators_1_set_Int_Int(8, 903) == 911 diff --git a/translator/src/test/kotlin/tests/input/safe_access_operator.txt b/translator/src/test/kotlin/tests/input/safe_access_operator.txt index 75fe29393c0..f7b1137a7d9 100644 --- a/translator/src/test/kotlin/tests/input/safe_access_operator.txt +++ b/translator/src/test/kotlin/tests/input/safe_access_operator.txt @@ -1 +1 @@ -test1() == 1 +save_access_operator_test1() == 1 diff --git a/translator/src/test/kotlin/tests/input/simple_class_2.txt b/translator/src/test/kotlin/tests/input/simple_class_2.txt index afa9ecb4001..25648e5b636 100644 --- a/translator/src/test/kotlin/tests/input/simple_class_2.txt +++ b/translator/src/test/kotlin/tests/input/simple_class_2.txt @@ -1,3 +1,3 @@ -change_Int(0) == 1 -change_Int(1) == 2 -testGen_Int(10) == 10 +simple_class_2_change_Int(0) == 1 +simple_class_2_change_Int(1) == 2 +simple_class_2_testGen_Int(10) == 10 diff --git a/translator/src/test/kotlin/tests/kotlin/callbacks_1.kt b/translator/src/test/kotlin/tests/kotlin/callbacks_1.kt index 11d3c98d374..6142fd0e975 100644 --- a/translator/src/test/kotlin/tests/kotlin/callbacks_1.kt +++ b/translator/src/test/kotlin/tests/kotlin/callbacks_1.kt @@ -1,26 +1,26 @@ external fun apply_c(arg: Int, x: (Int)-> Int): Int -fun inc(i: Int): Int { +fun callback_1_inc(i: Int): Int { return i + 1 } -fun dec(i: Int): Int { +fun callback_1_dec(i: Int): Int { return i - 1 } -fun apply(arg: Int, x: (Int) -> Int): Int { +fun callback_1_apply(arg: Int, x: (Int) -> Int): Int { return x(arg) } fun compact_test(x: Int): Int { - return apply(apply(apply(x, ::inc), ::inc), ::dec) + return callback_1_apply(callback_1_apply(callback_1_apply(x, ::callback_1_inc), ::callback_1_inc), ::callback_1_dec) } fun external_test(x: Int): Int { - return apply_c(apply_c(apply_c(x, ::dec), ::dec), ::inc) + return apply_c(apply_c(apply_c(x, ::callback_1_dec), ::callback_1_dec), ::callback_1_inc) } fun mixed_test(x: Int): Int { - return apply(apply_c(apply(apply_c(apply(x, ::inc), ::inc), ::inc), ::dec), ::inc) + return callback_1_apply(apply_c(callback_1_apply(apply_c(callback_1_apply(x, ::callback_1_inc), ::callback_1_inc), ::callback_1_inc), ::callback_1_dec), ::callback_1_inc) } \ No newline at end of file diff --git a/translator/src/test/kotlin/tests/kotlin/complex_dot_expr.kt b/translator/src/test/kotlin/tests/kotlin/complex_dot_expr.kt index 9a9606fbc44..0957a99f4c0 100644 --- a/translator/src/test/kotlin/tests/kotlin/complex_dot_expr.kt +++ b/translator/src/test/kotlin/tests/kotlin/complex_dot_expr.kt @@ -1,7 +1,7 @@ -class MyClass(val i: Int) +class complex_dot_expr_MyClass(val i: Int) -fun gen(i: Int) = MyClass(i) +fun gen(i: Int) = complex_dot_expr_MyClass(i) fun test1(q: Int) = gen(q).i -fun test2(w: Int) = MyClass(w).i +fun test2(w: Int) = complex_dot_expr_MyClass(w).i diff --git a/translator/src/test/kotlin/tests/kotlin/elvis_1.kt b/translator/src/test/kotlin/tests/kotlin/elvis_1.kt index fd04b91fee6..672319b6bc4 100644 --- a/translator/src/test/kotlin/tests/kotlin/elvis_1.kt +++ b/translator/src/test/kotlin/tests/kotlin/elvis_1.kt @@ -1,15 +1,15 @@ -class MyClass(val i: Int) +class elvis_1_MyClass(val i: Int) fun elvis_test_1(x: Int): Int { - var z: MyClass? = null + var z: elvis_1_MyClass? = null if (x > 1) { - z = MyClass(1) + z = elvis_1_MyClass(1) } else { } - val y = z ?: return 0 + z ?: return 0 return 1 } diff --git a/translator/src/test/kotlin/tests/kotlin/function_eq.kt b/translator/src/test/kotlin/tests/kotlin/function_eq.kt index c05216aa729..c4a81cd9a52 100644 --- a/translator/src/test/kotlin/tests/kotlin/function_eq.kt +++ b/translator/src/test/kotlin/tests/kotlin/function_eq.kt @@ -1,8 +1,7 @@ +class function_eq_MyClass(val i: Int) -class MyClass(val i: Int) - -fun inc(i: Int) = i + 1 -fun dinc(i: Int) = inc(inc(i)) -fun sum(i: Int, j: Int) = i + j -fun gen() = MyClass(1) +fun function_eq_inc(i: Int) = i + 1 +fun function_eq_dinc(i: Int) = function_eq_inc(function_eq_inc(i)) +fun function_eq_sum(i: Int, j: Int) = i + j +fun function_eq_gen() = function_eq_MyClass(1) diff --git a/translator/src/test/kotlin/tests/kotlin/get_set_operators_1.kt b/translator/src/test/kotlin/tests/kotlin/get_set_operators_1.kt new file mode 100644 index 00000000000..be0cf8f2055 --- /dev/null +++ b/translator/src/test/kotlin/tests/kotlin/get_set_operators_1.kt @@ -0,0 +1,22 @@ +class get_set_operators_1_class { + var cap = 9 + + operator fun get(x: Int): Int { + return x + 8 + } + + operator fun set(x: Int, y: Int): Unit { + cap = x + y + } +} + +fun get_set_operators_1_get(arg: Int): Int { + val b = get_set_operators_1_class() + return b[arg] +} + +fun get_set_operators_1_set(ind: Int, arg: Int): Int { + val b = get_set_operators_1_class() + b[ind] = arg + return b.cap +} \ No newline at end of file diff --git a/translator/src/test/kotlin/tests/kotlin/if_1.kt b/translator/src/test/kotlin/tests/kotlin/if_1.kt index ba38538844c..59a1cace462 100644 --- a/translator/src/test/kotlin/tests/kotlin/if_1.kt +++ b/translator/src/test/kotlin/tests/kotlin/if_1.kt @@ -8,10 +8,9 @@ fun if_test_1(x: Int): Int { return a } -class MyClass_if_1(i: Int) +class MyClass_if_1() fun if_test_null(x: Int): Int { - val y: MyClass_if_1? = null if (y == null) { return 1 @@ -21,7 +20,7 @@ fun if_test_null(x: Int): Int { } fun if_test_null_2(x: Int): Int { - val y: MyClass_if_1? = MyClass_if_1(1) + val y: MyClass_if_1? = MyClass_if_1() if (y == null) { return 1 diff --git a/translator/src/test/kotlin/tests/kotlin/safe_access_operator.kt b/translator/src/test/kotlin/tests/kotlin/safe_access_operator.kt index 92d16fffd77..8e3df0e76de 100644 --- a/translator/src/test/kotlin/tests/kotlin/safe_access_operator.kt +++ b/translator/src/test/kotlin/tests/kotlin/safe_access_operator.kt @@ -1,10 +1,9 @@ +class save_access_operator_Gen(val i: Int) +class save_access_operator_MyClass(val i: save_access_operator_Gen?) -class Gen(val i: Int) -class MyClass(val i: Gen?) - -fun test1(): Int { - val x: MyClass? = null - val y = MyClass(x?.i) +fun save_access_operator_test1(): Int { + val x: save_access_operator_MyClass? = null + val y = save_access_operator_MyClass(x?.i) if (y == null) { return 0 diff --git a/translator/src/test/kotlin/tests/kotlin/simple_class_2.kt b/translator/src/test/kotlin/tests/kotlin/simple_class_2.kt index 6856ff4a655..41b23a122ba 100644 --- a/translator/src/test/kotlin/tests/kotlin/simple_class_2.kt +++ b/translator/src/test/kotlin/tests/kotlin/simple_class_2.kt @@ -1,13 +1,11 @@ +class simple_class_2_MyClass(val b: Int, var c: Int) -class MyClass(val b: Int, var c: Int) - -fun genMyClass(i: Int): MyClass { - return MyClass(i, i) +fun simple_class_2_genMyClass(i: Int): simple_class_2_MyClass { + return simple_class_2_MyClass(i, i) } -fun change(x: Int): Int { - - val y = MyClass(x, x) +fun simple_class_2_change(x: Int): Int { + val y = simple_class_2_MyClass(x, x) y.c = x y.c = x y.c = 1 @@ -16,7 +14,7 @@ fun change(x: Int): Int { return y.c } -fun testGen(i: Int): Int { - val j = genMyClass(i) +fun simple_class_2_testGen(i: Int): Int { + val j = simple_class_2_genMyClass(i) return j.b }