All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.k2js.translate.callTranslator.FunctionCallCases.kt Maven / Gradle / Ivy

/*
 * 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.callTranslator

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.CallableDescriptor
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.k2js.translate.general.Translation
import com.google.dart.compiler.backend.js.ast.JsLiteral
import com.google.dart.compiler.backend.js.ast.JsName
import org.jetbrains.k2js.translate.context.TranslationContext
import org.jetbrains.k2js.translate.reference.CallArgumentTranslator
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor
import org.jetbrains.jet.lang.descriptors.Visibilities
import org.jetbrains.jet.lang.psi.Call.CallType

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
object DefaultFunctionCallCase : FunctionCallCase {
    // TODO: refactor after fix ArgumentsInfo - duplicate code
    private fun nativeSpreadFunWithThisObjectOrReceiver(argumentsInfo: CallArgumentTranslator.ArgumentsInfo, functionName: JsName): JsExpression {
        val cachedReceiver = argumentsInfo.getCachedReceiver()!!
        val functionCallRef = Namer.getFunctionApplyRef(JsNameRef(functionName, cachedReceiver.assignmentExpression()))
        return JsInvocation(functionCallRef, argumentsInfo.getTranslateArguments())
    }

    fun buildDefaultCallWithThisObject(argumentsInfo: CallArgumentTranslator.ArgumentsInfo,
                                       thisObject: JsExpression,
                                       functionName: JsName,
                                       isNative: Boolean,
                                       hasSpreadOperator: Boolean): JsExpression {
        if (isNative && hasSpreadOperator) {
            return nativeSpreadFunWithThisObjectOrReceiver(argumentsInfo, functionName)
        }
        val functionRef = JsNameRef(functionName, thisObject)
        return JsInvocation(functionRef, argumentsInfo.getTranslateArguments())
    }

    fun buildDefaultCallWithoutReceiver(context: TranslationContext,
                                        argumentsInfo: CallArgumentTranslator.ArgumentsInfo,
                                        callableDescriptor: CallableDescriptor,
                                        functionName: JsName,
                                        isNative: Boolean,
                                        hasSpreadOperator: Boolean): JsExpression {
        if (isNative && hasSpreadOperator) {
            val functionCallRef = Namer.getFunctionApplyRef(JsNameRef(functionName))
            return JsInvocation(functionCallRef, argumentsInfo.getTranslateArguments())
        }
        if (isNative) {
            return JsInvocation(JsNameRef(functionName), argumentsInfo.getTranslateArguments())
        }

        val functionRef = context.aliasOrValue(callableDescriptor) {
            val qualifierForFunction = context.getQualifierForDescriptor(it)
            JsNameRef(functionName, qualifierForFunction)
        }
        return JsInvocation(functionRef, argumentsInfo.getTranslateArguments())
    }

    override fun FunctionCallInfo.noReceivers(): JsExpression {
        return buildDefaultCallWithoutReceiver(context, argumentsInfo, callableDescriptor, functionName, isNative(), hasSpreadOperator())
    }

    override fun FunctionCallInfo.thisObject(): JsExpression {
        return buildDefaultCallWithThisObject(argumentsInfo, thisObject!!, functionName, isNative(), hasSpreadOperator())
    }

    override fun FunctionCallInfo.receiverArgument(): JsExpression {
        if (isNative() && hasSpreadOperator()) {
            return nativeSpreadFunWithThisObjectOrReceiver(argumentsInfo, functionName)
        }
        if (isNative()) {
            return JsInvocation(JsNameRef(functionName, receiverObject), argumentsInfo.getTranslateArguments())
        }

        val functionRef = context.aliasOrValue(callableDescriptor) {
            val qualifierForFunction = context.getQualifierForDescriptor(it)
            JsNameRef(functionName, qualifierForFunction) // TODO: remake to call
        }

        val referenceToCall =
                if (callableDescriptor.getVisibility() == Visibilities.LOCAL) {
                    Namer.getFunctionCallRef(functionRef)
                }
                else {
                    functionRef
                }

        return JsInvocation(referenceToCall, addReceiverToArgs(receiverObject!!, argumentsInfo.getTranslateArguments()))
    }

    override fun FunctionCallInfo.bothReceivers(): JsExpression {
        // TODO: think about crazy case: spreadOperator + native
        val functionRef = JsNameRef(functionName, thisObject!!)
        return JsInvocation(functionRef, addReceiverToArgs(receiverObject!!, argumentsInfo.getTranslateArguments()))
    }
}


object DelegateFunctionIntrinsic : DelegateIntrinsic {
    override fun FunctionCallInfo.getArgs(): List {
        return argumentsInfo.getTranslateArguments()
    }
    override fun FunctionCallInfo.getDescriptor(): CallableDescriptor {
        return callableDescriptor
    }
}

object InvokeIntrinsic : FunctionCallCase {
    fun canApply(callInfo: FunctionCallInfo): Boolean {
        if (!callInfo.callableDescriptor.getName().asString().equals("invoke"))
            return false
        val parameterCount = callInfo.callableDescriptor.getValueParameters().size()
        val funDeclaration = callInfo.callableDescriptor.getContainingDeclaration()
        return funDeclaration == ((if (callInfo.callableDescriptor.getReceiverParameter() == null)
            KotlinBuiltIns.getInstance().getFunction(parameterCount)
        else
            KotlinBuiltIns.getInstance().getExtensionFunction(parameterCount)))
    }

    override fun FunctionCallInfo.thisObject(): JsExpression {
        return JsInvocation(thisObject, argumentsInfo.getTranslateArguments())
    }
    override fun FunctionCallInfo.bothReceivers(): JsExpression {
        return JsInvocation(Namer.getFunctionCallRef(thisObject!!), addReceiverToArgs(receiverObject!!, argumentsInfo.getTranslateArguments()))
    }
}

object ConstructorCallCase : FunctionCallCase {
    fun canApply(callInfo: FunctionCallInfo): Boolean {
        return callInfo.callableDescriptor is ConstructorDescriptor
    }

    override fun FunctionCallInfo.noReceivers(): JsExpression {
        if (isNative()) {
            return JsNew(JsNameRef(functionName), argumentsInfo.getTranslateArguments())
        }

        val functionRef = context.aliasOrValue(callableDescriptor) {
            context.getQualifiedReference(it)
        }
        return JsNew(functionRef, argumentsInfo.getTranslateArguments())
    }
}

object SuperCallCase : FunctionCallCase {
    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 FunctionCallInfo.translateFunctionCall(): JsExpression {
    val intrinsic = DelegateFunctionIntrinsic.intrinsic(this)

    return when {
        intrinsic != null ->
            intrinsic
        InvokeIntrinsic.canApply(this) ->
            InvokeIntrinsic.translate(this)
        ConstructorCallCase.canApply(this) ->
            ConstructorCallCase.translate(this)
        SuperCallCase.canApply(this) ->
            SuperCallCase.translate(this)
        else ->
            DefaultFunctionCallCase.translate(this)
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy