001 /*
002 * Copyright 2010-2013 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.k2js.translate.reference;
018
019 import com.google.dart.compiler.backend.js.ast.JsExpression;
020 import com.google.dart.compiler.backend.js.ast.JsNameRef;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
024 import org.jetbrains.jet.lang.psi.JetCallExpression;
025 import org.jetbrains.jet.lang.psi.JetExpression;
026 import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
027 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
028 import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
029 import org.jetbrains.jet.lang.resolve.calls.util.ExpressionAsFunctionDescriptor;
030 import org.jetbrains.k2js.translate.context.TranslationContext;
031 import org.jetbrains.k2js.translate.general.Translation;
032 import org.jetbrains.k2js.translate.utils.AnnotationsUtils;
033 import org.jetbrains.k2js.translate.utils.PsiUtils;
034
035 import static org.jetbrains.k2js.translate.utils.PsiUtils.getCallee;
036
037 public final class CallExpressionTranslator extends AbstractCallExpressionTranslator {
038
039 @NotNull
040 public static JsExpression translate(@NotNull JetCallExpression expression,
041 @Nullable JsExpression receiver,
042 @NotNull CallType callType,
043 @NotNull TranslationContext context) {
044 if (InlinedCallExpressionTranslator.shouldBeInlined(expression, context)) {
045 return InlinedCallExpressionTranslator.translate(expression, receiver, callType, context);
046 }
047 return (new CallExpressionTranslator(expression, receiver, callType, context)).translate();
048 }
049
050 private final boolean isNativeFunctionCall;
051 private CallArgumentTranslator.ArgumentsInfo argumentsInfo = null;
052 private JsExpression translatedReceiver = null;
053 private JsExpression translatedCallee = null;
054
055 private CallExpressionTranslator(@NotNull JetCallExpression expression,
056 @Nullable JsExpression receiver,
057 @NotNull CallType callType, @NotNull TranslationContext context) {
058 super(expression, receiver, callType, context);
059 this.isNativeFunctionCall = AnnotationsUtils.isNativeObject(resolvedCall.getCandidateDescriptor());
060 }
061
062 @NotNull
063 private JsExpression translate() {
064 prepareToBuildCall();
065
066 return CallBuilder.build(context())
067 .receiver(translatedReceiver)
068 .callee(translatedCallee)
069 .args(argumentsInfo.getTranslateArguments())
070 .resolvedCall(getResolvedCall())
071 .type(callType)
072 .translate();
073 }
074
075 private void prepareToBuildCall() {
076 argumentsInfo = CallArgumentTranslator.translate(resolvedCall, receiver, context());
077 translatedReceiver = getReceiver();
078 translatedCallee = getCalleeExpression();
079 }
080
081 @NotNull
082 private ResolvedCall<?> getResolvedCall() {
083 if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
084 return ((VariableAsFunctionResolvedCall) resolvedCall).getFunctionCall();
085 }
086 return resolvedCall;
087 }
088
089 @Nullable
090 private JsExpression getReceiver() {
091 assert argumentsInfo != null : "the results of this function depends on the argumentsInfo";
092 if (receiver == null) {
093 return null;
094 }
095 if (argumentsInfo.getCachedReceiver() != null) {
096 return argumentsInfo.getCachedReceiver().assignmentExpression();
097 }
098 return receiver;
099 }
100
101 @Nullable
102 private JsExpression getCalleeExpression() {
103 assert argumentsInfo != null : "the results of this function depends on the argumentsInfo";
104 if (isNativeFunctionCall && argumentsInfo.isHasSpreadOperator()) {
105 String functionName = resolvedCall.getCandidateDescriptor().getOriginal().getName().getIdentifier();
106 return new JsNameRef("apply", functionName);
107 }
108 CallableDescriptor candidateDescriptor = resolvedCall.getCandidateDescriptor();
109 if (candidateDescriptor instanceof ExpressionAsFunctionDescriptor) {
110 return translateExpressionAsFunction();
111 }
112 if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
113 return translateVariableForVariableAsFunctionResolvedCall();
114 }
115 return null;
116 }
117
118 @NotNull
119 //TODO: looks hacky and should be modified soon
120 private JsExpression translateVariableForVariableAsFunctionResolvedCall() {
121 JetExpression callee = PsiUtils.getCallee(expression);
122 if (callee instanceof JetSimpleNameExpression) {
123 return ReferenceTranslator.getAccessTranslator((JetSimpleNameExpression) callee, receiver, context()).translateAsGet();
124 }
125 assert receiver != null;
126 return Translation.translateAsExpression(callee, context());
127 }
128
129 @NotNull
130 private JsExpression translateExpressionAsFunction() {
131 return Translation.translateAsExpression(getCallee(expression), context());
132 }
133
134 }