From f0c2aa9eb21f71f8a6643c6c3a47dd3b6bbf2e3a Mon Sep 17 00:00:00 2001 From: Alexey Tsvetkov Date: Mon, 16 Mar 2015 19:59:25 +0300 Subject: [PATCH] JS: converted CallArgumentTranslator to Kotlin --- .../reference/CallArgumentTranslator.kt | 537 ++++++++---------- 1 file changed, 243 insertions(+), 294 deletions(-) diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt index 8a040a8f347..6185fbe8613 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt @@ -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, 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 translateArguments; - private final boolean hasSpreadOperator; - private final TemporaryConstVariable cachedReceiver; - - public ArgumentsInfo(List arguments, boolean operator, TemporaryConstVariable receiver) { - translateArguments = arguments; - hasSpreadOperator = operator; - cachedReceiver = receiver; - } - - @NotNull - public List 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 result, - @NotNull TranslationContext context - ) { - List 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 arguments, - @NotNull List result, - @NotNull TranslationContext context, - boolean shouldWrapVarargInArray - ) { - if (arguments.isEmpty()) { - if (shouldWrapVarargInArray) { - result.add(new JsArrayLiteral(Collections.emptyList())); - } - return ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT; - } + private val isNativeFunctionCall: Boolean - List list; - if (shouldWrapVarargInArray) { - list = arguments.size() == 1 ? new SmartList() : new ArrayList(arguments.size()); - } - else { - list = result; - } - - ArgumentsKind resultKind = translateValueArguments(arguments, list, context); - - if (shouldWrapVarargInArray) { - List 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 arguments, - @NotNull List list, - @NotNull TranslationContext context - ) { - ArgumentsKind resultKind = ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT; - List argContexts = new SmartList(); - 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 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 prepareConcatArguments(@NotNull List arguments, @NotNull List 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 concatArguments = new SmartList(); - List lastArrayContent = new SmartList(); - - 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(); + private fun removeLastUndefinedArguments(result: List) { + 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 argExpressions, - @NotNull List argContexts, - @NotNull TranslationContext context, - boolean toTmpVars - ) { - for(int i=0; i 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 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 valueParameters = resolvedCall.getResultingDescriptor().getValueParameters(); + private fun translate(): ArgumentsInfo { + val valueParameters = resolvedCall.getResultingDescriptor().getValueParameters() if (valueParameters.isEmpty()) { - return new ArgumentsInfo(Collections.emptyList(), false, null); + return ArgumentsInfo(listOf(), false, null) } - boolean hasSpreadOperator = false; - TemporaryConstVariable cachedReceiver = null; + var hasSpreadOperator = false + var cachedReceiver: TemporaryConstVariable? = null - List result = new ArrayList(valueParameters.size()); - List valueArgumentsByIndex = resolvedCall.getValueArgumentsByIndex(); + var result: MutableList = 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 argsBeforeVararg = null; - boolean argumentsShouldBeExtractedToTmpVars = false; - List argContexts = new SmartList(); - ArgumentsKind kind = ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT; - List concatArguments = null; + var argsBeforeVararg: List? = null + var argumentsShouldBeExtractedToTmpVars = false + val argContexts = SmartList() + var kind = ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT + var concatArguments: MutableList? = 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 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(); - List list = new SmartList(); - kind = translateValueArguments(arguments, list, argContext); - concatArguments = prepareConcatArguments(arguments, list); + argsBeforeVararg = result + result = SmartList() + val list = SmartList() + 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(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, 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, result: MutableList, context: TranslationContext, shouldWrapVarargInArray: Boolean): ArgumentsKind { + if (arguments.isEmpty()) { + if (shouldWrapVarargInArray) { + result.add(JsArrayLiteral(listOf())) + } + return ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT + } + + val list: MutableList + if (shouldWrapVarargInArray) { + list = if (arguments.size() == 1) SmartList() else ArrayList(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, list: MutableList, context: TranslationContext): ArgumentsKind { + var resultKind = ArgumentsKind.HAS_NOT_EMPTY_EXPRESSION_ARGUMENT + val argContexts = SmartList() + 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 { + 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, list: List): MutableList { + 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() + var lastArrayContent: MutableList = 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() + } + else { + concatArguments.add(expressionArgument) + } + } + else { + lastArrayContent.add(expressionArgument) + } + } + if (lastArrayContent.size() > 0) { + concatArguments.add(JsArrayLiteral(lastArrayContent)) + } + + return concatArguments + } + + private fun extractArguments(argExpressions: MutableList, argContexts: List, 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) + } + } + } } }