JS backend: Add FunctionCallCases
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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<FunctionCallCase, FunctionCallInfo>()
|
||||
val functionCallCases: CallCaseDispatcher<FunctionCallCase, FunctionCallInfo> = createFunctionCases()
|
||||
val variableAccessCases = CallCaseDispatcher<VariableAccessCase, VariableAccessInfo>()
|
||||
|
||||
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