JS backend: Dropped old CallTranslator

This commit is contained in:
Erokhin Stanislav
2013-12-27 17:47:06 +04:00
parent 2d50858289
commit 2f1b44ed9e
5 changed files with 3 additions and 597 deletions
@@ -1,134 +0,0 @@
/*
* 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.JsExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor;
import org.jetbrains.jet.lang.resolve.BindingTraceContext;
import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
import org.jetbrains.jet.lang.resolve.calls.model.MutableDataFlowInfoForArguments;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallImpl;
import org.jetbrains.jet.lang.resolve.calls.tasks.ExplicitReceiverKind;
import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionCandidate;
import org.jetbrains.jet.lang.resolve.calls.tasks.TracingStrategy;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.k2js.translate.context.TranslationContext;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public final class CallBuilder {
public static CallBuilder build(@NotNull TranslationContext context) {
return new CallBuilder(context);
}
@NotNull
private final TranslationContext context;
@Nullable
private /*var*/ JsExpression receiver = null;
@NotNull
private List<JsExpression> args = Collections.emptyList();
@NotNull
private /*var*/ CallType callType = CallType.NORMAL;
@Nullable
private /*var*/ ResolvedCall<?> resolvedCall = null;
@Nullable
private /*var*/ CallableDescriptor descriptor = null;
@Nullable
private /*var*/ JsExpression callee = null;
private CallBuilder(@NotNull TranslationContext context) {
this.context = context;
}
@NotNull
public CallBuilder receiver(@Nullable JsExpression receiver) {
this.receiver = receiver;
return this;
}
@NotNull
public CallBuilder args(@NotNull List<JsExpression> args) {
assert this.args == Collections.EMPTY_LIST;
this.args = args;
return this;
}
@NotNull
public CallBuilder args(@NotNull JsExpression... args) {
return args(Arrays.asList(args));
}
@NotNull
public CallBuilder descriptor(@NotNull CallableDescriptor descriptor) {
this.descriptor = descriptor;
return this;
}
@NotNull
public CallBuilder callee(@Nullable JsExpression callee) {
this.callee = callee;
return this;
}
@NotNull
public CallBuilder resolvedCall(@NotNull ResolvedCall<?> call) {
this.resolvedCall = call;
return this;
}
@NotNull
public CallBuilder type(@NotNull CallType type) {
this.callType = type;
return this;
}
@NotNull
private CallTranslator finish() {
if (resolvedCall == null) {
assert descriptor != null;
resolvedCall = ResolvedCallImpl.create(ResolutionCandidate.create(descriptor, safeGetValue(descriptor.getExpectedThisObject()),
safeGetValue(descriptor.getReceiverParameter()),
ExplicitReceiverKind.THIS_OBJECT, false),
TemporaryBindingTrace.create(new BindingTraceContext(), "trace to resolve call (in js)"),
TracingStrategy.EMPTY,
MutableDataFlowInfoForArguments.WITHOUT_ARGUMENTS_CHECK);
}
if (descriptor == null) {
descriptor = resolvedCall.getCandidateDescriptor().getOriginal();
}
assert resolvedCall != null;
return new CallTranslator(receiver, callee, args, resolvedCall, descriptor, callType, context);
}
@NotNull
private static ReceiverValue safeGetValue(@Nullable ReceiverParameterDescriptor descriptor) {
return descriptor == null ? ReceiverValue.NO_RECEIVER : descriptor.getValue();
}
@NotNull
public JsExpression translate() {
return finish().translate();
}
}
@@ -1,65 +0,0 @@
/*
* 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.JsExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public final class CallParameters {
@Nullable
private final JsExpression receiver;
@NotNull
private final JsExpression functionReference;
@Nullable
private final JsExpression thisObject;
public CallParameters(@Nullable JsExpression receiver,
@NotNull JsExpression functionReference,
@Nullable JsExpression thisObject) {
this.receiver = receiver;
this.functionReference = functionReference;
this.thisObject = thisObject;
}
@NotNull
public JsExpression getFunctionReference() {
return functionReference;
}
@Nullable
public JsExpression getThisObject() {
return thisObject;
}
@Nullable
public JsExpression getReceiver() {
return receiver;
}
@Nullable
public JsExpression getThisOrReceiverOrNull() {
if (thisObject == null) {
return receiver;
}
assert receiver == null;
return thisObject;
}
}
@@ -1,120 +0,0 @@
/*
* 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.JsExpression;
import com.google.dart.compiler.backend.js.ast.JsLiteral;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace;
import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ClassReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExtensionReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ThisReceiver;
import org.jetbrains.k2js.translate.context.TranslationContext;
import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getDeclarationDescriptorForReceiver;
public final class CallParametersResolver {
public static CallParameters resolveCallParameters(@Nullable JsExpression qualifier,
@Nullable JsExpression callee,
@NotNull CallableDescriptor descriptor,
@NotNull ResolvedCall<? extends CallableDescriptor> call,
@NotNull TranslationContext context) {
return (new CallParametersResolver(qualifier, callee, descriptor, call, context)).resolve();
}
// the actual qualifier for the call at the call site
@Nullable
private final JsExpression qualifier;
@Nullable
private final JsExpression callee;
@NotNull
private final CallableDescriptor descriptor;
@NotNull
private final TranslationContext context;
@NotNull
private final ResolvedCall<? extends CallableDescriptor> resolvedCall;
private final boolean isExtensionCall;
private CallParametersResolver(@Nullable JsExpression qualifier,
@Nullable JsExpression callee,
@NotNull CallableDescriptor descriptor,
@NotNull ResolvedCall<? extends CallableDescriptor> call,
@NotNull TranslationContext context) {
this.qualifier = qualifier;
this.callee = callee;
this.descriptor = descriptor;
this.context = context;
this.resolvedCall = call;
this.isExtensionCall = resolvedCall.getReceiverArgument().exists();
}
@NotNull
private CallParameters resolve() {
JsExpression receiver = isExtensionCall ? getExtensionFunctionCallReceiver() : null;
JsExpression functionReference = getFunctionReference();
JsExpression thisObject = getThisObject();
return new CallParameters(receiver, functionReference, thisObject);
}
@NotNull
private JsExpression getFunctionReference() {
if (callee != null) {
return callee;
}
if (!(resolvedCall instanceof VariableAsFunctionResolvedCall)) {
return ReferenceTranslator.translateAsLocalNameReference(descriptor, context);
}
ResolvedCallWithTrace<FunctionDescriptor> call = ((VariableAsFunctionResolvedCall) resolvedCall).getFunctionCall();
return CallBuilder.build(context).resolvedCall(call).translate();
}
@Nullable
private JsExpression getThisObject() {
if (qualifier != null && !isExtensionCall) {
return qualifier;
}
ReceiverValue thisObject = resolvedCall.getThisObject();
if (!thisObject.exists()) {
return null;
}
if (thisObject instanceof ClassReceiver) {
JsExpression ref = context.getAliasForDescriptor(((ClassReceiver) thisObject).getDeclarationDescriptor());
return ref == null ? JsLiteral.THIS : ref;
}
else if (thisObject instanceof ExtensionReceiver) {
return context.getAliasForDescriptor(getDeclarationDescriptorForReceiver(thisObject));
}
return resolvedCall.getReceiverArgument().exists() && resolvedCall.getExplicitReceiverKind().isThisObject() ? JsLiteral.THIS : null;
}
@NotNull
private JsExpression getExtensionFunctionCallReceiver() {
if (qualifier != null) {
return qualifier;
}
return context.getThisObject(((ThisReceiver) resolvedCall.getReceiverArgument()).getDeclarationDescriptor());
}
}
@@ -1,274 +0,0 @@
/*
* 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 org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.JetSuperExpression;
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.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.k2js.translate.context.Namer;
import org.jetbrains.k2js.translate.context.TranslationContext;
import org.jetbrains.k2js.translate.general.AbstractTranslator;
import org.jetbrains.k2js.translate.intrinsic.functions.basic.FunctionIntrinsic;
import org.jetbrains.k2js.translate.utils.AnnotationsUtils;
import org.jetbrains.k2js.translate.utils.ErrorReportingUtils;
import org.jetbrains.k2js.translate.utils.TranslationUtils;
import java.util.ArrayList;
import java.util.List;
import static org.jetbrains.k2js.translate.reference.CallParametersResolver.resolveCallParameters;
import static org.jetbrains.k2js.translate.utils.JsAstUtils.assignment;
import static org.jetbrains.k2js.translate.utils.JsAstUtils.setQualifier;
//TODO: write tests on calling backing fields as functions
public final class CallTranslator extends AbstractTranslator {
@NotNull
private final List<JsExpression> arguments;
@NotNull
private final ResolvedCall<?> resolvedCall;
@NotNull
private final CallableDescriptor descriptor;
@NotNull
private final CallType callType;
@NotNull
private final CallParameters callParameters;
/*package*/ CallTranslator(@Nullable JsExpression receiver, @Nullable JsExpression callee,
@NotNull List<JsExpression> arguments,
@NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall,
@NotNull CallableDescriptor descriptorToCall,
@NotNull CallType callType,
@NotNull TranslationContext context) {
super(context);
this.arguments = arguments;
this.resolvedCall = resolvedCall;
this.callType = callType;
this.descriptor = descriptorToCall;
this.callParameters = resolveCallParameters(receiver, callee, descriptor, resolvedCall, context);
}
@NotNull
public ResolvedCall<? extends CallableDescriptor> getResolvedCall() {
return resolvedCall;
}
@NotNull
public CallParameters getCallParameters() {
return callParameters;
}
@NotNull
/*package*/ JsExpression translate() {
JsExpression result = intrinsicInvocation();
if (result != null) {
return result;
}
if ((descriptor instanceof ConstructorDescriptor)) {
return createConstructorCallExpression(translateAsFunctionWithNoThisObject(descriptor));
}
if (resolvedCall.getReceiverArgument().exists()) {
if (AnnotationsUtils.isNativeObject(descriptor)) {
return nativeExtensionCall();
}
return extensionFunctionCall(!(descriptor instanceof ExpressionAsFunctionDescriptor));
}
if (isExpressionAsFunction()) {
return expressionAsFunctionCall();
}
if (isSuperInvocation()) {
return superMethodCall(getThisObjectOrQualifier());
}
return methodCall(getThisObjectOrQualifier());
}
private boolean isExpressionAsFunction() {
return descriptor instanceof ExpressionAsFunctionDescriptor ||
resolvedCall instanceof VariableAsFunctionResolvedCall;
}
@NotNull
private JsExpression expressionAsFunctionCall() {
return methodCall(null);
}
@Nullable
public JsExpression intrinsicInvocation() {
//if (descriptor instanceof FunctionDescriptor) {
// try {
// FunctionIntrinsic intrinsic = context().intrinsics().getFunctionIntrinsics().getIntrinsic((FunctionDescriptor) descriptor);
// if (intrinsic.exists()) {
// return intrinsic.apply(this, arguments, context());
// }
// }
// catch (RuntimeException e) {
// throw ErrorReportingUtils.reportErrorWithLocation(e, descriptor, bindingContext());
// }
//}
return null;
}
@NotNull
public HasArguments createConstructorCallExpression(@NotNull JsExpression constructorReference) {
return new JsNew(constructorReference, arguments);
}
@NotNull
private JsExpression translateAsFunctionWithNoThisObject(@NotNull DeclarationDescriptor descriptor) {
return ReferenceTranslator.translateAsFQReference(descriptor, context());
}
@NotNull
private JsExpression nativeExtensionCall() {
return methodCall(callParameters.getReceiver());
}
@NotNull
public JsExpression explicitInvokeCall() {
return callType.constructCall(callParameters.getThisObject(), new CallType.CallConstructor() {
@NotNull
@Override
public JsExpression construct(@Nullable JsExpression receiver) {
return new JsInvocation(receiver, arguments);
}
}, context());
}
@NotNull
public JsExpression extensionFunctionCall(final boolean useThis) {
return callType.constructCall(callParameters.getReceiver(), new CallType.CallConstructor() {
@NotNull
@Override
public JsExpression construct(@Nullable JsExpression receiver) {
assert receiver != null : "Could not be null for extensions";
JsExpression functionReference = callParameters.getFunctionReference();
if (useThis) {
setQualifier(functionReference, getThisObjectOrQualifier());
}
return new JsInvocation(callParameters.getFunctionReference(), generateCallArgumentList(receiver));
}
}, context());
}
@NotNull
private List<JsExpression> generateCallArgumentList(@NotNull JsExpression receiver) {
return TranslationUtils.generateInvocationArguments(receiver, arguments);
}
private boolean isSuperInvocation() {
ReceiverValue thisObject = resolvedCall.getThisObject();
return thisObject instanceof ExpressionReceiver && ((ExpressionReceiver) thisObject).getExpression() instanceof JetSuperExpression;
}
@NotNull
private JsExpression superMethodCall(@Nullable JsExpression receiver) {
return callType.constructCall(receiver, new CallType.CallConstructor() {
@NotNull
@Override
public JsExpression construct(@Nullable JsExpression receiver) {
assert receiver != null : "Receiver for superCall must be not null";
if (isDirectPropertyAccess()) {
return superPropertyAccess(receiver, getPropertyName());
}
JsExpression qualifiedCallee = getQualifiedCallee(Namer.getRefToPrototype(receiver));
qualifiedCallee = Namer.getFunctionCallRef(qualifiedCallee);
List<JsExpression> arguments = new ArrayList<JsExpression>(CallTranslator.this.arguments.size() + 1);
arguments.add(JsLiteral.THIS);
arguments.addAll(CallTranslator.this.arguments);
return new JsInvocation(qualifiedCallee, arguments);
}
}, context());
}
@NotNull
private JsStringLiteral getPropertyName() {
assert descriptor instanceof PropertyAccessorDescriptor;
String propertyName = ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty().getName().asString();
return context().program().getStringLiteral(propertyName);
}
@NotNull
private JsExpression superPropertyAccess(@NotNull JsExpression classRef, @NotNull JsStringLiteral propertyName) {
if (descriptor instanceof PropertyGetterDescriptor) {
assert arguments.isEmpty();
return new JsInvocation(context().namer().getCallGetProperty(), JsLiteral.THIS, classRef, propertyName);
} else {
assert descriptor instanceof PropertySetterDescriptor;
assert arguments.size() == 1;
return new JsInvocation(context().namer().getCallSetProperty(), JsLiteral.THIS, classRef, propertyName, arguments.get(0));
}
}
@NotNull
private JsExpression methodCall(@Nullable JsExpression receiver) {
return callType.constructCall(receiver, new CallType.CallConstructor() {
@NotNull
@Override
public JsExpression construct(@Nullable JsExpression receiver) {
JsExpression qualifiedCallee = getQualifiedCallee(receiver);
if (isDirectPropertyAccess()) {
return directPropertyAccess(qualifiedCallee);
}
return new JsInvocation(qualifiedCallee, arguments);
}
}, context());
}
@NotNull
private JsExpression directPropertyAccess(@NotNull JsExpression callee) {
if (descriptor instanceof PropertyGetterDescriptor) {
assert arguments.isEmpty();
return callee;
}
else {
assert descriptor instanceof PropertySetterDescriptor;
assert arguments.size() == 1;
return assignment(callee, arguments.get(0));
}
}
private boolean isDirectPropertyAccess() {
return descriptor instanceof PropertyAccessorDescriptor;
}
@NotNull
private JsExpression getQualifiedCallee(@Nullable JsExpression receiver) {
JsExpression callee = callParameters.getFunctionReference();
if (receiver != null) {
setQualifier(callee, receiver);
}
return callee;
}
@Nullable
private JsExpression getThisObjectOrQualifier() {
JsExpression thisObject = callParameters.getThisObject();
if (thisObject != null) {
return thisObject;
}
return context().getQualifierForDescriptor(descriptor);
}
}
@@ -41,7 +41,6 @@ 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;
import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getExpectedReceiverDescriptor;
@@ -117,13 +116,13 @@ public final class InlinedCallExpressionTranslator extends AbstractCallExpressio
private TranslationContext createContextWithAliasForThisExpression(@NotNull TranslationContext contextForInlining) {
TranslationContext contextWithAliasForThisExpression = contextForInlining;
SimpleFunctionDescriptor functionDescriptor = getFunctionDescriptor();
CallParameters callParameters = resolveCallParameters(receiver, null, functionDescriptor, resolvedCall, contextForInlining);
JsExpression receiver = callParameters.getReceiver();
CallInfo callInfo = ReferencePackage.getCallInfo(contextForInlining, resolvedCall, receiver);
JsExpression receiver = callInfo.getReceiverObject();
if (receiver != null) {
contextWithAliasForThisExpression =
contextWithAlias(contextWithAliasForThisExpression, receiver, getExpectedReceiverDescriptor(functionDescriptor));
}
JsExpression thisObject = callParameters.getThisObject();
JsExpression thisObject = callInfo.getThisObject();
if (thisObject != null) {
contextWithAliasForThisExpression =
contextWithAlias(contextWithAliasForThisExpression, thisObject, getExpectedThisDescriptor(functionDescriptor));