JS backend: Add FunctionCallCases
This commit is contained in:
@@ -114,7 +114,7 @@ public final class CallTranslator extends AbstractTranslator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private JsExpression intrinsicInvocation() {
|
public JsExpression intrinsicInvocation() {
|
||||||
if (descriptor instanceof FunctionDescriptor) {
|
if (descriptor instanceof FunctionDescriptor) {
|
||||||
try {
|
try {
|
||||||
FunctionIntrinsic intrinsic = context().intrinsics().getFunctionIntrinsics().getIntrinsic((FunctionDescriptor) descriptor);
|
FunctionIntrinsic intrinsic = context().intrinsics().getFunctionIntrinsics().getIntrinsic((FunctionDescriptor) descriptor);
|
||||||
|
|||||||
@@ -25,9 +25,10 @@ import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall
|
|||||||
import org.jetbrains.k2js.translate.context.TranslationContext
|
import org.jetbrains.k2js.translate.context.TranslationContext
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
import org.jetbrains.k2js.facade.exceptions.UnsupportedFeatureException
|
import org.jetbrains.k2js.facade.exceptions.UnsupportedFeatureException
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.tasks.ExplicitReceiverKind.*
|
||||||
|
|
||||||
|
|
||||||
val functionCallCases = CallCaseDispatcher<FunctionCallCase, FunctionCallInfo>()
|
val functionCallCases: CallCaseDispatcher<FunctionCallCase, FunctionCallInfo> = createFunctionCases()
|
||||||
val variableAccessCases = CallCaseDispatcher<VariableAccessCase, VariableAccessInfo>()
|
val variableAccessCases = CallCaseDispatcher<VariableAccessCase, VariableAccessInfo>()
|
||||||
|
|
||||||
fun TranslationContext.buildCall(resolvedCall: ResolvedCall<out FunctionDescriptor>, receiver: JsExpression? = null): JsExpression {
|
fun TranslationContext.buildCall(resolvedCall: ResolvedCall<out FunctionDescriptor>, receiver: JsExpression? = null): JsExpression {
|
||||||
@@ -135,3 +136,25 @@ class CallCaseDispatcher<C : CallCase<I>, I : BaseCallInfo> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait DelegateIntrinsic<I : BaseCallInfo> : CallCase<I> {
|
||||||
|
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<JsExpression>
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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<JsExpression>) : List<JsExpression> {
|
||||||
|
if (arguments.isEmpty())
|
||||||
|
return Collections.singletonList(receiver)
|
||||||
|
|
||||||
|
val argumentList = ArrayList<JsExpression>(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<FunctionCallInfo> {
|
||||||
|
override fun FunctionCallInfo.getArgs(): List<JsExpression> {
|
||||||
|
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<FunctionCallCase, FunctionCallInfo> {
|
||||||
|
val caseDispatcher = CallCaseDispatcher<FunctionCallCase, FunctionCallInfo>()
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user