JS inline refactor: moved invocation and function utils to separate files

This commit is contained in:
Alexey Tsvetkov
2014-10-02 15:38:30 +04:00
committed by Zalim Bashorov
parent 7fbed5ee86
commit 17a78dd522
4 changed files with 170 additions and 118 deletions
@@ -1,113 +0,0 @@
/*
* Copyright 2010-2014 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.inline;
import com.google.dart.compiler.backend.js.ast.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
class InvocationUtil {
/**
* Tests if result of call is being used in containing statement
*/
public static boolean isResultUsed(JsStatement containingStatement, JsInvocation call) {
return !(containingStatement instanceof JsExpressionStatement)
|| call != ((JsExpressionStatement) containingStatement).getExpression();
}
@Nullable
public static JsName getName(@NotNull JsInvocation call) {
JsExpression qualifier = call.getQualifier();
if (qualifier instanceof JsNameRef) {
return ((JsNameRef) qualifier).getName();
}
return null;
}
/**
* Gets inner function from function, that creates closure
*
* For example:
* function(a) {
* return function() { return a; }
* }
*
* Inner functions can only be generated when lambda
* with closure is created
*/
@Nullable
public static JsFunction getInnerFunction(@NotNull JsFunction outer) {
List<JsStatement> statements = outer.getBody().getStatements();
if (statements.size() != 1) {
return null;
}
JsStatement statement = statements.get(0);
if (!(statement instanceof JsReturn)) {
return null;
}
JsExpression returnExpr = ((JsReturn) statement).getExpression();
if (!(returnExpr instanceof JsFunction)) {
return null;
}
return (JsFunction) returnExpr;
}
/**
* Tests if invocation is JavaScript call function
*
* @return true if invocation is something like `x.call(thisReplacement)`
* false otherwise
*/
public static boolean isCallInvocation(JsInvocation invocation) {
JsExpression qualifier = invocation.getQualifier();
if (!(qualifier instanceof JsNameRef)) {
return false;
}
JsNameRef qualifierNameRef = (JsNameRef) qualifier;
return qualifierNameRef.getIdent().equals("call")
&& invocation.getArguments().size() == 1;
}
public static boolean hasReceiver(@NotNull JsInvocation invocation) {
return getReceiverImpl(invocation) != null;
}
@NotNull
public static JsExpression getReceiver(@NotNull JsInvocation invocation) {
JsExpression receiver = getReceiverImpl(invocation);
assert receiver != null;
return receiver;
}
@Nullable
private static JsExpression getReceiverImpl(@NotNull JsInvocation invocation) {
JsExpression qualifier = invocation.getQualifier();
if (!(qualifier instanceof JsNameRef)) {
return null;
}
return ((JsNameRef) qualifier).getQualifier();
}
}
@@ -0,0 +1,44 @@
/*
* Copyright 2010-2014 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.inline.util
import com.google.dart.compiler.backend.js.ast.JsFunction
import com.google.dart.compiler.backend.js.ast.JsReturn
public fun isFunctionCreator(outer: JsFunction): Boolean =
outer.getInnerFunction() != null
/**
* Gets inner function from function, that creates closure
*
* For example:
* function(a) {
* return function() { return a; }
* }
*
* Inner functions can only be generated when lambda
* with closure is created
*/
public fun JsFunction.getInnerFunction(): JsFunction? {
val statements = getBody().getStatements()
if (statements.size() != 1) return null
val statement = statements.get(0)
val returnExpr = (statement as? JsReturn)?.getExpression()
return returnExpr as? JsFunction
}
@@ -0,0 +1,125 @@
/*
* Copyright 2010-2014 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.inline.util
import com.google.dart.compiler.backend.js.ast.JsStatement
import com.google.dart.compiler.backend.js.ast.JsInvocation
import com.google.dart.compiler.backend.js.ast.JsExpressionStatement
import com.google.dart.compiler.backend.js.ast.JsName
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.JsFunction
import com.google.dart.compiler.backend.js.ast.JsReturn
import org.jetbrains.k2js.translate.context.Namer
import com.google.dart.compiler.backend.js.ast.HasName
import com.google.dart.compiler.backend.js.ast.JsNode
/**
* Gets invocation qualifier name.
*
* @returns `f` for `_.foo.f()` call
*/
public fun getSimpleName(call: JsInvocation): JsName? {
val qualifier = call.getQualifier()
return (qualifier as? JsNameRef)?.getName()
}
/**
* Tries to get ident for call.
*
* @returns first name ident (iterating through qualifier chain)
*/
public fun getSimpleIdent(call: JsInvocation): String? {
var qualifier = call.getQualifier()
while (qualifier != null) {
when (qualifier) {
is JsInvocation -> {
val callableQualifier = qualifier as JsInvocation
qualifier = callableQualifier.getQualifier()
if (isCallInvocation(callableQualifier)) {
qualifier = (qualifier as? JsNameRef)?.getQualifier()
}
}
is HasName -> return (qualifier as HasName).getName()?.getIdent()
else -> break
}
}
return null
}
/**
* Checks if JsInvocation is function creator call.
*
* Function creator is a function, that creates closure.
*/
public fun isFunctionCreatorInvocation(invocation: JsInvocation): Boolean {
val staticRef = getStaticRef(invocation)
return when (staticRef) {
is JsFunction -> isFunctionCreator(staticRef)
else -> false
}
}
/**
* Tests if invocation is JavaScript call function
*
* @return true if invocation is something like `x.call(thisReplacement)`
* false otherwise
*/
public fun isCallInvocation(invocation: JsInvocation): Boolean {
val qualifier = invocation.getQualifier() as? JsNameRef
val arguments = invocation.getArguments()
return qualifier?.getIdent() == Namer.CALL_FUNCTION && arguments.notEmpty
}
/**
* Checks if invocation has qualifier before call.
*
* @return true, if invocation is similar to `something.f()`
* false, if invocation is similar to `f()`
*/
public fun hasCallerQualifier(invocation: JsInvocation): Boolean {
return getCallerQualifierImpl(invocation) != null
}
/**
* Gets qualifier preceding call.
*
* @return caller for invocation of type `caller.f()`,
* where caller is any JsNameRef (for example a.b.c. etc.)
*
* @throws AssertionError, if invocation does not have caller qualifier.
*/
public fun getCallerQualifier(invocation: JsInvocation): JsExpression {
return getCallerQualifierImpl(invocation) ?:
throw AssertionError("must check hasQualifier() before calling getQualifier")
}
private fun getCallerQualifierImpl(invocation: JsInvocation): JsExpression? {
return (invocation.getQualifier() as? JsNameRef)?.getQualifier()
}
private fun getStaticRef(invocation: JsInvocation): JsNode? {
val qualifier = invocation.getQualifier()
val qualifierName = (qualifier as? HasName)?.getName()
return qualifierName?.getStaticRef()
}
@@ -33,6 +33,7 @@ import org.jetbrains.jet.lang.descriptors.Visibilities
import com.google.dart.compiler.backend.js.ast.JsVars.JsVar
import org.jetbrains.k2js.translate.utils.JsAstUtils
import com.intellij.util.SmartList
import org.jetbrains.k2js.inline.util.getInnerFunction
import org.jetbrains.jet.lang.types.lang.InlineUtil
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor
@@ -177,12 +178,7 @@ private fun getFreshNamesInScope(scope: JsScope, suggested: List<JsName?>): List
return freshNames.toList()
}
private fun JsFunction.getInnerFunction(): JsFunction? {
val outerStatements = this.getBody().getStatements()
val outerReturn = outerStatements.get(0) as? JsReturn
val innerFunction = outerReturn?.getExpression() as? JsFunction
return innerFunction
}
private fun JsFunction.addDeclaration(name: JsName, value: JsExpression?) {