JS: converted CallArgumentTranslator to Kotlin
This commit is contained in:
+243
-294
@@ -14,361 +14,310 @@
|
||||
* 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.intellij.util.SmartList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.kotlin.js.translate.context.TemporaryConstVariable;
|
||||
import org.jetbrains.kotlin.js.translate.context.TemporaryVariable;
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
||||
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.kotlin.js.translate.general.Translation;
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
|
||||
import org.jetbrains.kotlin.psi.JetExpression;
|
||||
import org.jetbrains.kotlin.psi.ValueArgument;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*;
|
||||
import com.google.dart.compiler.backend.js.ast.*
|
||||
import com.intellij.util.SmartList
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.js.translate.context.TemporaryConstVariable
|
||||
import org.jetbrains.kotlin.js.translate.context.TemporaryVariable
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator
|
||||
import org.jetbrains.kotlin.js.translate.general.Translation
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
|
||||
import org.jetbrains.kotlin.psi.JetExpression
|
||||
import org.jetbrains.kotlin.psi.ValueArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList
|
||||
import java.util.Collections
|
||||
|
||||
public class CallArgumentTranslator extends AbstractTranslator {
|
||||
public class CallArgumentTranslator private(private val resolvedCall: ResolvedCall<*>, private val receiver: JsExpression?, context: TranslationContext) : AbstractTranslator(context) {
|
||||
|
||||
@NotNull
|
||||
public static ArgumentsInfo translate(
|
||||
@NotNull ResolvedCall<?> resolvedCall,
|
||||
@Nullable JsExpression receiver,
|
||||
@NotNull TranslationContext context
|
||||
) {
|
||||
return translate(resolvedCall, receiver, context, context.dynamicContext().jsBlock());
|
||||
}
|
||||
public class ArgumentsInfo(public val translateArguments: List<JsExpression>, private val hasSpreadOperator: Boolean, public val cachedReceiver: TemporaryConstVariable) {
|
||||
|
||||
@NotNull
|
||||
public static ArgumentsInfo translate(
|
||||
@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;
|
||||
public fun isHasSpreadOperator(): Boolean {
|
||||
return hasSpreadOperator
|
||||
}
|
||||
}
|
||||
|
||||
private static enum ArgumentsKind { HAS_EMPTY_EXPRESSION_ARGUMENT, HAS_NOT_EMPTY_EXPRESSION_ARGUMENT }
|
||||
|
||||
@NotNull
|
||||
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;
|
||||
}
|
||||
private enum class ArgumentsKind {
|
||||
HAS_EMPTY_EXPRESSION_ARGUMENT
|
||||
HAS_NOT_EMPTY_EXPRESSION_ARGUMENT
|
||||
}
|
||||
|
||||
@NotNull
|
||||
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;
|
||||
}
|
||||
private val isNativeFunctionCall: Boolean
|
||||
|
||||
List<JsExpression> list;
|
||||
if (shouldWrapVarargInArray) {
|
||||
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;
|
||||
{
|
||||
this.isNativeFunctionCall = AnnotationsUtils.isNativeObject(resolvedCall.getCandidateDescriptor())
|
||||
}
|
||||
|
||||
private static ArgumentsKind translateValueArguments(
|
||||
@NotNull List<ValueArgument> arguments,
|
||||
@NotNull List<JsExpression> list,
|
||||
@NotNull TranslationContext context
|
||||
) {
|
||||
ArgumentsKind resultKind = ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT;
|
||||
List<TranslationContext> argContexts = new SmartList<TranslationContext>();
|
||||
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>();
|
||||
private fun removeLastUndefinedArguments(result: List<JsExpression>) {
|
||||
var i: Int
|
||||
run {
|
||||
i = result.size() - 1
|
||||
while (i >= 0) {
|
||||
if (result.get(i) != context().namer().getUndefinedExpression()) {
|
||||
break
|
||||
}
|
||||
else {
|
||||
concatArguments.add(expressionArgument);
|
||||
}
|
||||
}
|
||||
else {
|
||||
lastArrayContent.add(expressionArgument);
|
||||
i--
|
||||
}
|
||||
}
|
||||
if (lastArrayContent.size() > 0) {
|
||||
concatArguments.add(new JsArrayLiteral(lastArrayContent));
|
||||
}
|
||||
|
||||
return concatArguments;
|
||||
result.subList(i + 1, result.size()).clear()
|
||||
}
|
||||
|
||||
private static void extractArguments(
|
||||
@NotNull List<JsExpression> argExpressions,
|
||||
@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();
|
||||
private fun translate(): ArgumentsInfo {
|
||||
val valueParameters = resolvedCall.getResultingDescriptor().getValueParameters()
|
||||
if (valueParameters.isEmpty()) {
|
||||
return new ArgumentsInfo(Collections.<JsExpression>emptyList(), false, null);
|
||||
return ArgumentsInfo(listOf<JsExpression>(), false, null)
|
||||
}
|
||||
boolean hasSpreadOperator = false;
|
||||
TemporaryConstVariable cachedReceiver = null;
|
||||
var hasSpreadOperator = false
|
||||
var cachedReceiver: TemporaryConstVariable? = null
|
||||
|
||||
List<JsExpression> result = new ArrayList<JsExpression>(valueParameters.size());
|
||||
List<ResolvedValueArgument> valueArgumentsByIndex = resolvedCall.getValueArgumentsByIndex();
|
||||
var result: MutableList<JsExpression> = ArrayList(valueParameters.size())
|
||||
val valueArgumentsByIndex = resolvedCall.getValueArgumentsByIndex()
|
||||
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;
|
||||
boolean argumentsShouldBeExtractedToTmpVars = false;
|
||||
List<TranslationContext> argContexts = new SmartList<TranslationContext>();
|
||||
ArgumentsKind kind = ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT;
|
||||
List<JsExpression> concatArguments = null;
|
||||
var argsBeforeVararg: List<JsExpression>? = null
|
||||
var argumentsShouldBeExtractedToTmpVars = false
|
||||
val argContexts = SmartList<TranslationContext>()
|
||||
var kind = ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT
|
||||
var concatArguments: MutableList<JsExpression>? = null
|
||||
|
||||
for (ValueParameterDescriptor parameterDescriptor : valueParameters) {
|
||||
ResolvedValueArgument actualArgument = valueArgumentsByIndex.get(parameterDescriptor.getIndex());
|
||||
for (parameterDescriptor in valueParameters) {
|
||||
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();
|
||||
for (int i = 0; i != size; ++i) {
|
||||
if (arguments.get(i).getSpreadElement() != null) {
|
||||
hasSpreadOperator = true;
|
||||
break;
|
||||
val size = arguments.size()
|
||||
run {
|
||||
var i = 0
|
||||
while (i != size) {
|
||||
if (arguments.get(i).getSpreadElement() != null) {
|
||||
hasSpreadOperator = true
|
||||
break
|
||||
}
|
||||
++i
|
||||
}
|
||||
}
|
||||
|
||||
if (hasSpreadOperator) {
|
||||
if (isNativeFunctionCall) {
|
||||
argsBeforeVararg = result;
|
||||
result = new SmartList<JsExpression>();
|
||||
List<JsExpression> list = new SmartList<JsExpression>();
|
||||
kind = translateValueArguments(arguments, list, argContext);
|
||||
concatArguments = prepareConcatArguments(arguments, list);
|
||||
argsBeforeVararg = result
|
||||
result = SmartList<JsExpression>()
|
||||
val list = SmartList<JsExpression>()
|
||||
kind = translateValueArguments(arguments, list, argContext)
|
||||
concatArguments = prepareConcatArguments(arguments, list)
|
||||
}
|
||||
else {
|
||||
kind = translateVarargArgument(arguments, result, argContext, size > 1);
|
||||
kind = translateVarargArgument(arguments, result, argContext, size > 1)
|
||||
}
|
||||
}
|
||||
else {
|
||||
kind = translateVarargArgument(arguments, result, argContext, !isNativeFunctionCall);
|
||||
kind = translateVarargArgument(arguments, result, argContext, !isNativeFunctionCall)
|
||||
}
|
||||
}
|
||||
else {
|
||||
kind = translateSingleArgument(actualArgument, result, argContext);
|
||||
kind = translateSingleArgument(actualArgument, result, argContext)
|
||||
}
|
||||
|
||||
context().moveVarsFrom(argContext);
|
||||
argContexts.add(argContext);
|
||||
argumentsShouldBeExtractedToTmpVars = argumentsShouldBeExtractedToTmpVars || !argContext.currentBlockIsEmpty();
|
||||
context().moveVarsFrom(argContext)
|
||||
argContexts.add(argContext)
|
||||
argumentsShouldBeExtractedToTmpVars = argumentsShouldBeExtractedToTmpVars || !argContext.currentBlockIsEmpty()
|
||||
|
||||
if (kind == ArgumentsKind.HAS_EMPTY_EXPRESSION_ARGUMENT) break;
|
||||
if (kind == ArgumentsKind.HAS_EMPTY_EXPRESSION_ARGUMENT) break
|
||||
}
|
||||
|
||||
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) {
|
||||
assert argsBeforeVararg != null : "argsBeforeVararg should not be null";
|
||||
assert concatArguments != null : "concatArguments should not be null";
|
||||
assert(argsBeforeVararg != null, "argsBeforeVararg should not be null")
|
||||
assert(concatArguments != null, "concatArguments should not be null")
|
||||
|
||||
concatArguments.addAll(result);
|
||||
concatArguments!!.addAll(result)
|
||||
|
||||
if (!argsBeforeVararg.isEmpty()) {
|
||||
concatArguments.add(0, new JsArrayLiteral(argsBeforeVararg));
|
||||
if (!argsBeforeVararg!!.isEmpty()) {
|
||||
concatArguments!!.add(0, JsArrayLiteral(argsBeforeVararg))
|
||||
}
|
||||
|
||||
result = new SmartList<JsExpression>(concatArgumentsIfNeeded(concatArguments));
|
||||
result = SmartList(concatArgumentsIfNeeded(concatArguments))
|
||||
|
||||
if (receiver != null) {
|
||||
cachedReceiver = context().getOrDeclareTemporaryConstVariable(receiver);
|
||||
result.add(0, cachedReceiver.reference());
|
||||
cachedReceiver = context().getOrDeclareTemporaryConstVariable(receiver)
|
||||
result.add(0, cachedReceiver!!.reference())
|
||||
}
|
||||
else {
|
||||
result.add(0, JsLiteral.NULL);
|
||||
result.add(0, JsLiteral.NULL)
|
||||
}
|
||||
}
|
||||
|
||||
removeLastUndefinedArguments(result);
|
||||
return new ArgumentsInfo(result, hasSpreadOperator, cachedReceiver);
|
||||
removeLastUndefinedArguments(result)
|
||||
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