From 16f97d5c9712a6c7dba509b7a22db54ac648e55f Mon Sep 17 00:00:00 2001 From: Erokhin Stanislav Date: Fri, 27 Dec 2013 17:33:22 +0400 Subject: [PATCH] JS backend: Add FunctionCallCases --- .../translate/reference/CallTranslator.java | 2 +- .../reference/ClearCallTranslator.kt | 25 ++- .../translate/reference/FunctionCallCases.kt | 149 ++++++++++++++++++ 3 files changed, 174 insertions(+), 2 deletions(-) create mode 100644 js/js.translator/src/org/jetbrains/k2js/translate/reference/FunctionCallCases.kt diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java index d3fac298abd..aa80d941e39 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java @@ -114,7 +114,7 @@ public final class CallTranslator extends AbstractTranslator { } @Nullable - private JsExpression intrinsicInvocation() { + public JsExpression intrinsicInvocation() { if (descriptor instanceof FunctionDescriptor) { try { FunctionIntrinsic intrinsic = context().intrinsics().getFunctionIntrinsics().getIntrinsic((FunctionDescriptor) descriptor); diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/ClearCallTranslator.kt b/js/js.translator/src/org/jetbrains/k2js/translate/reference/ClearCallTranslator.kt index 2b25e15de11..232911443f1 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/ClearCallTranslator.kt +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/ClearCallTranslator.kt @@ -25,9 +25,10 @@ import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall import org.jetbrains.k2js.translate.context.TranslationContext import java.util.ArrayList import org.jetbrains.k2js.facade.exceptions.UnsupportedFeatureException +import org.jetbrains.jet.lang.resolve.calls.tasks.ExplicitReceiverKind.* -val functionCallCases = CallCaseDispatcher() +val functionCallCases: CallCaseDispatcher = createFunctionCases() val variableAccessCases = CallCaseDispatcher() fun TranslationContext.buildCall(resolvedCall: ResolvedCall, receiver: JsExpression? = null): JsExpression { @@ -135,3 +136,25 @@ class CallCaseDispatcher, I : BaseCallInfo> { } } +trait DelegateIntrinsic : CallCase { + fun I.getReceiver(): JsExpression? { + return when (resolvedCall.getExplicitReceiverKind()) { + THIS_OBJECT -> thisObject + RECEIVER_ARGUMENT, BOTH_RECEIVERS -> receiverObject + else -> null + } + } + + fun I.getDescriptor(): CallableDescriptor + fun I.getArgs(): List + + fun I.intrinsic(): JsExpression? { + val callType = if (resolvedCall.isSafeCall()) CallType.SAFE else CallType.NORMAL + val translator = CallTranslator(getReceiver(), null, getArgs(), resolvedCall, getDescriptor(), callType, context) + return translator.intrinsicInvocation() + } + + fun intrinsic(): JsExpression? { + return callInfo.intrinsic() + } +} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/FunctionCallCases.kt b/js/js.translator/src/org/jetbrains/k2js/translate/reference/FunctionCallCases.kt new file mode 100644 index 00000000000..8d8db4159f7 --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/FunctionCallCases.kt @@ -0,0 +1,149 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.k2js.translate.reference + +import com.google.dart.compiler.backend.js.ast.JsExpression +import com.google.dart.compiler.backend.js.ast.JsNameRef +import com.google.dart.compiler.backend.js.ast.JsInvocation +import java.util.Collections +import java.util.ArrayList +import org.jetbrains.k2js.translate.context.Namer +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor +import org.jetbrains.jet.lang.descriptors.CallableDescriptor +import org.jetbrains.jet.lang.resolve.calls.tasks.ExplicitReceiverKind +import com.google.dart.compiler.backend.js.ast.JsNew +import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor +import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns +import org.jetbrains.jet.lang.resolve.calls.util.ExpressionAsFunctionDescriptor +import org.jetbrains.k2js.translate.utils.TranslationUtils +import org.jetbrains.k2js.translate.general.Translation +import org.jetbrains.k2js.translate.utils.PsiUtils +import com.google.dart.compiler.backend.js.ast.JsLiteral + +public fun addReceiverToArgs(receiver: JsExpression, arguments: List) : List { + if (arguments.isEmpty()) + return Collections.singletonList(receiver) + + val argumentList = ArrayList(1 + arguments.size()) + argumentList.add(receiver) + argumentList.addAll(arguments) + return argumentList +} + + +// call may be native and|or with spreadOperator +class DefaultCallCase(callInfo: FunctionCallInfo): FunctionCallCase(callInfo) { //TODO: check spreadOperator + + override fun FunctionCallInfo.bothReceivers(): JsExpression { // TODO: think about crazy case: spreadOperator + native + val functionRef = JsNameRef(functionName, thisObject!!) + return JsInvocation(functionRef, addReceiverToArgs(receiverObject!!, argumentsInfo.getTranslateArguments())) + } + + override fun FunctionCallInfo.thisObject(): JsExpression { + if (isNative() && hasSpreadOperator()) { + val cachedReceiver = argumentsInfo.getCachedReceiver()!! + val functionCallRef = Namer.getFunctionCallRef(JsNameRef(functionName, cachedReceiver.assignmentExpression())) + return JsInvocation(functionCallRef, argumentsInfo.getTranslateArguments()) + } + val functionRef = JsNameRef(functionName, thisObject!!) + return JsInvocation(functionRef, argumentsInfo.getTranslateArguments()) + } + + // TODO: refactor after fix ArgumentsInfo - duplicate code + override fun FunctionCallInfo.receiverArgument(): JsExpression { + val qualifierForFunction = context.getQualifierForDescriptor(callableDescriptor) + if (isNative() && hasSpreadOperator()) { + val functionCallRef = Namer.getFunctionCallRef(JsNameRef(functionName, qualifierForFunction)) + return JsInvocation(functionCallRef, argumentsInfo.getTranslateArguments()) + } + if (isNative()) { + return JsInvocation(JsNameRef(functionName, receiverObject), argumentsInfo.getTranslateArguments()) + } + val functionCall = JsNameRef(functionName, qualifierForFunction) // TODO: remake to call + return JsInvocation(functionCall, addReceiverToArgs(receiverObject!!, argumentsInfo.getTranslateArguments())) + } + override fun FunctionCallInfo.noReceivers(): JsExpression { + val qualifierForFunction = context.getQualifierForDescriptor(callableDescriptor) + if (isNative() && hasSpreadOperator()) { + val functionCallRef = Namer.getFunctionCallRef(JsNameRef(functionName, qualifierForFunction)) + return JsInvocation(functionCallRef, argumentsInfo.getTranslateArguments()) + } + val functionCall = JsNameRef(functionName, qualifierForFunction) + return JsInvocation(functionCall, argumentsInfo.getTranslateArguments()) + } +} + + +class DelegateFunctionIntrinsic(callInfo: FunctionCallInfo) : FunctionCallCase(callInfo), DelegateIntrinsic { + override fun FunctionCallInfo.getArgs(): List { + return argumentsInfo.getTranslateArguments() + } + override fun FunctionCallInfo.getDescriptor(): CallableDescriptor { + return callableDescriptor + } +} + +class ConstructorCallCase(callInfo: FunctionCallInfo) : FunctionCallCase(callInfo) { + override fun FunctionCallInfo.noReceivers(): JsExpression { + return JsNew(context.getQualifiedReference(callableDescriptor), argumentsInfo.getTranslateArguments()) + } +} + +class ExpressionAsFunctionDescriptorIntrinsic(callInfo: FunctionCallInfo) : FunctionCallCase(callInfo) { + class object { + fun canApply(callInfo: FunctionCallInfo): Boolean { + return callInfo.callableDescriptor is ExpressionAsFunctionDescriptor + } + } + + override fun FunctionCallInfo.noReceivers(): JsExpression { + if (callableDescriptor !is ExpressionAsFunctionDescriptor) { + throw IllegalStateException("callableDescriptor must be ExpressionAsFunctionDescriptor $callInfo") + } + val funRef = Translation.translateAsExpression(callableDescriptor.getExpression()!!, context) + return JsInvocation(funRef, argumentsInfo.getTranslateArguments()) + + } +} + +class SuperCallCase(callInfo: FunctionCallInfo) : FunctionCallCase(callInfo) { + class object { + fun canApply(callInfo: FunctionCallInfo): Boolean { + return callInfo.isSuperInvocation() + } + } + + override fun FunctionCallInfo.thisObject(): JsExpression { // TODO: spread operator + val prototypeClass = JsNameRef(Namer.getPrototypeName(), thisObject!!) + val functionRef = Namer.getFunctionCallRef(JsNameRef(functionName, prototypeClass)) + return JsInvocation(functionRef, addReceiverToArgs(JsLiteral.THIS, argumentsInfo.getTranslateArguments())) + } +} + +fun createFunctionCases(): CallCaseDispatcher { + val caseDispatcher = CallCaseDispatcher() + + caseDispatcher.addCase(::ExpressionAsFunctionDescriptorIntrinsic) {ExpressionAsFunctionDescriptorIntrinsic.canApply(it)} + + caseDispatcher.addCase { DelegateFunctionIntrinsic(it).intrinsic() } + + caseDispatcher.addCase(::ConstructorCallCase) {it.callableDescriptor is ConstructorDescriptor} + caseDispatcher.addCase(::SuperCallCase) {SuperCallCase.canApply(it)} + + caseDispatcher.addCase(::DefaultCallCase) { true } // TODO: fix this + return caseDispatcher +} \ No newline at end of file