Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2010-2015 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.kotlin.js.inline.context
import com.google.dart.compiler.backend.js.ast.*
import com.google.dart.compiler.backend.js.ast.metadata.staticRef
import org.jetbrains.kotlin.js.inline.util.aliasArgumentsIfNeeded
import org.jetbrains.kotlin.js.inline.util.getInnerFunction
import org.jetbrains.kotlin.js.inline.util.getSimpleName
import org.jetbrains.kotlin.js.inline.util.isCallInvocation
import org.jetbrains.kotlin.js.inline.util.isFunctionCreator
import com.intellij.util.containers.ContainerUtil
import java.util.IdentityHashMap
import org.jetbrains.kotlin.js.inline.FunctionReader
import com.google.dart.compiler.backend.js.ast.metadata.descriptor
abstract class FunctionContext(
private val function: JsFunction,
private val inliningContext: InliningContext,
private val functionReader: FunctionReader
) {
/**
* Caches function with captured arguments applied.
*
* @see getFunctionWithClosure
*/
private val functionsWithClosure = IdentityHashMap()
protected abstract fun lookUpStaticFunction(functionName: JsName?): JsFunction?
fun getFunctionDefinition(call: JsInvocation): JsFunction {
return getFunctionDefinitionImpl(call)!!
}
fun hasFunctionDefinition(call: JsInvocation): Boolean {
return getFunctionDefinitionImpl(call) != null
}
fun getScope(): JsScope {
return function.scope
}
fun declareFunctionConstructorCalls(arguments: List) {
val calls = ContainerUtil.findAll(arguments, JsInvocation::class.java)
for (call in calls) {
val callName = getSimpleName(call)
if (callName == null) continue
val staticRef = callName.staticRef
if (staticRef !is JsFunction) continue
val functionCalled = staticRef
if (isFunctionCreator(functionCalled)) {
declareFunctionConstructorCall(call)
}
}
}
fun declareFunctionConstructorCall(call: JsInvocation) {
functionsWithClosure.put(call, null)
}
/**
* Gets function definition by invocation.
*
* Notes:
* 1. Qualifier -- [()/.call()] part of invocation.
* 2. Local functions are compiled like function literals,
* but called not directly, but through variable.
*
* For example, local `fun f(a, b) = a + b; f(1, 2)` becomes `var f = _.foo.f$; f(1, 2)`
*
* Invocation properties:
* 1. Ends with either [()/.call()].
*
* 2. Qualifier can be JsNameRef with static ref to JsFunction
* in case of function literal without closure.
*
* For example, qualifier == _.foo.lambda$
*
* 3. Qualifier can be JsInvocation with static ref to JsFunction
* in case of function literal with closure. In this case
* qualifier arguments are captured in closure.
*
* For example, qualifier == _.foo.lambda(captured_1)
*
* 4. Qualifier can be JsNameRef with static ref to case [2]
* in case of local function without closure.
*
* 5. Qualifier can be JsNameRef with ref to case [3]
* in case of local function with closure.
*/
private fun getFunctionDefinitionImpl(call: JsInvocation): JsFunction? {
val descriptor = call.descriptor
if (descriptor != null && descriptor in functionReader) return functionReader[descriptor]
/** remove ending `()` */
var callQualifier: JsNode = call.qualifier
/** remove ending `.call()` */
if (isCallInvocation(call)) {
callQualifier = (callQualifier as JsNameRef).qualifier!!
}
/** in case 4, 5 get ref (reduce 4, 5 to 2, 3 accordingly) */
@Suppress("USELESS_CAST") // NB do not remove 'as JsNode' below until KT-10752 is fixed
if (callQualifier is JsNameRef) {
val staticRef = callQualifier.name?.staticRef
callQualifier = when (staticRef) {
is JsNameRef -> staticRef as JsNode
is JsInvocation -> staticRef as JsNode
is JsFunction, null -> callQualifier
else -> throw AssertionError("Unexpected static reference type ${staticRef.javaClass}")
}
}
/** process cases 2, 3 */
val qualifier = callQualifier
return when (qualifier) {
is JsInvocation -> getFunctionWithClosure(qualifier)
is JsNameRef -> lookUpStaticFunction(qualifier.name)
else -> null
}
}
/**
* Gets function body with captured args applied,
* and stores in cache.
*
* Function literals and local functions with closure
* are translated as function, that returns function.
*
* For example,
* val a = 1
* val f = { a * 2 }
* `f` becomes
* f: function (a) {
* return function () { return a * 2 }
* }
*
* @returns inner function with captured parameters,
* replaced by outer arguments
*
* For invocation `f(10)()` returns
* `function () { return 10 * 2 }`
*/
private fun getFunctionWithClosure(call: JsInvocation): JsFunction {
val constructed = functionsWithClosure.get(call)
if (constructed is JsFunction) return constructed
val name = getSimpleName(call)!!
val closureCreator = lookUpStaticFunction(name)!!
val innerFunction = closureCreator.getInnerFunction()!!
val withCapturedArgs = applyCapturedArgs(call, innerFunction, closureCreator)
functionsWithClosure.put(call, withCapturedArgs)
return withCapturedArgs
}
private fun applyCapturedArgs(call: JsInvocation, inner: JsFunction, outer: JsFunction): JsFunction {
val innerClone = inner.deepCopy()
val namingContext = inliningContext.newNamingContext()
val arguments = call.arguments
val parameters = outer.parameters
aliasArgumentsIfNeeded(namingContext, arguments, parameters)
namingContext.applyRenameTo(innerClone)
return innerClone
}
}