From dae791d7b18e7ccc202ce2046bf1e9146337cc3b Mon Sep 17 00:00:00 2001 From: Erokhin Stanislav Date: Fri, 20 Sep 2013 20:09:31 +0400 Subject: [PATCH] JS backend: refactoring: extract CallArgumentTranslator from AbstractCallExpressionTranslator and CallExpressionTranslator --- .../AbstractCallExpressionTranslator.java | 59 +----- .../reference/CallArgumentTranslator.java | 193 ++++++++++++++++++ .../reference/CallExpressionTranslator.java | 83 +------- .../InlinedCallExpressionTranslator.java | 8 +- 4 files changed, 206 insertions(+), 137 deletions(-) create mode 100644 js/js.translator/src/org/jetbrains/k2js/translate/reference/CallArgumentTranslator.java diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/AbstractCallExpressionTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/AbstractCallExpressionTranslator.java index 85769e5278d..a31778088b2 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/AbstractCallExpressionTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/AbstractCallExpressionTranslator.java @@ -16,25 +16,14 @@ package org.jetbrains.k2js.translate.reference; -import com.google.dart.compiler.backend.js.ast.JsArrayLiteral; import com.google.dart.compiler.backend.js.ast.JsExpression; -import com.intellij.util.SmartList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.psi.JetCallExpression; -import org.jetbrains.jet.lang.psi.JetExpression; -import org.jetbrains.jet.lang.psi.ValueArgument; -import org.jetbrains.jet.lang.resolve.calls.model.*; +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.general.AbstractTranslator; -import org.jetbrains.k2js.translate.general.Translation; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import static org.jetbrains.k2js.translate.utils.BindingUtils.getDefaultArgument; import static org.jetbrains.k2js.translate.utils.BindingUtils.getResolvedCallForCallExpression; public abstract class AbstractCallExpressionTranslator extends AbstractTranslator { @@ -58,50 +47,4 @@ public abstract class AbstractCallExpressionTranslator extends AbstractTranslato this.callType = type; } - protected abstract boolean shouldWrapVarargInArray(); - - protected void translateSingleArgument( - @NotNull ResolvedValueArgument actualArgument, - @NotNull ValueParameterDescriptor parameterDescriptor, - @NotNull List result - ) { - List valueArguments = actualArgument.getArguments(); - if (actualArgument instanceof VarargValueArgument) { - translateVarargArgument(valueArguments, result); - } - else if (actualArgument instanceof DefaultValueArgument) { - JetExpression defaultArgument = getDefaultArgument(bindingContext(), parameterDescriptor); - result.add(Translation.translateAsExpression(defaultArgument, context())); - } - else { - assert actualArgument instanceof ExpressionValueArgument; - assert valueArguments.size() == 1; - JetExpression argumentExpression = valueArguments.get(0).getArgumentExpression(); - assert argumentExpression != null; - result.add(Translation.translateAsExpression(argumentExpression, context())); - } - } - - private void translateVarargArgument(@NotNull List arguments, @NotNull List result) { - if (arguments.isEmpty()) { - if (shouldWrapVarargInArray()) { - result.add(new JsArrayLiteral(Collections.emptyList())); - } - return; - } - - List list; - if (shouldWrapVarargInArray()) { - list = arguments.size() == 1 ? new SmartList() : new ArrayList(arguments.size()); - result.add(new JsArrayLiteral(list)); - } - else { - list = result; - } - for (ValueArgument argument : arguments) { - JetExpression argumentExpression = argument.getArgumentExpression(); - assert argumentExpression != null; - list.add(Translation.translateAsExpression(argumentExpression, context())); - } - } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallArgumentTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallArgumentTranslator.java new file mode 100644 index 00000000000..dbee301cc64 --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallArgumentTranslator.java @@ -0,0 +1,193 @@ +/* + * Copyright 2010-2013 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.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.jet.lang.descriptors.ValueParameterDescriptor; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.psi.ValueArgument; +import org.jetbrains.jet.lang.resolve.calls.model.*; +import org.jetbrains.k2js.translate.context.TemporaryConstVariable; +import org.jetbrains.k2js.translate.context.TranslationContext; +import org.jetbrains.k2js.translate.general.AbstractTranslator; +import org.jetbrains.k2js.translate.general.Translation; +import org.jetbrains.k2js.translate.utils.AnnotationsUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.jetbrains.k2js.translate.utils.BindingUtils.getDefaultArgument; + +public class CallArgumentTranslator extends AbstractTranslator { + + @NotNull + public static ArgumentsInfo translate( + @NotNull ResolvedCall resolvedCall, + @Nullable JsExpression receiver, + @NotNull TranslationContext context + ) { + CallArgumentTranslator argumentTranslator = new CallArgumentTranslator(resolvedCall, receiver, context); + return argumentTranslator.translate(); + } + + 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 static void translateSingleArgument( + @NotNull ResolvedValueArgument actualArgument, + @NotNull ValueParameterDescriptor parameterDescriptor, + @NotNull List result, + @NotNull TranslationContext context, + boolean shouldWrapVarargInArray + ) { + List valueArguments = actualArgument.getArguments(); + if (actualArgument instanceof VarargValueArgument) { + translateVarargArgument(valueArguments, result, context, shouldWrapVarargInArray); + } + else if (actualArgument instanceof DefaultValueArgument) { + JetExpression defaultArgument = getDefaultArgument(context.bindingContext(), parameterDescriptor); + result.add(Translation.translateAsExpression(defaultArgument, context)); + } + else { + assert actualArgument instanceof ExpressionValueArgument; + assert valueArguments.size() == 1; + JetExpression argumentExpression = valueArguments.get(0).getArgumentExpression(); + assert argumentExpression != null; + result.add(Translation.translateAsExpression(argumentExpression, context)); + } + } + + private static void translateVarargArgument( + @NotNull List arguments, + @NotNull List result, + @NotNull TranslationContext context, + boolean shouldWrapVarargInArray + ) { + if (arguments.isEmpty()) { + if (shouldWrapVarargInArray) { + result.add(new JsArrayLiteral(Collections.emptyList())); + } + return; + } + + List list; + if (shouldWrapVarargInArray) { + list = arguments.size() == 1 ? new SmartList() : new ArrayList(arguments.size()); + result.add(new JsArrayLiteral(list)); + } + else { + list = result; + } + for (ValueArgument argument : arguments) { + JetExpression argumentExpression = argument.getArgumentExpression(); + assert argumentExpression != null; + list.add(Translation.translateAsExpression(argumentExpression, context)); + } + } + + @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 ArgumentsInfo translate() { + List valueParameters = resolvedCall.getResultingDescriptor().getValueParameters(); + if (valueParameters.isEmpty()) { + return new ArgumentsInfo(Collections.emptyList(), false, null); + } + boolean hasSpreadOperator = false; + TemporaryConstVariable cachedReceiver = null; + + List result = new ArrayList(valueParameters.size()); + List valueArgumentsByIndex = resolvedCall.getValueArgumentsByIndex(); + List argsBeforeVararg = null; + for (ValueParameterDescriptor parameterDescriptor : valueParameters) { + ResolvedValueArgument actualArgument = valueArgumentsByIndex.get(parameterDescriptor.getIndex()); + + if (actualArgument instanceof VarargValueArgument) { + assert !hasSpreadOperator; + + List arguments = actualArgument.getArguments(); + hasSpreadOperator = arguments.size() == 1 && arguments.get(0).getSpreadElement() != null; + + if (isNativeFunctionCall && hasSpreadOperator) { + argsBeforeVararg = result; + result = new SmartList(); + } + } + + translateSingleArgument(actualArgument, parameterDescriptor, result, context(), !isNativeFunctionCall && !hasSpreadOperator); + } + + if (isNativeFunctionCall && hasSpreadOperator) { + if (!argsBeforeVararg.isEmpty()) { + JsInvocation concatArguments = new JsInvocation(new JsNameRef("concat", new JsArrayLiteral(argsBeforeVararg)), result); + result = new SmartList(concatArguments); + } + + if (receiver != null) { + cachedReceiver = context().getOrDeclareTemporaryConstVariable(receiver); + result.add(0, cachedReceiver.reference()); + } + else { + result.add(0, JsLiteral.NULL); + } + } + return new ArgumentsInfo(result, hasSpreadOperator, cachedReceiver); + } + +} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallExpressionTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallExpressionTranslator.java index 91dbf318c89..f8754905e84 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallExpressionTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallExpressionTranslator.java @@ -16,31 +16,22 @@ package org.jetbrains.k2js.translate.reference; -import com.google.dart.compiler.backend.js.ast.*; -import com.intellij.util.SmartList; +import com.google.dart.compiler.backend.js.ast.JsExpression; +import com.google.dart.compiler.backend.js.ast.JsNameRef; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.CallableDescriptor; -import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.psi.JetCallExpression; import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; -import org.jetbrains.jet.lang.psi.ValueArgument; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; -import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument; -import org.jetbrains.jet.lang.resolve.calls.model.VarargValueArgument; import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall; import org.jetbrains.jet.lang.resolve.calls.util.ExpressionAsFunctionDescriptor; -import org.jetbrains.k2js.translate.context.TemporaryConstVariable; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.general.Translation; import org.jetbrains.k2js.translate.utils.AnnotationsUtils; import org.jetbrains.k2js.translate.utils.PsiUtils; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - import static org.jetbrains.k2js.translate.utils.PsiUtils.getCallee; public final class CallExpressionTranslator extends AbstractCallExpressionTranslator { @@ -57,9 +48,7 @@ public final class CallExpressionTranslator extends AbstractCallExpressionTransl } private final boolean isNativeFunctionCall; - private boolean hasSpreadOperator = false; - private TemporaryConstVariable cachedReceiver = null; - private List translatedArguments = null; + private CallArgumentTranslator.ArgumentsInfo argumentsInfo = null; private JsExpression translatedReceiver = null; private JsExpression translatedCallee = null; @@ -77,14 +66,14 @@ public final class CallExpressionTranslator extends AbstractCallExpressionTransl return CallBuilder.build(context()) .receiver(translatedReceiver) .callee(translatedCallee) - .args(translatedArguments) + .args(argumentsInfo.getTranslateArguments()) .resolvedCall(getResolvedCall()) .type(callType) .translate(); } private void prepareToBuildCall() { - translatedArguments = translateArguments(); + argumentsInfo = CallArgumentTranslator.translate(resolvedCall, receiver, context()); translatedReceiver = getReceiver(); translatedCallee = getCalleeExpression(); } @@ -99,20 +88,20 @@ public final class CallExpressionTranslator extends AbstractCallExpressionTransl @Nullable private JsExpression getReceiver() { - assert translatedArguments != null : "the results of this function depends on the results of translateArguments()"; + assert argumentsInfo != null : "the results of this function depends on the argumentsInfo"; if (receiver == null) { return null; } - if (cachedReceiver != null) { - return cachedReceiver.assignmentExpression(); + if (argumentsInfo.getCachedReceiver() != null) { + return argumentsInfo.getCachedReceiver().assignmentExpression(); } return receiver; } @Nullable private JsExpression getCalleeExpression() { - assert translatedArguments != null : "the results of this function depends on the results of translateArguments()"; - if (isNativeFunctionCall && hasSpreadOperator) { + assert argumentsInfo != null : "the results of this function depends on the argumentsInfo"; + if (isNativeFunctionCall && argumentsInfo.isHasSpreadOperator()) { String functionName = resolvedCall.getCandidateDescriptor().getOriginal().getName().getIdentifier(); return new JsNameRef("apply", functionName); } @@ -142,56 +131,4 @@ public final class CallExpressionTranslator extends AbstractCallExpressionTransl return Translation.translateAsExpression(getCallee(expression), context()); } - @NotNull - private List translateArguments() { - List valueParameters = resolvedCall.getResultingDescriptor().getValueParameters(); - if (valueParameters.isEmpty()) { - return Collections.emptyList(); - } - - List result = new ArrayList(valueParameters.size()); - List valueArgumentsByIndex = resolvedCall.getValueArgumentsByIndex(); - List argsBeforeVararg = null; - for (ValueParameterDescriptor parameterDescriptor : valueParameters) { - ResolvedValueArgument actualArgument = valueArgumentsByIndex.get(parameterDescriptor.getIndex()); - - if (actualArgument instanceof VarargValueArgument) { - assert !hasSpreadOperator; - - List arguments = actualArgument.getArguments(); - hasSpreadOperator = arguments.size() == 1 && arguments.get(0).getSpreadElement() != null; - - if (isNativeFunctionCall && hasSpreadOperator) { - assert argsBeforeVararg == null; - argsBeforeVararg = result; - result = new SmartList(); - } - } - - translateSingleArgument(actualArgument, parameterDescriptor, result); - } - - if (isNativeFunctionCall && hasSpreadOperator) { - assert argsBeforeVararg != null; - if (!argsBeforeVararg.isEmpty()) { - JsInvocation concatArguments = new JsInvocation(new JsNameRef("concat", new JsArrayLiteral(argsBeforeVararg)), result); - result = new SmartList(concatArguments); - } - - if (receiver != null) { - cachedReceiver = context().getOrDeclareTemporaryConstVariable(receiver); - result.add(0, cachedReceiver.reference()); - } - else { - result.add(0, JsLiteral.NULL); - } - } - - return result; - } - - @Override - public boolean shouldWrapVarargInArray() { - return !isNativeFunctionCall && !hasSpreadOperator; - } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/InlinedCallExpressionTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/InlinedCallExpressionTranslator.java index bb90d730f6b..a5aa3fb9618 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/InlinedCallExpressionTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/InlinedCallExpressionTranslator.java @@ -40,6 +40,7 @@ import org.jetbrains.k2js.translate.utils.mutator.Mutator; import java.util.List; import java.util.Map; +import static org.jetbrains.k2js.translate.reference.CallArgumentTranslator.translateSingleArgument; import static org.jetbrains.k2js.translate.reference.CallParametersResolver.resolveCallParameters; import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionForDescriptor; import static org.jetbrains.k2js.translate.utils.FunctionBodyTranslator.translateFunctionBody; @@ -154,16 +155,11 @@ public final class InlinedCallExpressionTranslator extends AbstractCallExpressio private JsExpression translateArgument(@NotNull ValueParameterDescriptor parameterDescriptor, @NotNull ResolvedValueArgument actualArgument) { List result = new SmartList(); - translateSingleArgument(actualArgument, parameterDescriptor, result); + translateSingleArgument(actualArgument, parameterDescriptor, result, context(), true); assert result.size() == 1 : "We always wrap varargs in kotlin calls."; return result.get(0); } - @Override - public boolean shouldWrapVarargInArray() { - return true; - } - private static final class InlineFunctionMutator implements Mutator { @NotNull