JS backend: Use new call translator in CallExpressionTranslator and move invoke intrinsic to FunctionCallCases

This commit is contained in:
Erokhin Stanislav
2013-12-27 17:33:24 +04:00
parent a1edc0368a
commit 4617e730d6
5 changed files with 31 additions and 137 deletions
@@ -19,9 +19,7 @@ package org.jetbrains.k2js.translate.intrinsic.functions.factories;
import com.google.dart.compiler.backend.js.ast.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetQualifiedExpression;
@@ -31,12 +29,9 @@ import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.lang.types.lang.PrimitiveType;
import org.jetbrains.k2js.translate.context.Namer;
import org.jetbrains.k2js.translate.context.TranslationContext;
import org.jetbrains.k2js.translate.intrinsic.functions.basic.FunctionIntrinsic;
import org.jetbrains.k2js.translate.intrinsic.functions.patterns.DescriptorPredicate;
import org.jetbrains.k2js.translate.intrinsic.functions.patterns.NamePredicate;
import org.jetbrains.k2js.translate.reference.CallTranslator;
import org.jetbrains.k2js.translate.utils.AnnotationsUtils;
@@ -47,7 +42,6 @@ import java.util.List;
import static org.jetbrains.k2js.translate.intrinsic.functions.basic.FunctionIntrinsic.CallParametersAwareFunctionIntrinsic;
import static org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternBuilder.pattern;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.generateInvocationArguments;
public final class TopLevelFIF extends CompositeFIF {
@NotNull
@@ -139,46 +133,6 @@ public final class TopLevelFIF extends CompositeFIF {
add(pattern("String|Boolean|Char|Number.equals"), EQUALS);
add(pattern("jet", "arrayOfNulls"), new KotlinFunctionIntrinsic("nullArray"));
add(pattern("jet", "iterator").receiverExists(), RETURN_RECEIVER_INTRINSIC);
add(new DescriptorPredicate() {
@Override
public boolean apply(@NotNull FunctionDescriptor descriptor) {
if (!descriptor.getName().asString().equals("invoke")) {
return false;
}
int parameterCount = descriptor.getValueParameters().size();
DeclarationDescriptor fun = descriptor.getContainingDeclaration();
return fun == (descriptor.getReceiverParameter() == null
? KotlinBuiltIns.getInstance().getFunction(parameterCount)
: KotlinBuiltIns.getInstance().getExtensionFunction(parameterCount));
}
}, new CallParametersAwareFunctionIntrinsic() {
@NotNull
@Override
public JsExpression apply(
@NotNull CallTranslator callTranslator,
@NotNull List<JsExpression> arguments,
@NotNull TranslationContext context
) {
JsExpression thisExpression = callTranslator.getCallParameters().getThisObject();
JsExpression functionReference = callTranslator.getCallParameters().getFunctionReference();
if (thisExpression == null) {
return new JsInvocation(functionReference, arguments);
}
else if (callTranslator.getResolvedCall().getReceiverArgument().exists()) {
return callTranslator.extensionFunctionCall(false);
}
else {
CallableDescriptor descriptor = callTranslator.getResolvedCall().getCandidateDescriptor();
if (descriptor.getName().asString().equals("invoke") &&
functionReference instanceof JsNameRef &&
((JsNameRef) functionReference).getIdent().startsWith("invoke")) {
return callTranslator.explicitInvokeCall();
}
return new JsInvocation(Namer.getFunctionCallRef(functionReference), generateInvocationArguments(thisExpression, arguments));
}
}
}
);
add(pattern("jet", "Map", "get").checkOverridden(), NATIVE_MAP_GET);
add(pattern("js", "set").receiverExists(), NATIVE_MAP_SET);
@@ -19,6 +19,7 @@ package org.jetbrains.k2js.translate.reference;
import com.google.dart.compiler.backend.js.ast.JsExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.psi.JetCallExpression;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.k2js.translate.context.TranslationContext;
@@ -31,7 +32,7 @@ public abstract class AbstractCallExpressionTranslator extends AbstractTranslato
@NotNull
protected final JetCallExpression expression;
@NotNull
protected final ResolvedCall<?> resolvedCall;
protected final ResolvedCall<? extends FunctionDescriptor> resolvedCall;
@Nullable
protected final JsExpression receiver;
@NotNull
@@ -17,23 +17,10 @@
package org.jetbrains.k2js.translate.reference;
import com.google.dart.compiler.backend.js.ast.JsExpression;
import com.google.dart.compiler.backend.js.ast.JsName;
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.psi.JetCallExpression;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.util.ExpressionAsFunctionDescriptor;
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 static org.jetbrains.k2js.translate.utils.PsiUtils.getCallee;
public final class CallExpressionTranslator extends AbstractCallExpressionTranslator {
@@ -48,88 +35,14 @@ public final class CallExpressionTranslator extends AbstractCallExpressionTransl
return (new CallExpressionTranslator(expression, receiver, callType, context)).translate();
}
private final boolean isNativeFunctionCall;
private CallArgumentTranslator.ArgumentsInfo argumentsInfo = null;
private JsExpression translatedReceiver = null;
private JsExpression translatedCallee = null;
private CallExpressionTranslator(@NotNull JetCallExpression expression,
@Nullable JsExpression receiver,
@NotNull CallType callType, @NotNull TranslationContext context) {
super(expression, receiver, callType, context);
this.isNativeFunctionCall = AnnotationsUtils.isNativeObject(resolvedCall.getCandidateDescriptor());
}
@NotNull
private JsExpression translate() {
prepareToBuildCall();
return CallBuilder.build(context())
.receiver(translatedReceiver)
.callee(translatedCallee)
.args(argumentsInfo.getTranslateArguments())
.resolvedCall(getResolvedCall())
.type(callType)
.translate();
return ReferencePackage.buildCall(context(), resolvedCall, receiver);
}
private void prepareToBuildCall() {
argumentsInfo = CallArgumentTranslator.translate(resolvedCall, receiver, context());
translatedReceiver = getReceiver();
translatedCallee = getCalleeExpression();
}
@NotNull
private ResolvedCall<?> getResolvedCall() {
if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
return ((VariableAsFunctionResolvedCall) resolvedCall).getFunctionCall();
}
return resolvedCall;
}
@Nullable
private JsExpression getReceiver() {
assert argumentsInfo != null : "the results of this function depends on the argumentsInfo";
if (receiver == null) {
return null;
}
if (argumentsInfo.getCachedReceiver() != null) {
return argumentsInfo.getCachedReceiver().assignmentExpression();
}
return receiver;
}
@Nullable
private JsExpression getCalleeExpression() {
assert argumentsInfo != null : "the results of this function depends on the argumentsInfo";
if (isNativeFunctionCall && argumentsInfo.isHasSpreadOperator()) {
JsName functionName = context().getNameForDescriptor(resolvedCall.getCandidateDescriptor());
return new JsNameRef("apply", functionName.makeRef());
}
CallableDescriptor candidateDescriptor = resolvedCall.getCandidateDescriptor();
if (candidateDescriptor instanceof ExpressionAsFunctionDescriptor) {
return translateExpressionAsFunction();
}
if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
return translateVariableForVariableAsFunctionResolvedCall();
}
return null;
}
@NotNull
//TODO: looks hacky and should be modified soon
private JsExpression translateVariableForVariableAsFunctionResolvedCall() {
JetExpression callee = PsiUtils.getCallee(expression);
if (callee instanceof JetSimpleNameExpression) {
return ReferenceTranslator.getAccessTranslator((JetSimpleNameExpression) callee, receiver, context()).translateAsGet();
}
assert receiver != null;
return Translation.translateAsExpression(callee, context());
}
@NotNull
private JsExpression translateExpressionAsFunction() {
return Translation.translateAsExpression(getCallee(expression), context());
}
}
@@ -97,6 +97,28 @@ class DelegateFunctionIntrinsic(callInfo: FunctionCallInfo) : FunctionCallCase(c
}
}
class InvokeIntrinsic(callInfo: FunctionCallInfo) : FunctionCallCase(callInfo) {
class object {
fun canApply(callInfo: FunctionCallInfo): Boolean {
if (!callInfo.callableDescriptor.getName().asString().equals("invoke"))
return false
val parameterCount = callInfo.callableDescriptor.getValueParameters().size()
val funDeclaration = callInfo.callableDescriptor.getContainingDeclaration()
return funDeclaration == ((if (callInfo.callableDescriptor.getReceiverParameter() == null)
KotlinBuiltIns.getInstance().getFunction(parameterCount)
else
KotlinBuiltIns.getInstance().getExtensionFunction(parameterCount)))
}
}
override fun FunctionCallInfo.thisObject(): JsExpression {
return JsInvocation(thisObject, argumentsInfo.getTranslateArguments())
}
override fun FunctionCallInfo.bothReceivers(): JsExpression {
return JsInvocation(thisObject, addReceiverToArgs(receiverObject!!, argumentsInfo.getTranslateArguments()))
}
}
class ConstructorCallCase(callInfo: FunctionCallInfo) : FunctionCallCase(callInfo) {
override fun FunctionCallInfo.noReceivers(): JsExpression {
return JsNew(context.getQualifiedReference(callableDescriptor), argumentsInfo.getTranslateArguments())
@@ -138,6 +160,7 @@ fun createFunctionCases(): CallCaseDispatcher<FunctionCallCase, FunctionCallInfo
val caseDispatcher = CallCaseDispatcher<FunctionCallCase, FunctionCallInfo>()
caseDispatcher.addCase(::ExpressionAsFunctionDescriptorIntrinsic) {ExpressionAsFunctionDescriptorIntrinsic.canApply(it)}
caseDispatcher.addCase(::InvokeIntrinsic) {InvokeIntrinsic.canApply(it)}
caseDispatcher.addCase { DelegateFunctionIntrinsic(it).intrinsic() }
@@ -156,10 +156,13 @@ public final class BindingUtils {
}
@NotNull
public static ResolvedCall<?> getResolvedCallForCallExpression(@NotNull BindingContext context,
public static ResolvedCall<? extends FunctionDescriptor> getResolvedCallForCallExpression(@NotNull BindingContext context,
@NotNull JetCallExpression expression) {
JetExpression calleeExpression = PsiUtils.getCallee(expression);
return getResolvedCall(context, calleeExpression);
ResolvedCall<?> resolvedCall = getResolvedCall(context, calleeExpression);
assert resolvedCall.getResultingDescriptor() instanceof FunctionDescriptor
: message(expression, "ResolvedCall for this expression must be ResolvedCall<? extends FunctionDescriptor>");
return (ResolvedCall<? extends FunctionDescriptor>) resolvedCall;
}
public static boolean isVariableReassignment(@NotNull BindingContext context, @NotNull JetExpression expression) {