From 2088315ed1389401f628b779495f6a4866157b74 Mon Sep 17 00:00:00 2001 From: Alexey Stepanov Date: Mon, 22 Aug 2016 12:27:18 +0300 Subject: [PATCH] translator: add default functions arguments --- .../kotlinnative/translator/BlockCodegen.kt | 41 ++++++++++--- .../translator/FunctionCodegen.kt | 20 +++++++ .../translator/llvm/types/LLVMType.kt | 5 +- .../input/function_default_arguments_1.txt | 9 +++ .../kotlin/function_default_arguments_1.kt | 59 +++++++++++++++++++ 5 files changed, 126 insertions(+), 8 deletions(-) create mode 100644 translator/src/test/kotlin/tests/input/function_default_arguments_1.txt create mode 100644 translator/src/test/kotlin/tests/kotlin/function_default_arguments_1.kt diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt index 471082a0443..a0ea707b26d 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt @@ -15,6 +15,9 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getFunctionResolvedCallWithAs import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert import org.jetbrains.kotlin.resolve.calls.callUtil.getType import org.jetbrains.kotlin.resolve.calls.callUtil.getValueArgumentsInParentheses +import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument +import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument +import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument import org.jetbrains.kotlin.resolve.constants.TypedCompileTimeConstant import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver @@ -23,6 +26,7 @@ import org.kotlinnative.translator.llvm.* import org.kotlinnative.translator.llvm.types.* import java.rmi.UnexpectedException import java.util.* +import kotlin.comparisons.compareBy abstract class BlockCodegen(val state: TranslationState, val variableManager: VariableManager, val codeBuilder: LLVMBuilder) { @@ -402,20 +406,28 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va } private fun evaluateCallExpression(expr: KtCallExpression, scopeDepth: Int, classScope: StructCodegen? = null, caller: LLVMVariable? = null): LLVMSingleValue? { - val names = parseArgList(expr, scopeDepth) + var names = parseArgList(expr, scopeDepth) var name = expr.firstChild.firstChild.text + val targetFunction = state.bindingContext.get(BindingContext.CALL, expr.calleeExpression) + val resolvedCall = state.bindingContext.get(BindingContext.RESOLVED_CALL, targetFunction) + val functionDescriptor = expr.getFunctionResolvedCallWithAssert(state.bindingContext).candidateDescriptor + val arguments = resolvedCall!!.valueArguments.toSortedMap(compareBy { it.index }).values + val external = state.externalFunctions.containsKey(name) - val function = "$name${if (names.size > 0 && !external) LLVMType.mangleFunctionArguments(names) else ""}" + val functionArguments = functionDescriptor.valueParameters.map { it -> it.type }.map { LLVMMapStandardType(it, state) } + val function = "$name${if (!external) LLVMType.mangleFunctionTypes(functionArguments) else ""}" + if (state.functions.containsKey(function) || state.externalFunctions.containsKey(function)) { val descriptor = state.functions[function] ?: state.externalFunctions[function] ?: return null + names = parseNamedValueArguments(arguments, descriptor.defaultValues, scopeDepth) val args = loadArgsIfRequired(names, descriptor.args) return evaluateFunctionCallExpression(LLVMVariable(function, descriptor.returnType!!.type, scope = LLVMVariableScope()), args) } if (state.classes.containsKey(name) || classScope?.structName == name) { val descriptor = state.classes[name] ?: classScope ?: return null - val detectedConstructor = LLVMType.mangleFunctionArguments(names) + val detectedConstructor = LLVMType.mangleFunctionTypes(functionArguments) val args = loadArgsIfRequired(names, descriptor.constructorFields[detectedConstructor]!!) return evaluateConstructorCallExpression(LLVMVariable(descriptor.fullName + detectedConstructor, descriptor.type, scope = LLVMVariableScope()), args) } @@ -545,21 +557,36 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va return result } - private fun parseArgList(expr: KtCallExpression, scopeDepth: Int): ArrayList { + private fun parseArgList(expr: KtCallExpression, scopeDepth: Int): List { val args = expr.getValueArgumentsInParentheses() return parseValueArguments(args, scopeDepth) } - private fun parseValueArguments(args: List, scopeDepth: Int): ArrayList { + private fun parseValueArguments(args: List, scopeDepth: Int): List { val result = ArrayList() for (arg in args) { - val currentExpression = evaluateExpression(arg.getArgumentExpression(), scopeDepth) as LLVMSingleValue - result.add(currentExpression) + result.add(parseOneValueArgument(arg, scopeDepth)) } return result } + fun parseOneValueArgument(arg: ValueArgument, scopeDepth: Int): LLVMSingleValue { + return evaluateExpression(arg.getArgumentExpression(), scopeDepth) as LLVMSingleValue + } + + private fun parseNamedValueArguments(args: MutableCollection, defaultValues: List, scopeDepth: Int): List = + args.mapIndexed(fun(i: Int, value: ResolvedValueArgument): LLVMSingleValue { + return when (value) { + is DefaultValueArgument -> evaluateExpression(defaultValues[i], scopeDepth)!! + else -> { + val expr = ((value as ExpressionValueArgument).valueArgument as KtValueArgument).getArgumentExpression()!! + evaluateExpression(expr, scopeDepth)!! + } + } + }).toList() + + private fun evaluateBinaryExpression(expr: KtBinaryExpression, scopeDepth: Int): LLVMVariable? { val operator = expr.operationToken if (operator == KtTokens.ELVIS) { diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt index 9d94144b184..de1780cf32f 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt @@ -1,9 +1,15 @@ package org.kotlinnative.translator +import org.jetbrains.kotlin.codegen.StackValue +import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtNamedFunction +import org.jetbrains.kotlin.psi.KtParameter import org.jetbrains.kotlin.psi.psiUtil.getNextSiblingIgnoringWhitespaceAndComments import org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.source.KotlinSourceElement +import org.jetbrains.org.objectweb.asm.Label +import org.jetbrains.org.objectweb.asm.Type import org.kotlinnative.translator.llvm.* import org.kotlinnative.translator.llvm.types.LLVMFunctionType import org.kotlinnative.translator.llvm.types.LLVMReferenceType @@ -26,6 +32,7 @@ class FunctionCodegen(state: TranslationState, val fullName: String get() = functionNamePrefix + name val external: Boolean + val defaultValues: List init { val descriptor = state.bindingContext.get(BindingContext.FUNCTION, function)!! @@ -50,6 +57,19 @@ class FunctionCodegen(state: TranslationState, state.extensionFunctions.put(translatorType.toString(), extensionFunctionsOfThisType) } + defaultValues = mutableListOf() + val valueParameters = descriptor.valueParameters + for (index in valueParameters.indices) { + val parameterDescriptor = valueParameters[index] + if (parameterDescriptor.declaresDefaultValue()) { + val initializer = (parameterDescriptor.source as KotlinSourceElement).psi + val defaultValue = (initializer as KtParameter).defaultValue + defaultValues.add(defaultValue!!) + } else { + defaultValues.add(null) + } + } + val retType = returnType!!.type when (retType) { is LLVMReferenceType -> { diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMType.kt b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMType.kt index ef4fc9f13cd..b4c75ca3260 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMType.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMType.kt @@ -39,7 +39,10 @@ abstract class LLVMType() : Cloneable { companion object { fun mangleFunctionArguments(names: List) = - "_${names.joinToString(separator = "_", transform = { it.type!!.mangle() })}" + mangleFunctionTypes(names.map { it.type!! }) + + fun mangleFunctionTypes(names: List) = + if (names.size > 0) "_${names.joinToString(separator = "_", transform = { it.mangle() })}" else "" } } diff --git a/translator/src/test/kotlin/tests/input/function_default_arguments_1.txt b/translator/src/test/kotlin/tests/input/function_default_arguments_1.txt new file mode 100644 index 00000000000..11457898ed6 --- /dev/null +++ b/translator/src/test/kotlin/tests/input/function_default_arguments_1.txt @@ -0,0 +1,9 @@ +function_default_arguments_1_mixed() == 76 +function_default_arguments_1_last_missed_Int(23) == 977 +function_default_arguments_1_last_present_Int(25) == 54 +function_default_arguments_1_position_third_only_Int(19) == 716 +function_default_arguments_1_position_all_reverse_Int(17) == 126 +function_default_arguments_1_position_all_right_order_Int(17) == 126 +function_default_arguments_1_position_all_default_Int(27) ==8268 +function_default_arguments_1_all_position() == 194 +function_default_arguments_1_add_class_arg() == 314 diff --git a/translator/src/test/kotlin/tests/kotlin/function_default_arguments_1.kt b/translator/src/test/kotlin/tests/kotlin/function_default_arguments_1.kt new file mode 100644 index 00000000000..d61ee8e9c67 --- /dev/null +++ b/translator/src/test/kotlin/tests/kotlin/function_default_arguments_1.kt @@ -0,0 +1,59 @@ +class function_default_arguments_1_argClass(val classArgument: Int) + +fun function_default_arguments_1_add(x: Int, t: function_default_arguments_1_argClass = function_default_arguments_1_argClass(124), y: Int = 53, z: Int = 777): Int { + return x + y +} + +fun function_default_arguments_1_add_class(x: Int, t: function_default_arguments_1_argClass = function_default_arguments_1_argClass(124), y: Int = 53, z: Int = 777): Int { + return x + t.classArgument +} + +fun function_default_arguments_1_add_class_arg(): Int { + return function_default_arguments_1_add_class(190) +} + +fun function_default_arguments_1_mixed(): Int { + return function_default_arguments_1_add(23, t = function_default_arguments_1_argClass(29), z = 8) +} + +fun function_default_arguments_1_last_missed_fun(z: Int, u: Int = 954): Int { + return z + u +} + +fun function_default_arguments_1_last_missed(x: Int): Int { + return function_default_arguments_1_last_missed_fun(x) +} + +fun function_default_arguments_1_last_present(x: Int): Int { + return function_default_arguments_1_last_missed_fun(x, 29) +} + +fun function_default_arguments_1_position_fun(first: Int, second: Int = 324 + , third: Int = 2531): Int { + return first + 2 * second + 3 * third +} + +fun function_default_arguments_1_position_third_only(x: Int): Int { + return function_default_arguments_1_position_fun(11, third = x) +} + +fun function_default_arguments_1_position_all_reverse(x: Int): Int { + return function_default_arguments_1_position_fun(11, third = x, second = 32) +} + +fun function_default_arguments_1_position_all_right_order(x: Int): Int { + return function_default_arguments_1_position_fun(11, second = 32, third = x) +} + +fun function_default_arguments_1_position_all_default(x: Int): Int { + return function_default_arguments_1_position_fun(x) +} + +fun function_default_arguments_1_all_position_fun(first: Int = 31, second: Int = 32 + , third: Int = 33): Int { + return first + 2 * second + 3 * third +} + +fun function_default_arguments_1_all_position(): Int { + return function_default_arguments_1_all_position_fun() +} \ No newline at end of file