JS: converted CallArgumentTranslator to Kotlin
This commit is contained in:
+243
-294
@@ -14,361 +14,310 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.js.translate.reference;
|
package org.jetbrains.kotlin.js.translate.reference
|
||||||
|
|
||||||
import com.google.dart.compiler.backend.js.ast.*;
|
import com.google.dart.compiler.backend.js.ast.*
|
||||||
import com.intellij.util.SmartList;
|
import com.intellij.util.SmartList
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.kotlin.js.translate.context.TemporaryConstVariable
|
||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
|
import org.jetbrains.kotlin.js.translate.context.TemporaryVariable
|
||||||
import org.jetbrains.kotlin.js.translate.context.TemporaryConstVariable;
|
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||||
import org.jetbrains.kotlin.js.translate.context.TemporaryVariable;
|
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator
|
||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
import org.jetbrains.kotlin.js.translate.general.Translation
|
||||||
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator;
|
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
||||||
import org.jetbrains.kotlin.js.translate.general.Translation;
|
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils;
|
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
|
||||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
|
import org.jetbrains.kotlin.psi.JetExpression
|
||||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
|
import org.jetbrains.kotlin.psi.ValueArgument
|
||||||
import org.jetbrains.kotlin.psi.JetExpression;
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
import org.jetbrains.kotlin.psi.ValueArgument;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.*;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList
|
||||||
import java.util.Collections;
|
import java.util.Collections
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class CallArgumentTranslator extends AbstractTranslator {
|
public class CallArgumentTranslator private(private val resolvedCall: ResolvedCall<*>, private val receiver: JsExpression?, context: TranslationContext) : AbstractTranslator(context) {
|
||||||
|
|
||||||
@NotNull
|
public class ArgumentsInfo(public val translateArguments: List<JsExpression>, private val hasSpreadOperator: Boolean, public val cachedReceiver: TemporaryConstVariable) {
|
||||||
public static ArgumentsInfo translate(
|
|
||||||
@NotNull ResolvedCall<?> resolvedCall,
|
|
||||||
@Nullable JsExpression receiver,
|
|
||||||
@NotNull TranslationContext context
|
|
||||||
) {
|
|
||||||
return translate(resolvedCall, receiver, context, context.dynamicContext().jsBlock());
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
public fun isHasSpreadOperator(): Boolean {
|
||||||
public static ArgumentsInfo translate(
|
return hasSpreadOperator
|
||||||
@NotNull ResolvedCall<?> resolvedCall,
|
|
||||||
@Nullable JsExpression receiver,
|
|
||||||
@NotNull TranslationContext context,
|
|
||||||
@NotNull JsBlock block
|
|
||||||
) {
|
|
||||||
TranslationContext innerContext = context.innerBlock(block);
|
|
||||||
CallArgumentTranslator argumentTranslator = new CallArgumentTranslator(resolvedCall, receiver, innerContext);
|
|
||||||
ArgumentsInfo result = argumentTranslator.translate();
|
|
||||||
context.moveVarsFrom(innerContext);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ArgumentsInfo {
|
|
||||||
private final List<JsExpression> translateArguments;
|
|
||||||
private final boolean hasSpreadOperator;
|
|
||||||
private final TemporaryConstVariable cachedReceiver;
|
|
||||||
|
|
||||||
public ArgumentsInfo(List<JsExpression> arguments, boolean operator, TemporaryConstVariable receiver) {
|
|
||||||
translateArguments = arguments;
|
|
||||||
hasSpreadOperator = operator;
|
|
||||||
cachedReceiver = receiver;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public List<JsExpression> getTranslateArguments() {
|
|
||||||
return translateArguments;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isHasSpreadOperator() {
|
|
||||||
return hasSpreadOperator;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public TemporaryConstVariable getCachedReceiver() {
|
|
||||||
return cachedReceiver;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static enum ArgumentsKind { HAS_EMPTY_EXPRESSION_ARGUMENT, HAS_NOT_EMPTY_EXPRESSION_ARGUMENT }
|
private enum class ArgumentsKind {
|
||||||
|
HAS_EMPTY_EXPRESSION_ARGUMENT
|
||||||
@NotNull
|
HAS_NOT_EMPTY_EXPRESSION_ARGUMENT
|
||||||
private static ArgumentsKind translateSingleArgument(
|
|
||||||
@NotNull ResolvedValueArgument actualArgument,
|
|
||||||
@NotNull List<JsExpression> result,
|
|
||||||
@NotNull TranslationContext context
|
|
||||||
) {
|
|
||||||
List<ValueArgument> valueArguments = actualArgument.getArguments();
|
|
||||||
|
|
||||||
if (actualArgument instanceof DefaultValueArgument) {
|
|
||||||
result.add(context.namer().getUndefinedExpression());
|
|
||||||
return ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert actualArgument instanceof ExpressionValueArgument;
|
|
||||||
assert valueArguments.size() == 1;
|
|
||||||
|
|
||||||
JetExpression argumentExpression = valueArguments.get(0).getArgumentExpression();
|
|
||||||
assert argumentExpression != null;
|
|
||||||
|
|
||||||
JsExpression jsExpression = Translation.translateAsExpression(argumentExpression, context);
|
|
||||||
result.add(jsExpression);
|
|
||||||
|
|
||||||
if (JsAstUtils.isEmptyExpression(jsExpression)) {
|
|
||||||
return ArgumentsKind.HAS_EMPTY_EXPRESSION_ARGUMENT;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
private val isNativeFunctionCall: Boolean
|
||||||
private static ArgumentsKind translateVarargArgument(
|
|
||||||
@NotNull List<ValueArgument> arguments,
|
|
||||||
@NotNull List<JsExpression> result,
|
|
||||||
@NotNull TranslationContext context,
|
|
||||||
boolean shouldWrapVarargInArray
|
|
||||||
) {
|
|
||||||
if (arguments.isEmpty()) {
|
|
||||||
if (shouldWrapVarargInArray) {
|
|
||||||
result.add(new JsArrayLiteral(Collections.<JsExpression>emptyList()));
|
|
||||||
}
|
|
||||||
return ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<JsExpression> list;
|
{
|
||||||
if (shouldWrapVarargInArray) {
|
this.isNativeFunctionCall = AnnotationsUtils.isNativeObject(resolvedCall.getCandidateDescriptor())
|
||||||
list = arguments.size() == 1 ? new SmartList<JsExpression>() : new ArrayList<JsExpression>(arguments.size());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
list = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ArgumentsKind resultKind = translateValueArguments(arguments, list, context);
|
|
||||||
|
|
||||||
if (shouldWrapVarargInArray) {
|
|
||||||
List<JsExpression> concatArguments = prepareConcatArguments(arguments, list);
|
|
||||||
JsExpression concatExpression = concatArgumentsIfNeeded(concatArguments);
|
|
||||||
result.add(concatExpression);
|
|
||||||
}
|
|
||||||
|
|
||||||
return resultKind;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ArgumentsKind translateValueArguments(
|
private fun removeLastUndefinedArguments(result: List<JsExpression>) {
|
||||||
@NotNull List<ValueArgument> arguments,
|
var i: Int
|
||||||
@NotNull List<JsExpression> list,
|
run {
|
||||||
@NotNull TranslationContext context
|
i = result.size() - 1
|
||||||
) {
|
while (i >= 0) {
|
||||||
ArgumentsKind resultKind = ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT;
|
if (result.get(i) != context().namer().getUndefinedExpression()) {
|
||||||
List<TranslationContext> argContexts = new SmartList<TranslationContext>();
|
break
|
||||||
boolean argumentsShouldBeExtractedToTmpVars = false;
|
|
||||||
for (ValueArgument argument : arguments) {
|
|
||||||
JetExpression argumentExpression = argument.getArgumentExpression();
|
|
||||||
assert argumentExpression != null;
|
|
||||||
TranslationContext argContext = context.innerBlock();
|
|
||||||
JsExpression argExpression = Translation.translateAsExpression(argumentExpression, argContext);
|
|
||||||
list.add(argExpression);
|
|
||||||
context.moveVarsFrom(argContext);
|
|
||||||
argContexts.add(argContext);
|
|
||||||
argumentsShouldBeExtractedToTmpVars = argumentsShouldBeExtractedToTmpVars || !argContext.currentBlockIsEmpty();
|
|
||||||
if (JsAstUtils.isEmptyExpression(argExpression)) {
|
|
||||||
resultKind = ArgumentsKind.HAS_EMPTY_EXPRESSION_ARGUMENT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (argumentsShouldBeExtractedToTmpVars) {
|
|
||||||
extractArguments(list, argContexts, context, resultKind == ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT);
|
|
||||||
}
|
|
||||||
return resultKind;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static JsExpression concatArgumentsIfNeeded(@NotNull List<JsExpression> concatArguments) {
|
|
||||||
assert concatArguments.size() > 0 : "concatArguments.size should not be 0";
|
|
||||||
|
|
||||||
if (concatArguments.size() > 1) {
|
|
||||||
return new JsInvocation(new JsNameRef("concat", concatArguments.get(0)), concatArguments.subList(1, concatArguments.size()));
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return concatArguments.get(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static List<JsExpression> prepareConcatArguments(@NotNull List<ValueArgument> arguments, @NotNull List<JsExpression> list) {
|
|
||||||
assert arguments.size() != 0 : "arguments.size should not be 0";
|
|
||||||
assert arguments.size() == list.size() : "arguments.size: " + arguments.size() + " != list.size: " + list.size();
|
|
||||||
|
|
||||||
List<JsExpression> concatArguments = new SmartList<JsExpression>();
|
|
||||||
List<JsExpression> lastArrayContent = new SmartList<JsExpression>();
|
|
||||||
|
|
||||||
int size = arguments.size();
|
|
||||||
for(int index = 0; index < size; index++) {
|
|
||||||
ValueArgument valueArgument = arguments.get(index);
|
|
||||||
JsExpression expressionArgument = list.get(index);
|
|
||||||
|
|
||||||
if (valueArgument.getSpreadElement() != null) {
|
|
||||||
if (lastArrayContent.size() > 0) {
|
|
||||||
concatArguments.add(new JsArrayLiteral(lastArrayContent));
|
|
||||||
concatArguments.add(expressionArgument);
|
|
||||||
lastArrayContent = new SmartList<JsExpression>();
|
|
||||||
}
|
}
|
||||||
else {
|
i--
|
||||||
concatArguments.add(expressionArgument);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
lastArrayContent.add(expressionArgument);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lastArrayContent.size() > 0) {
|
result.subList(i + 1, result.size()).clear()
|
||||||
concatArguments.add(new JsArrayLiteral(lastArrayContent));
|
|
||||||
}
|
|
||||||
|
|
||||||
return concatArguments;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void extractArguments(
|
private fun translate(): ArgumentsInfo {
|
||||||
@NotNull List<JsExpression> argExpressions,
|
val valueParameters = resolvedCall.getResultingDescriptor().getValueParameters()
|
||||||
@NotNull List<TranslationContext> argContexts,
|
|
||||||
@NotNull TranslationContext context,
|
|
||||||
boolean toTmpVars
|
|
||||||
) {
|
|
||||||
for(int i=0; i<argExpressions.size(); i++) {
|
|
||||||
TranslationContext argContext = argContexts.get(i);
|
|
||||||
JsExpression jsArgExpression = argExpressions.get(i);
|
|
||||||
if (argContext.currentBlockIsEmpty() && TranslationUtils.isCacheNeeded(jsArgExpression)) {
|
|
||||||
if (toTmpVars) {
|
|
||||||
TemporaryVariable temporaryVariable = context.declareTemporary(jsArgExpression);
|
|
||||||
context.addStatementToCurrentBlock(temporaryVariable.assignmentExpression().makeStmt());
|
|
||||||
argExpressions.set(i, temporaryVariable.reference());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
context.addStatementToCurrentBlock(jsArgExpression.makeStmt());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
context.addStatementsToCurrentBlockFrom(argContext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private final ResolvedCall<?> resolvedCall;
|
|
||||||
@Nullable
|
|
||||||
private final JsExpression receiver;
|
|
||||||
private final boolean isNativeFunctionCall;
|
|
||||||
|
|
||||||
private CallArgumentTranslator(
|
|
||||||
@NotNull ResolvedCall<?> resolvedCall,
|
|
||||||
@Nullable JsExpression receiver,
|
|
||||||
@NotNull TranslationContext context
|
|
||||||
) {
|
|
||||||
super(context);
|
|
||||||
this.resolvedCall = resolvedCall;
|
|
||||||
this.receiver = receiver;
|
|
||||||
this.isNativeFunctionCall = AnnotationsUtils.isNativeObject(resolvedCall.getCandidateDescriptor());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void removeLastUndefinedArguments(@NotNull List<JsExpression> result) {
|
|
||||||
int i;
|
|
||||||
for (i = result.size() - 1; i >= 0; i--) {
|
|
||||||
if (result.get(i) != context().namer().getUndefinedExpression()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result.subList(i + 1, result.size()).clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private ArgumentsInfo translate() {
|
|
||||||
List<ValueParameterDescriptor> valueParameters = resolvedCall.getResultingDescriptor().getValueParameters();
|
|
||||||
if (valueParameters.isEmpty()) {
|
if (valueParameters.isEmpty()) {
|
||||||
return new ArgumentsInfo(Collections.<JsExpression>emptyList(), false, null);
|
return ArgumentsInfo(listOf<JsExpression>(), false, null)
|
||||||
}
|
}
|
||||||
boolean hasSpreadOperator = false;
|
var hasSpreadOperator = false
|
||||||
TemporaryConstVariable cachedReceiver = null;
|
var cachedReceiver: TemporaryConstVariable? = null
|
||||||
|
|
||||||
List<JsExpression> result = new ArrayList<JsExpression>(valueParameters.size());
|
var result: MutableList<JsExpression> = ArrayList(valueParameters.size())
|
||||||
List<ResolvedValueArgument> valueArgumentsByIndex = resolvedCall.getValueArgumentsByIndex();
|
val valueArgumentsByIndex = resolvedCall.getValueArgumentsByIndex()
|
||||||
if (valueArgumentsByIndex == null) {
|
if (valueArgumentsByIndex == null) {
|
||||||
throw new IllegalStateException("Failed to arrange value arguments by index: " + resolvedCall.getResultingDescriptor());
|
throw IllegalStateException("Failed to arrange value arguments by index: " + resolvedCall.getResultingDescriptor())
|
||||||
}
|
}
|
||||||
List<JsExpression> argsBeforeVararg = null;
|
var argsBeforeVararg: List<JsExpression>? = null
|
||||||
boolean argumentsShouldBeExtractedToTmpVars = false;
|
var argumentsShouldBeExtractedToTmpVars = false
|
||||||
List<TranslationContext> argContexts = new SmartList<TranslationContext>();
|
val argContexts = SmartList<TranslationContext>()
|
||||||
ArgumentsKind kind = ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT;
|
var kind = ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT
|
||||||
List<JsExpression> concatArguments = null;
|
var concatArguments: MutableList<JsExpression>? = null
|
||||||
|
|
||||||
for (ValueParameterDescriptor parameterDescriptor : valueParameters) {
|
for (parameterDescriptor in valueParameters) {
|
||||||
ResolvedValueArgument actualArgument = valueArgumentsByIndex.get(parameterDescriptor.getIndex());
|
val actualArgument = valueArgumentsByIndex.get(parameterDescriptor.getIndex())
|
||||||
|
|
||||||
TranslationContext argContext = context().innerBlock();
|
val argContext = context().innerBlock()
|
||||||
|
|
||||||
if (actualArgument instanceof VarargValueArgument) {
|
if (actualArgument is VarargValueArgument) {
|
||||||
|
|
||||||
List<ValueArgument> arguments = actualArgument.getArguments();
|
val arguments = actualArgument.getArguments()
|
||||||
|
|
||||||
int size = arguments.size();
|
val size = arguments.size()
|
||||||
for (int i = 0; i != size; ++i) {
|
run {
|
||||||
if (arguments.get(i).getSpreadElement() != null) {
|
var i = 0
|
||||||
hasSpreadOperator = true;
|
while (i != size) {
|
||||||
break;
|
if (arguments.get(i).getSpreadElement() != null) {
|
||||||
|
hasSpreadOperator = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
++i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasSpreadOperator) {
|
if (hasSpreadOperator) {
|
||||||
if (isNativeFunctionCall) {
|
if (isNativeFunctionCall) {
|
||||||
argsBeforeVararg = result;
|
argsBeforeVararg = result
|
||||||
result = new SmartList<JsExpression>();
|
result = SmartList<JsExpression>()
|
||||||
List<JsExpression> list = new SmartList<JsExpression>();
|
val list = SmartList<JsExpression>()
|
||||||
kind = translateValueArguments(arguments, list, argContext);
|
kind = translateValueArguments(arguments, list, argContext)
|
||||||
concatArguments = prepareConcatArguments(arguments, list);
|
concatArguments = prepareConcatArguments(arguments, list)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
kind = translateVarargArgument(arguments, result, argContext, size > 1);
|
kind = translateVarargArgument(arguments, result, argContext, size > 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
kind = translateVarargArgument(arguments, result, argContext, !isNativeFunctionCall);
|
kind = translateVarargArgument(arguments, result, argContext, !isNativeFunctionCall)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
kind = translateSingleArgument(actualArgument, result, argContext);
|
kind = translateSingleArgument(actualArgument, result, argContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
context().moveVarsFrom(argContext);
|
context().moveVarsFrom(argContext)
|
||||||
argContexts.add(argContext);
|
argContexts.add(argContext)
|
||||||
argumentsShouldBeExtractedToTmpVars = argumentsShouldBeExtractedToTmpVars || !argContext.currentBlockIsEmpty();
|
argumentsShouldBeExtractedToTmpVars = argumentsShouldBeExtractedToTmpVars || !argContext.currentBlockIsEmpty()
|
||||||
|
|
||||||
if (kind == ArgumentsKind.HAS_EMPTY_EXPRESSION_ARGUMENT) break;
|
if (kind == ArgumentsKind.HAS_EMPTY_EXPRESSION_ARGUMENT) break
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argumentsShouldBeExtractedToTmpVars) {
|
if (argumentsShouldBeExtractedToTmpVars) {
|
||||||
extractArguments(result, argContexts, context(), kind == ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT);
|
extractArguments(result, argContexts, context(), kind == ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNativeFunctionCall && hasSpreadOperator) {
|
if (isNativeFunctionCall && hasSpreadOperator) {
|
||||||
assert argsBeforeVararg != null : "argsBeforeVararg should not be null";
|
assert(argsBeforeVararg != null, "argsBeforeVararg should not be null")
|
||||||
assert concatArguments != null : "concatArguments should not be null";
|
assert(concatArguments != null, "concatArguments should not be null")
|
||||||
|
|
||||||
concatArguments.addAll(result);
|
concatArguments!!.addAll(result)
|
||||||
|
|
||||||
if (!argsBeforeVararg.isEmpty()) {
|
if (!argsBeforeVararg!!.isEmpty()) {
|
||||||
concatArguments.add(0, new JsArrayLiteral(argsBeforeVararg));
|
concatArguments!!.add(0, JsArrayLiteral(argsBeforeVararg))
|
||||||
}
|
}
|
||||||
|
|
||||||
result = new SmartList<JsExpression>(concatArgumentsIfNeeded(concatArguments));
|
result = SmartList(concatArgumentsIfNeeded(concatArguments))
|
||||||
|
|
||||||
if (receiver != null) {
|
if (receiver != null) {
|
||||||
cachedReceiver = context().getOrDeclareTemporaryConstVariable(receiver);
|
cachedReceiver = context().getOrDeclareTemporaryConstVariable(receiver)
|
||||||
result.add(0, cachedReceiver.reference());
|
result.add(0, cachedReceiver!!.reference())
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result.add(0, JsLiteral.NULL);
|
result.add(0, JsLiteral.NULL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeLastUndefinedArguments(result);
|
removeLastUndefinedArguments(result)
|
||||||
return new ArgumentsInfo(result, hasSpreadOperator, cachedReceiver);
|
return ArgumentsInfo(result, hasSpreadOperator, cachedReceiver)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
public fun translate(resolvedCall: ResolvedCall<*>, receiver: JsExpression?, context: TranslationContext): ArgumentsInfo {
|
||||||
|
return translate(resolvedCall, receiver, context, context.dynamicContext().jsBlock())
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun translate(resolvedCall: ResolvedCall<*>, receiver: JsExpression?, context: TranslationContext, block: JsBlock): ArgumentsInfo {
|
||||||
|
val innerContext = context.innerBlock(block)
|
||||||
|
val argumentTranslator = CallArgumentTranslator(resolvedCall, receiver, innerContext)
|
||||||
|
val result = argumentTranslator.translate()
|
||||||
|
context.moveVarsFrom(innerContext)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun translateSingleArgument(actualArgument: ResolvedValueArgument, result: MutableList<JsExpression>, context: TranslationContext): ArgumentsKind {
|
||||||
|
val valueArguments = actualArgument.getArguments()
|
||||||
|
|
||||||
|
if (actualArgument is DefaultValueArgument) {
|
||||||
|
result.add(context.namer().getUndefinedExpression())
|
||||||
|
return ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(actualArgument is ExpressionValueArgument)
|
||||||
|
assert(valueArguments.size() == 1)
|
||||||
|
|
||||||
|
val argumentExpression = valueArguments.get(0).getArgumentExpression()
|
||||||
|
assert(argumentExpression != null)
|
||||||
|
|
||||||
|
val jsExpression = Translation.translateAsExpression(argumentExpression, context)
|
||||||
|
result.add(jsExpression)
|
||||||
|
|
||||||
|
if (JsAstUtils.isEmptyExpression(jsExpression)) {
|
||||||
|
return ArgumentsKind.HAS_EMPTY_EXPRESSION_ARGUMENT
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun translateVarargArgument(arguments: List<ValueArgument>, result: MutableList<JsExpression>, context: TranslationContext, shouldWrapVarargInArray: Boolean): ArgumentsKind {
|
||||||
|
if (arguments.isEmpty()) {
|
||||||
|
if (shouldWrapVarargInArray) {
|
||||||
|
result.add(JsArrayLiteral(listOf<JsExpression>()))
|
||||||
|
}
|
||||||
|
return ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT
|
||||||
|
}
|
||||||
|
|
||||||
|
val list: MutableList<JsExpression>
|
||||||
|
if (shouldWrapVarargInArray) {
|
||||||
|
list = if (arguments.size() == 1) SmartList<JsExpression>() else ArrayList<JsExpression>(arguments.size())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
list = result
|
||||||
|
}
|
||||||
|
|
||||||
|
val resultKind = translateValueArguments(arguments, list, context)
|
||||||
|
|
||||||
|
if (shouldWrapVarargInArray) {
|
||||||
|
val concatArguments = prepareConcatArguments(arguments, list)
|
||||||
|
val concatExpression = concatArgumentsIfNeeded(concatArguments)
|
||||||
|
result.add(concatExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultKind
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun translateValueArguments(arguments: List<ValueArgument>, list: MutableList<JsExpression>, context: TranslationContext): ArgumentsKind {
|
||||||
|
var resultKind = ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT
|
||||||
|
val argContexts = SmartList<TranslationContext>()
|
||||||
|
var argumentsShouldBeExtractedToTmpVars = false
|
||||||
|
for (argument in arguments) {
|
||||||
|
val argumentExpression = argument.getArgumentExpression()
|
||||||
|
assert(argumentExpression != null)
|
||||||
|
val argContext = context.innerBlock()
|
||||||
|
val argExpression = Translation.translateAsExpression(argumentExpression, argContext)
|
||||||
|
list.add(argExpression)
|
||||||
|
context.moveVarsFrom(argContext)
|
||||||
|
argContexts.add(argContext)
|
||||||
|
argumentsShouldBeExtractedToTmpVars = argumentsShouldBeExtractedToTmpVars || !argContext.currentBlockIsEmpty()
|
||||||
|
if (JsAstUtils.isEmptyExpression(argExpression)) {
|
||||||
|
resultKind = ArgumentsKind.HAS_EMPTY_EXPRESSION_ARGUMENT
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (argumentsShouldBeExtractedToTmpVars) {
|
||||||
|
extractArguments(list, argContexts, context, resultKind == ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT)
|
||||||
|
}
|
||||||
|
return resultKind
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun concatArgumentsIfNeeded(concatArguments: List<JsExpression>): JsExpression {
|
||||||
|
assert(concatArguments.size() > 0, "concatArguments.size should not be 0")
|
||||||
|
|
||||||
|
if (concatArguments.size() > 1) {
|
||||||
|
return JsInvocation(JsNameRef("concat", concatArguments.get(0)), concatArguments.subList(1, concatArguments.size()))
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return concatArguments.get(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun prepareConcatArguments(arguments: List<ValueArgument>, list: List<JsExpression>): MutableList<JsExpression> {
|
||||||
|
assert(arguments.size() != 0, "arguments.size should not be 0")
|
||||||
|
assert(arguments.size() == list.size()) { "arguments.size: " + arguments.size() + " != list.size: " + list.size() }
|
||||||
|
|
||||||
|
val concatArguments = SmartList<JsExpression>()
|
||||||
|
var lastArrayContent: MutableList<JsExpression> = SmartList()
|
||||||
|
|
||||||
|
val size = arguments.size()
|
||||||
|
for (index in 0..size - 1) {
|
||||||
|
val valueArgument = arguments.get(index)
|
||||||
|
val expressionArgument = list.get(index)
|
||||||
|
|
||||||
|
if (valueArgument.getSpreadElement() != null) {
|
||||||
|
if (lastArrayContent.size() > 0) {
|
||||||
|
concatArguments.add(JsArrayLiteral(lastArrayContent))
|
||||||
|
concatArguments.add(expressionArgument)
|
||||||
|
lastArrayContent = SmartList<JsExpression>()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
concatArguments.add(expressionArgument)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lastArrayContent.add(expressionArgument)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lastArrayContent.size() > 0) {
|
||||||
|
concatArguments.add(JsArrayLiteral(lastArrayContent))
|
||||||
|
}
|
||||||
|
|
||||||
|
return concatArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun extractArguments(argExpressions: MutableList<JsExpression>, argContexts: List<TranslationContext>, context: TranslationContext, toTmpVars: Boolean) {
|
||||||
|
for (i in argExpressions.indices) {
|
||||||
|
val argContext = argContexts.get(i)
|
||||||
|
val jsArgExpression = argExpressions.get(i)
|
||||||
|
if (argContext.currentBlockIsEmpty() && TranslationUtils.isCacheNeeded(jsArgExpression)) {
|
||||||
|
if (toTmpVars) {
|
||||||
|
val temporaryVariable = context.declareTemporary(jsArgExpression)
|
||||||
|
context.addStatementToCurrentBlock(temporaryVariable.assignmentExpression().makeStmt())
|
||||||
|
argExpressions.set(i, temporaryVariable.reference())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
context.addStatementToCurrentBlock(jsArgExpression.makeStmt())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
context.addStatementsToCurrentBlockFrom(argContext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user