implement some of the intrinsic functionality

This commit is contained in:
Pavel Talanov
2011-12-01 19:12:07 +04:00
parent 5212ee4b00
commit cb071e3f74
29 changed files with 780 additions and 405 deletions
@@ -309,6 +309,13 @@ public class AstUtil {
throw new AssertionError("Set qualifier should be applied only to JsInvocation or JsNameRef instances");
}
//TODO: look for should-be-usages
public static JsNameRef qualified(JsName selector, JsExpression qualifier) {
JsNameRef reference = selector.makeRef();
AstUtil.setQualifier(reference, qualifier);
return reference;
}
public static JsBinaryOperation equals(JsExpression arg1, JsExpression arg2) {
return new JsBinaryOperation(JsBinaryOperator.REF_EQ, arg1, arg2);
}
@@ -1,27 +0,0 @@
package org.jetbrains.k2js.intrinsic;
import com.google.dart.compiler.backend.js.ast.JsExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetBinaryExpression;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.k2js.translate.general.TranslationContext;
import org.jetbrains.k2js.translate.operation.IntrinsicBinaryOperationTranslator;
/**
* @author Talanov Pavel
*/
public enum BinaryOperationIntrinsic implements Intrinsic {
INSTANCE;
/*package*/ BinaryOperationIntrinsic() {
}
@NotNull
@Override
public JsExpression apply(@NotNull JetExpression expression,
@NotNull TranslationContext context) {
assert expression instanceof JetBinaryExpression : "This intrinsic must be applied to binary operations.";
return IntrinsicBinaryOperationTranslator.translate((JetBinaryExpression) expression, context);
}
}
@@ -1,27 +0,0 @@
package org.jetbrains.k2js.intrinsic;
import org.jetbrains.annotations.NotNull;
/**
* @author Talanov Pavel
*/
public final class IntrinsicFactory {
@NotNull
private final Intrinsics intrinsics;
private IntrinsicFactory(@NotNull Intrinsics intrinsics) {
this.intrinsics = intrinsics;
}
// public Intrinsic getIntrinsicForExpression(@NotNull FunctionDescriptor descriptor,
// @NotNull JetExpression expression,
// @NotNull TranslationContext context) {
// assert intrinsics.hasDescriptor(descriptor);
// if (JetExpression instanceof JetBinaryExpression) {
// return new BinaryOperationIntrinsic()
// }
// }
}
@@ -1,86 +0,0 @@
package org.jetbrains.k2js.intrinsic;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.types.JetStandardLibrary;
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
import java.util.HashMap;
import java.util.Map;
/**
* @author Talanov Pavel
*/
public final class Intrinsics {
@NotNull
private final Map<DeclarationDescriptor, Intrinsic> descriptorToIntrinsicMap =
new HashMap<DeclarationDescriptor, Intrinsic>();
public static Intrinsics standardLibraryIntrinsics(@NotNull JetStandardLibrary library) {
return new Intrinsics(library);
}
private Intrinsics(@NotNull JetStandardLibrary library) {
IntrinsicDeclarationVisitor visitor = new IntrinsicDeclarationVisitor(this);
for (DeclarationDescriptor descriptor : library.getLibraryScope().getAllDescriptors()) {
descriptor.accept(visitor, null);
}
}
/*package*/ void declareIntrinsic(@NotNull DeclarationDescriptor descriptor) {
//TODO: this is a hack
descriptorToIntrinsicMap.put(descriptor, null);
addBinaryIntrinsics(descriptor);
// addUnaryIntrinsics(descriptor);
// addAssignmentIntrinsics(descriptor);
// addEqualsIntrinsics(descriptor);
}
// private void addEqualsIntrinsics(FunctionDescriptor descriptor) {
// //BinaryOperationIntrinsic binaryOperationIntrinsic = new BinaryOperationIntrinsic();
// String functionName = descriptor.getName();
// if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsValue(functionName)) {
// descriptorToIntrinsicMap.put(descriptor, binaryOperationIntrinsic);
// }
// }
//
// private void addUnaryIntrinsics(@NotNull FunctionDescriptor descriptor) {
// BinaryOperationIntrinsic binaryOperationIntrinsic = new BinaryOperationIntrinsic();
// String functionName = descriptor.getName();
// if (OperatorConventions.UNARY_OPERATION_NAMES.containsValue(functionName)) {
// descriptorToIntrinsicMap.put(descriptor, binaryOperationIntrinsic);
// }
// }
//
private void addBinaryIntrinsics(@NotNull DeclarationDescriptor descriptor) {
String functionName = descriptor.getName();
if (OperatorConventions.BINARY_OPERATION_NAMES.containsValue(functionName)) {
descriptorToIntrinsicMap.put(descriptor, BinaryOperationIntrinsic.INSTANCE);
}
}
//
// private void addAssignmentIntrinsics(@NotNull FunctionDescriptor descriptor) {
// String functionName = descriptor.getName();
// if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsValue(functionName)) {
// BinaryOperationIntrinsic binaryOperationIntrinsic = new BinaryOperationIntrinsic();
// descriptorToIntrinsicMap.put(descriptor, binaryOperationIntrinsic);
// }
// }
//
public boolean hasDescriptor(@NotNull DeclarationDescriptor descriptor) {
if (descriptor instanceof FunctionDescriptor) {
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor.getOriginal();
return descriptorToIntrinsicMap.containsKey(functionDescriptor);
}
return false;
}
public Intrinsic getIntrinsic(@NotNull DeclarationDescriptor descriptor) {
Intrinsic intrinsic = descriptorToIntrinsicMap.get(descriptor);
// assert intrinsic != null;
return intrinsic;
}
}
@@ -14,6 +14,7 @@ import org.jetbrains.k2js.translate.general.TranslatorVisitor;
import org.jetbrains.k2js.translate.operation.OperationTranslator;
import org.jetbrains.k2js.translate.operation.UnaryOperationTranslator;
import org.jetbrains.k2js.translate.reference.ArrayAccessTranslator;
import org.jetbrains.k2js.translate.reference.CallTranslator;
import org.jetbrains.k2js.translate.reference.PropertyAccessTranslator;
import org.jetbrains.k2js.translate.reference.ReferenceTranslator;
import org.jetbrains.k2js.translate.utils.BindingUtils;
@@ -108,24 +109,9 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
@Override
@NotNull
public JsNode visitCallExpression(JetCallExpression expression, TranslationContext context) {
JsExpression callee = translateCallee(expression, context);
List<JsExpression> arguments = translateArgumentList(expression.getValueArguments(), context);
if (isConstructorInvocation(context, expression)) {
JsNew constructorCall = new JsNew(callee);
constructorCall.setArguments(arguments);
return constructorCall;
}
return AstUtil.newInvocation(callee, arguments);
}
@NotNull
private JsExpression translateCallee(@NotNull JetCallExpression expression, @NotNull TranslationContext context) {
JetExpression callee = expression.getCalleeExpression();
if (callee == null) {
throw new AssertionError("Call expression with no callee encountered!");
}
return translateAsExpression(callee, context);
public JsNode visitCallExpression(@NotNull JetCallExpression expression,
@NotNull TranslationContext context) {
return CallTranslator.translate(expression, context);
}
@Override
@@ -10,7 +10,7 @@ import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.JetStandardLibrary;
import org.jetbrains.k2js.declarations.Declarations;
import org.jetbrains.k2js.intrinsic.Intrinsics;
import org.jetbrains.k2js.translate.intrinsic.Intrinsics;
import org.jetbrains.k2js.translate.utils.Namer;
public class StaticContext {
@@ -8,7 +8,7 @@ import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.k2js.declarations.Declarations;
import org.jetbrains.k2js.intrinsic.Intrinsics;
import org.jetbrains.k2js.translate.intrinsic.Intrinsics;
import org.jetbrains.k2js.translate.utils.BindingUtils;
import org.jetbrains.k2js.translate.utils.Namer;
@@ -68,7 +68,7 @@ public final class ClassInitializerTranslator extends AbstractInitializerTransla
@NotNull
private List<JsExpression> translateArguments(@NotNull JetDelegatorToSuperCall superCall) {
return TranslationUtils.translateArgumentList(superCall.getValueArguments(), context());
return TranslationUtils.translateArgumentList(context(), superCall.getValueArguments());
}
@Nullable
@@ -0,0 +1,38 @@
package org.jetbrains.k2js.translate.intrinsic;
import com.google.dart.compiler.backend.js.ast.JsBinaryOperation;
import com.google.dart.compiler.backend.js.ast.JsBinaryOperator;
import com.google.dart.compiler.backend.js.ast.JsExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lexer.JetToken;
import org.jetbrains.k2js.translate.general.TranslationContext;
import org.jetbrains.k2js.translate.operation.OperatorTable;
import java.util.List;
/**
* @author Talanov Pavel
*/
public class BinaryOperationIntrinsic implements Intrinsic {
@NotNull
/*package*/ static BinaryOperationIntrinsic newInstance(@NotNull JetToken token) {
JsBinaryOperator operator = OperatorTable.getBinaryOperator(token);
return new BinaryOperationIntrinsic(operator);
}
@NotNull
private final JsBinaryOperator operator;
private BinaryOperationIntrinsic(@NotNull JsBinaryOperator operator) {
this.operator = operator;
}
@NotNull
@Override
public JsExpression apply(@NotNull JsExpression receiver, @NotNull List<JsExpression> arguments,
@NotNull TranslationContext context) {
assert arguments.size() == 1 : "Binary operator should have a receiver and one argument";
return new JsBinaryOperation(operator, receiver, arguments.get(0));
}
}
@@ -0,0 +1,25 @@
package org.jetbrains.k2js.translate.intrinsic;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
import org.jetbrains.jet.lexer.JetToken;
/**
* @author Talanov Pavel
*/
public abstract class CompareToIntrinsic implements Intrinsic {
private JetToken comparisonToken = null;
@NotNull
public JetToken getComparisonToken() {
assert comparisonToken != null : "Should use set token first";
return comparisonToken;
}
public void setComparisonToken(@NotNull JetToken comparisonToken) {
assert OperatorConventions.COMPARISON_OPERATIONS.contains(comparisonToken)
: "Should be a comparison operation";
this.comparisonToken = comparisonToken;
}
}
@@ -0,0 +1,20 @@
package org.jetbrains.k2js.translate.intrinsic;
import org.jetbrains.annotations.NotNull;
/**
* @author Talanov Pavel
*/
public abstract class EqualsIntrinsic implements Intrinsic {
@NotNull
private Boolean isNegated = false;
public void setNegated(boolean isNegated) {
this.isNegated = isNegated;
}
public boolean isNegated() {
return isNegated;
}
}
@@ -1,17 +1,18 @@
package org.jetbrains.k2js.intrinsic;
package org.jetbrains.k2js.translate.intrinsic;
import com.google.dart.compiler.backend.js.ast.JsExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.k2js.translate.general.TranslationContext;
import java.util.List;
/**
* @author Talanov Pavel
*/
public interface Intrinsic {
@NotNull
public JsExpression apply(@NotNull JetExpression expression,
public JsExpression apply(@NotNull JsExpression receiver, @NotNull List<JsExpression> arguments,
@NotNull TranslationContext context);
}
@@ -1,4 +1,4 @@
package org.jetbrains.k2js.intrinsic;
package org.jetbrains.k2js.translate.intrinsic;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -0,0 +1,88 @@
package org.jetbrains.k2js.translate.intrinsic;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.types.JetStandardLibrary;
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
import org.jetbrains.jet.lexer.JetToken;
import org.jetbrains.k2js.translate.operation.OperatorTable;
import java.util.HashMap;
import java.util.Map;
/**
* @author Talanov Pavel
*/
public final class Intrinsics {
@NotNull
private final Map<FunctionDescriptor, Intrinsic> descriptorToIntrinsicMap =
new HashMap<FunctionDescriptor, Intrinsic>();
public static Intrinsics standardLibraryIntrinsics(@NotNull JetStandardLibrary library) {
return new Intrinsics(library);
}
private Intrinsics(@NotNull JetStandardLibrary library) {
IntrinsicDeclarationVisitor visitor = new IntrinsicDeclarationVisitor(this);
for (DeclarationDescriptor descriptor : library.getLibraryScope().getAllDescriptors()) {
descriptor.accept(visitor, null);
}
}
/*package*/ void declareIntrinsic(@NotNull FunctionDescriptor descriptor) {
//TODO: HACK!
addCompareToIntrinsics(descriptor);
addEqualsIntrinsics(descriptor);
addUnaryIntrinsics(descriptor);
addBinaryIntrinsics(descriptor);
}
private void addCompareToIntrinsics(@NotNull FunctionDescriptor descriptor) {
String functionName = descriptor.getName();
if (functionName.equals("compareTo")) {
descriptorToIntrinsicMap.put(descriptor, PrimitiveCompareToIntrinsic.newInstance());
}
}
private void addEqualsIntrinsics(@NotNull FunctionDescriptor descriptor) {
String functionName = descriptor.getName();
if (functionName.equals("equals")) {
descriptorToIntrinsicMap.put(descriptor, PrimitiveEqualsIntrinsic.newInstance());
}
}
private void addUnaryIntrinsics(@NotNull FunctionDescriptor descriptor) {
String functionName = descriptor.getName();
JetToken token = OperatorConventions.UNARY_OPERATION_NAMES.inverse().get(functionName);
if (token != null) {
descriptorToIntrinsicMap.put(descriptor, UnaryOperationIntrinsic.newInstance(token));
}
}
private void addBinaryIntrinsics(@NotNull FunctionDescriptor descriptor) {
String functionName = descriptor.getName();
JetToken token = OperatorConventions.BINARY_OPERATION_NAMES.inverse().get(functionName);
if (token != null && OperatorTable.hasCorrespondingBinaryOperator(token)) {
descriptorToIntrinsicMap.put(descriptor, BinaryOperationIntrinsic.newInstance(token));
}
}
public boolean hasDescriptor(@NotNull DeclarationDescriptor descriptor) {
if (descriptor instanceof FunctionDescriptor) {
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor.getOriginal();
return (descriptorToIntrinsicMap.get(functionDescriptor) != null);
}
return false;
}
@NotNull
public Intrinsic getIntrinsic(@NotNull DeclarationDescriptor descriptor) {
assert descriptor instanceof FunctionDescriptor;
Intrinsic intrinsic = descriptorToIntrinsicMap.get(descriptor);
return intrinsic;
}
}
@@ -0,0 +1,31 @@
package org.jetbrains.k2js.translate.intrinsic;
import com.google.dart.compiler.backend.js.ast.JsBinaryOperation;
import com.google.dart.compiler.backend.js.ast.JsBinaryOperator;
import com.google.dart.compiler.backend.js.ast.JsExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.k2js.translate.general.TranslationContext;
import org.jetbrains.k2js.translate.operation.OperatorTable;
import java.util.List;
/**
* @author Talanov Pavel
*/
public final class PrimitiveCompareToIntrinsic extends CompareToIntrinsic {
@NotNull
/*package*/ static PrimitiveCompareToIntrinsic newInstance() {
return new PrimitiveCompareToIntrinsic();
}
@NotNull
public JsExpression apply(@NotNull JsExpression receiver, @NotNull List<JsExpression> arguments,
@NotNull TranslationContext context) {
assert arguments.size() == 1 : "Equals operation should have one argument";
JsBinaryOperator operator = OperatorTable.getBinaryOperator(getComparisonToken());
JsExpression argument = arguments.get(0);
return new JsBinaryOperation(operator, receiver, argument);
}
}
@@ -0,0 +1,32 @@
package org.jetbrains.k2js.translate.intrinsic;
import com.google.dart.compiler.backend.js.ast.JsExpression;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.k2js.translate.general.TranslationContext;
import java.util.List;
/**
* @author Talanov Pavel
*/
public final class PrimitiveEqualsIntrinsic extends EqualsIntrinsic {
@NotNull
/*package*/ static PrimitiveEqualsIntrinsic newInstance() {
return new PrimitiveEqualsIntrinsic();
}
@NotNull
public JsExpression apply(@NotNull JsExpression receiver, @NotNull List<JsExpression> arguments,
@NotNull TranslationContext context) {
assert arguments.size() == 1 : "Equals operation should have one argument";
if (isNegated()) {
return AstUtil.notEqual(receiver, arguments.get(0));
} else {
return AstUtil.equals(receiver, arguments.get(0));
}
}
}
@@ -0,0 +1,39 @@
package org.jetbrains.k2js.translate.intrinsic;
import com.google.dart.compiler.backend.js.ast.JsExpression;
import com.google.dart.compiler.backend.js.ast.JsPrefixOperation;
import com.google.dart.compiler.backend.js.ast.JsUnaryOperator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lexer.JetToken;
import org.jetbrains.k2js.translate.general.TranslationContext;
import org.jetbrains.k2js.translate.operation.OperatorTable;
import java.util.List;
/**
* @author Talanov Pavel
*/
public class UnaryOperationIntrinsic implements Intrinsic {
@NotNull
/*package*/ static UnaryOperationIntrinsic newInstance(@NotNull JetToken token) {
JsUnaryOperator operator = OperatorTable.getUnaryOperator(token);
return new UnaryOperationIntrinsic(operator);
}
@NotNull
private final JsUnaryOperator operator;
private UnaryOperationIntrinsic(@NotNull JsUnaryOperator operator) {
this.operator = operator;
}
@NotNull
@Override
public JsExpression apply(@NotNull JsExpression receiver, @NotNull List<JsExpression> arguments,
@NotNull TranslationContext context) {
assert arguments.size() == 0 : "Unary operator should not have arguments.";
//TODO: note that we cannot use this for increment/decrement
return new JsPrefixOperation(operator, receiver);
}
}
@@ -4,12 +4,15 @@ import com.google.dart.compiler.backend.js.ast.JsExpression;
import com.google.dart.compiler.backend.js.ast.JsInvocation;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetBinaryExpression;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lexer.JetToken;
import org.jetbrains.k2js.translate.general.Translation;
import org.jetbrains.k2js.translate.general.TranslationContext;
import org.jetbrains.k2js.translate.reference.PropertyAccessTranslator;
import static org.jetbrains.k2js.translate.utils.BindingUtils.isVariableReassignment;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateLeftExpression;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateRightExpression;
/**
* @author Talanov Pavel
*/
@@ -29,26 +32,16 @@ public abstract class BinaryOperationTranslator extends OperationTranslator {
super(context);
this.expression = expression;
this.isPropertyOnTheLeft = isPropertyAccess(expression.getLeft());
this.isVariableReassignment = isVariableReassignment(expression);
this.isVariableReassignment = isVariableReassignment(context.bindingContext(), expression);
this.right = translateRightExpression();
this.right = translateRightExpression(context(), expression);
//TODO: decide whether it is harmful to possibly translateNamespace left expression more than once
this.left = translateLeftExpression();
this.left = translateLeftExpression(context(), expression);
}
@NotNull
abstract protected JsExpression translate();
private JsExpression translateLeftExpression() {
return Translation.translateAsExpression(expression.getLeft(), context());
}
@NotNull
private JsExpression translateRightExpression() {
JetExpression rightExpression = expression.getRight();
assert rightExpression != null : "Binary expression should have a right expression";
return Translation.translateAsExpression(rightExpression, context());
}
@NotNull
protected JetToken getOperationToken() {
@@ -0,0 +1,9 @@
package org.jetbrains.k2js.translate.operation;
/**
* @author Talanov Pavel
*/
public final class EqualsTranslator {
}
@@ -0,0 +1,64 @@
package org.jetbrains.k2js.translate.operation;
import com.google.dart.compiler.backend.js.ast.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetUnaryExpression;
import org.jetbrains.jet.lexer.JetToken;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.k2js.translate.general.TranslationContext;
/**
* @author Talanov Pavel
*/
public final class IntrinsicUnaryOperationTranslator extends UnaryOperationTranslator {
@NotNull
public static JsExpression translate(@NotNull JetUnaryExpression expression,
@NotNull TranslationContext context) {
return (new IntrinsicUnaryOperationTranslator(expression, context))
.translate();
}
protected IntrinsicUnaryOperationTranslator(@NotNull JetUnaryExpression expression,
@NotNull TranslationContext context) {
super(expression, context);
}
@Override
@NotNull
protected JsExpression translate() {
if (isPropertyAccess) {
return translateAsMethodCall();
}
return jsUnaryExpression();
}
@NotNull
private JsExpression jsUnaryExpression() {
JsUnaryOperator operator = OperatorTable.getUnaryOperator(getOperationToken());
if (isPrefix) {
return new JsPrefixOperation(operator, baseExpression);
} else {
return new JsPostfixOperation(operator, baseExpression);
}
}
@Override
@NotNull
protected JsExpression operationExpression(@NotNull JsExpression receiver) {
return unaryAsBinary(getOperationToken(), receiver);
}
public JsBinaryOperation unaryAsBinary(@NotNull JetToken token, @NotNull JsExpression expression) {
JsNumberLiteral oneLiteral = context().program().getNumberLiteral(1);
if (token.equals(JetTokens.PLUSPLUS)) {
return new JsBinaryOperation(JsBinaryOperator.ADD, expression, oneLiteral);
}
if (token.equals(JetTokens.MINUSMINUS)) {
return new JsBinaryOperation(JsBinaryOperator.SUB, expression, oneLiteral);
}
throw new AssertionError("This method should be called only for increment and decrement operators");
}
}
@@ -9,14 +9,24 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.psi.JetBinaryExpression;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.k2js.intrinsic.Intrinsic;
import org.jetbrains.jet.lang.psi.JetOperationExpression;
import org.jetbrains.jet.lang.psi.JetUnaryExpression;
import org.jetbrains.jet.lexer.JetToken;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.k2js.translate.general.AbstractTranslator;
import org.jetbrains.k2js.translate.general.TranslationContext;
import org.jetbrains.k2js.translate.intrinsic.CompareToIntrinsic;
import org.jetbrains.k2js.translate.intrinsic.EqualsIntrinsic;
import org.jetbrains.k2js.translate.intrinsic.Intrinsic;
import org.jetbrains.k2js.translate.reference.ArrayAccessTranslator;
import org.jetbrains.k2js.translate.reference.CallTranslator;
import org.jetbrains.k2js.translate.reference.PropertyAccessTranslator;
import org.jetbrains.k2js.translate.utils.BindingUtils;
import org.jetbrains.k2js.translate.utils.TranslationUtils;
import java.util.Arrays;
import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateLeftExpression;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateRightExpression;
/**
* @author Talanov Pavel
@@ -24,67 +34,92 @@ import org.jetbrains.k2js.translate.utils.TranslationUtils;
public class OperationTranslator extends AbstractTranslator {
@NotNull
static public JsExpression translate(@NotNull JetBinaryExpression expression,
public static JsExpression translate(@NotNull JetBinaryExpression expression,
@NotNull TranslationContext context) {
JsExpression result = tryToApplyIntrinsic(expression, context);
if (result != null) return result;
//TODO: move to assignment translator
if (ArrayAccessTranslator.canBeArraySetterCall(expression)) {
return ArrayAccessTranslator.translateAsArraySetterCall(expression, context);
}
return translateAsBinary(expression, context);
DeclarationDescriptor descriptorForReferenceExpression = getDescriptorForReferenceExpression
(context.bindingContext(), expression.getOperation());
if (descriptorForReferenceExpression == null) {
return IntrinsicBinaryOperationTranslator.translate(expression, context);
}
if (isEqualsCall(expression, context)) {
return translateAsEqualsCall(expression, context);
}
if (isCompareToCall(expression, context)) {
return translateAsCompareToCall(expression, context);
}
return CallTranslator.translate(expression, context);
}
@NotNull
private static JsExpression translateAsBinary(@NotNull JetBinaryExpression expression,
@NotNull TranslationContext context) {
if (TranslationUtils.isIntrinsicOperation(context, expression.getOperationReference())) {
return IntrinsicBinaryOperationTranslator.translate(expression, context);
} else {
return OverloadedBinaryOperationTranslator.translate(expression, context);
}
public static JsExpression translate(@NotNull JetUnaryExpression expression,
@NotNull TranslationContext context) {
return CallTranslator.translate(expression, context);
}
@Nullable
private static JsExpression tryToApplyIntrinsic(@NotNull JetBinaryExpression expression,
@NotNull TranslationContext context) {
DeclarationDescriptor descriptor = BindingUtils.getDescriptorForReferenceExpression
(context.bindingContext(), expression.getOperationReference());
if (descriptor == null) {
return null;
}
if (!context.intrinsics().hasDescriptor(descriptor)) {
return null;
}
//TODO: should be no nulls here
Intrinsic intrinsic = context.intrinsics().getIntrinsic(descriptor);
if (intrinsic == null) return null;
return intrinsic.apply(expression, context);
public static boolean isEqualsCall(@NotNull JetBinaryExpression expression,
@NotNull TranslationContext context) {
DeclarationDescriptor operationDescriptor = getOperationDescriptor(expression, context);
//TODO: add descriptor is equals utils
boolean isEquals = operationDescriptor.getName().equals("equals");
boolean isIntrinsic = context.intrinsics().hasDescriptor(operationDescriptor);
return isEquals && isIntrinsic;
}
@NotNull
public static JsExpression translateAsEqualsCall(@NotNull JetBinaryExpression expression,
@NotNull TranslationContext context) {
Intrinsic intrinsic = context.intrinsics().
getIntrinsic(getOperationDescriptor(expression, context));
//TODO
((EqualsIntrinsic) intrinsic).setNegated(expression.getOperationToken().equals(JetTokens.EXCLEQ));
return intrinsic.apply(translateLeftExpression(context, expression),
Arrays.asList(translateRightExpression(context, expression)), context);
}
public static boolean isCompareToCall(@NotNull JetBinaryExpression expression,
@NotNull TranslationContext context) {
DeclarationDescriptor operationDescriptor = getOperationDescriptor(expression, context);
return (operationDescriptor.getName().equals("compareTo")
&& (context.intrinsics().hasDescriptor(operationDescriptor)));
}
@NotNull
public static JsExpression translateAsCompareToCall(@NotNull JetBinaryExpression expression,
@NotNull TranslationContext context) {
Intrinsic intrinsic = context.intrinsics().
getIntrinsic(getOperationDescriptor(expression, context));
((CompareToIntrinsic) intrinsic).setComparisonToken((JetToken) expression.getOperationToken());
return intrinsic.apply(translateLeftExpression(context, expression),
Arrays.asList(translateRightExpression(context, expression)), context);
}
protected OperationTranslator(@NotNull TranslationContext context) {
super(context);
}
//TODO: refactor
@Nullable
protected JsNameRef getOverloadedOperationReference(@NotNull JetSimpleNameExpression operationExpression) {
DeclarationDescriptor operationDescriptor = getOperationDescriptor(operationExpression);
if (operationDescriptor == null) {
protected static JsNameRef getOverloadedOperationReference(@NotNull JetOperationExpression operationExpression,
@NotNull TranslationContext context) {
DeclarationDescriptor operationDescriptor = getOperationDescriptor(operationExpression, context);
if (!context.isDeclared(operationDescriptor)) {
return null;
}
if (context().intrinsics().hasDescriptor(operationDescriptor)) {
return null;
}
if (!context().isDeclared(operationDescriptor)) {
return null;
}
return context().getNameForDescriptor(operationDescriptor).makeRef();
return context.getNameForDescriptor(operationDescriptor).makeRef();
}
@Nullable
private DeclarationDescriptor getOperationDescriptor(@NotNull JetSimpleNameExpression expression) {
return BindingUtils.getDescriptorForReferenceExpression
(context().bindingContext(), expression);
@NotNull
private static DeclarationDescriptor getOperationDescriptor(@NotNull JetOperationExpression expression,
@NotNull TranslationContext context) {
DeclarationDescriptor descriptorForReferenceExpression = getDescriptorForReferenceExpression
(context.bindingContext(), expression.getOperation());
assert descriptorForReferenceExpression != null;
return descriptorForReferenceExpression;
}
protected boolean isPropertyAccess(@NotNull JetExpression expression) {
@@ -92,12 +127,6 @@ public class OperationTranslator extends AbstractTranslator {
}
protected boolean isVariableReassignment(@NotNull JetExpression expression) {
return BindingUtils.isVariableReassignment
(context().bindingContext(), expression);
}
protected final class TemporaryVariable {
@NotNull
@@ -25,7 +25,7 @@ public final class OverloadedBinaryOperationTranslator extends BinaryOperationTr
private OverloadedBinaryOperationTranslator(@NotNull JetBinaryExpression expression,
@NotNull TranslationContext context) {
super(expression, context);
JsNameRef overloadedOperationReference = getOverloadedOperationReference(expression.getOperationReference());
JsNameRef overloadedOperationReference = getOverloadedOperationReference(expression, context);
assert overloadedOperationReference != null;
this.operationReference = overloadedOperationReference;
}
@@ -0,0 +1,44 @@
package org.jetbrains.k2js.translate.operation;
import com.google.dart.compiler.backend.js.ast.JsExpression;
import com.google.dart.compiler.backend.js.ast.JsNameRef;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetUnaryExpression;
import org.jetbrains.k2js.translate.general.TranslationContext;
/**
* @author Talanov Pavel
*/
public final class OverloadedUnaryOperationTranslator extends UnaryOperationTranslator {
@NotNull
public static JsExpression translate(@NotNull JetUnaryExpression expression,
@NotNull TranslationContext context) {
return (new OverloadedUnaryOperationTranslator(expression, context))
.translate();
}
@NotNull
private final JsNameRef operationReference;
private OverloadedUnaryOperationTranslator(@NotNull JetUnaryExpression expression,
@NotNull TranslationContext context) {
super(expression, context);
this.operationReference = getOverloadedOperationReference(expression, context);
}
@Override
@NotNull
protected JsExpression translate() {
return translateAsMethodCall();
}
@Override
@NotNull
protected JsExpression operationExpression(@NotNull JsExpression receiver) {
AstUtil.setQualifier(operationReference, receiver);
return AstUtil.newInvocation(operationReference);
}
}
@@ -1,70 +1,55 @@
package org.jetbrains.k2js.translate.operation;
import com.google.dart.compiler.backend.js.ast.*;
import com.google.dart.compiler.backend.js.ast.JsExpression;
import com.google.dart.compiler.backend.js.ast.JsInvocation;
import com.google.dart.compiler.backend.js.ast.JsNameRef;
import com.google.dart.compiler.util.AstUtil;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetPrefixExpression;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lang.psi.JetUnaryExpression;
import org.jetbrains.jet.lexer.JetToken;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.k2js.translate.general.Translation;
import org.jetbrains.k2js.translate.general.TranslationContext;
import org.jetbrains.k2js.translate.reference.PropertyAccessTranslator;
import org.jetbrains.k2js.translate.utils.BindingUtils;
import static org.jetbrains.k2js.translate.utils.BindingUtils.isVariableReassignment;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.getBaseExpression;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateBaseExpression;
/**
* @author Talanov Pavel
*/
public final class UnaryOperationTranslator extends OperationTranslator {
@NotNull
static public JsExpression translate(@NotNull JetPrefixExpression expression,
@NotNull TranslationContext context) {
return (new UnaryOperationTranslator(context, expression, true)).translate();
}
@NotNull
static public JsExpression translate(@NotNull JetPostfixExpression expression,
@NotNull TranslationContext context) {
return (new UnaryOperationTranslator(context, expression, false)).translate();
}
//TODO: reexamine class, see if can be clearer
public abstract class UnaryOperationTranslator extends OperationTranslator {
@NotNull
private final JetUnaryExpression expression;
@NotNull
private final JsExpression baseExpression;
private final boolean isPrefix;
protected final JsExpression baseExpression;
protected final boolean isPrefix;
private final boolean isVariableReassignment;
private final boolean isStatement;
private final boolean isPropertyAccess;
@Nullable
private final JsNameRef operationReference;
protected final boolean isPropertyAccess;
private UnaryOperationTranslator(@NotNull TranslationContext context, @NotNull JetUnaryExpression expression,
boolean isPrefix) {
protected UnaryOperationTranslator(@NotNull JetUnaryExpression expression,
@NotNull TranslationContext context) {
super(context);
this.expression = expression;
this.isPrefix = isPrefix;
this.isVariableReassignment = isVariableReassignment(expression);
this.isPrefix = isPrefix(expression);
this.isVariableReassignment = isVariableReassignment(context.bindingContext(), expression);
this.isStatement = BindingUtils.isStatement(context().bindingContext(), expression);
this.baseExpression = translateBaseExpression();
this.isPropertyAccess = isPropertyAccess(getBaseExpression());
this.operationReference = getOverloadedOperationReference(expression.getOperationSign());
this.baseExpression = translateBaseExpression(context, expression);
this.isPropertyAccess = isPropertyAccess(getBaseExpression(expression));
}
@NotNull
JsExpression translate() {
if ((operationReference != null) || isPropertyAccess) {
return translateOverload();
}
return jsUnaryExpression();
}
protected abstract JsExpression translate();
@NotNull
private JsExpression translateOverload() {
protected JsExpression translateAsMethodCall() {
if (isStatement || isPrefix) {
return asPrefix();
}
@@ -99,7 +84,6 @@ public final class UnaryOperationTranslator extends OperationTranslator {
private JsExpression asPostfixWithNoReassignment() {
// code fragment: expr(a++)
// generate: expr( (t1 = a, t2 = t1, t2.inc(), t1) )
assert operationReference != null;
TemporaryVariable t1 = declareTemporary(baseExpression);
TemporaryVariable t2 = declareTemporary(t1.nameReference());
JsExpression methodCall = operationExpression(t2.nameReference());
@@ -122,7 +106,7 @@ public final class UnaryOperationTranslator extends OperationTranslator {
@NotNull
private JsExpression propertyReassignment(@NotNull JsExpression toCallMethodUpon) {
JetExpression jetBaseExpression = getBaseExpression();
JetExpression jetBaseExpression = getBaseExpression(expression);
JsInvocation setterCall =
PropertyAccessTranslator.translateAsPropertySetterCall(jetBaseExpression, context());
assert PropertyAccessTranslator.canBePropertyGetterCall(jetBaseExpression, context()) : "Should be a getter call";
@@ -132,52 +116,19 @@ public final class UnaryOperationTranslator extends OperationTranslator {
}
@NotNull
private JsExpression operationExpression(@NotNull JsExpression receiver) {
if (operationReference != null) {
AstUtil.setQualifier(operationReference, receiver);
return AstUtil.newInvocation(operationReference);
}
return unaryAsBinary(getOperationToken(), receiver);
}
abstract JsExpression operationExpression(@NotNull JsExpression receiver);
@NotNull
private JsExpression jsUnaryExpression() {
JsUnaryOperator operator = OperatorTable.getUnaryOperator(getOperationToken());
if (isPrefix) {
return new JsPrefixOperation(operator, baseExpression);
} else {
return new JsPostfixOperation(operator, baseExpression);
}
}
@NotNull
private JsExpression translateBaseExpression() {
JetExpression baseExpression = getBaseExpression();
return Translation.translateAsExpression(baseExpression, context());
}
private JetExpression getBaseExpression() {
JetExpression baseExpression = expression.getBaseExpression();
assert baseExpression != null : "Unary expression should have a base expression";
return baseExpression;
}
@NotNull
private JetToken getOperationToken() {
JetSimpleNameExpression operationExpression = expression.getOperationSign();
protected JetToken getOperationToken() {
JetSimpleNameExpression operationExpression = expression.getOperation();
IElementType elementType = operationExpression.getReferencedNameElementType();
assert elementType instanceof JetToken : "Unary expression should have IElementType of type JetToken";
return (JetToken) elementType;
}
public JsBinaryOperation unaryAsBinary(@NotNull JetToken token, @NotNull JsExpression expression) {
JsNumberLiteral oneLiteral = context().program().getNumberLiteral(1);
if (token.equals(JetTokens.PLUSPLUS)) {
return new JsBinaryOperation(JsBinaryOperator.ADD, expression, oneLiteral);
}
if (token.equals(JetTokens.MINUSMINUS)) {
return new JsBinaryOperation(JsBinaryOperator.SUB, expression, oneLiteral);
}
throw new AssertionError("This method should be called only for increment and decrement operators");
private boolean isPrefix(JetUnaryExpression expression) {
return (expression instanceof JetPrefixExpression);
}
}
@@ -0,0 +1,137 @@
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 com.google.dart.compiler.backend.js.ast.JsNew;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.k2js.translate.general.AbstractTranslator;
import org.jetbrains.k2js.translate.general.TranslationContext;
import org.jetbrains.k2js.translate.intrinsic.Intrinsic;
import org.jetbrains.k2js.translate.utils.TranslationUtils;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression;
import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptorForCallExpression;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.*;
/**
* @author Talanov Pavel
*/
public final class CallTranslator extends AbstractTranslator {
public static boolean isFunctionCall(@NotNull JetOperationExpression expression,
@NotNull TranslationContext context) {
DeclarationDescriptor descriptor = getDescriptorForReferenceExpression
(context.bindingContext(), expression.getOperation());
return (descriptor instanceof FunctionDescriptor);
}
public static JsExpression translate(@NotNull JetUnaryExpression unaryExpression,
@NotNull TranslationContext context) {
JsExpression receiver = TranslationUtils.translateBaseExpression(context, unaryExpression);
List<JsExpression> arguments = Collections.emptyList();
DeclarationDescriptor descriptor = getDescriptorForReferenceExpression
(context.bindingContext(), unaryExpression.getOperation());
assert descriptor instanceof FunctionDescriptor;
return (new CallTranslator(receiver, arguments, (FunctionDescriptor) descriptor, context)).translate();
}
public static JsExpression translate(@NotNull JetDotQualifiedExpression dotExpression,
@NotNull TranslationContext context) {
//TODO: look for duplication
JsExpression receiver = translateReceiver(context, dotExpression);
JetExpression selectorExpression = dotExpression.getSelectorExpression();
assert selectorExpression instanceof JetCallExpression;
JetCallExpression callExpression = (JetCallExpression) selectorExpression;
List<JsExpression> arguments =
translateArgumentList(context, callExpression.getValueArguments());
FunctionDescriptor descriptor =
getFunctionDescriptorForCallExpression(context.bindingContext(), callExpression);
return (new CallTranslator(receiver, arguments, descriptor, context)).translate();
}
public static JsExpression translate(@NotNull JetCallExpression callExpression,
@NotNull TranslationContext context) {
DeclarationDescriptor descriptor =
getFunctionDescriptorForCallExpression(context.bindingContext(), callExpression);
JsExpression receiver = ReferenceTranslator.getImplicitReceiver(descriptor, context);
List<JsExpression> arguments = translateArgumentList(context, callExpression.getValueArguments());
return (new CallTranslator(receiver, arguments, (FunctionDescriptor) descriptor, context)).translate();
}
public static JsExpression translate(@NotNull JetBinaryExpression binaryExpression,
@NotNull TranslationContext context) {
JsExpression receiver = translateLeftExpression(context, binaryExpression);
List<JsExpression> arguments = Arrays.asList(translateRightExpression(context, binaryExpression));
//TODO: use PSI util method to get operation reference
DeclarationDescriptor descriptor = getDescriptorForReferenceExpression
(context.bindingContext(), binaryExpression.getOperation());
assert descriptor instanceof FunctionDescriptor;
return (new CallTranslator(receiver, arguments, (FunctionDescriptor) descriptor, context)).translate();
}
@Nullable
private final JsExpression receiver;
@NotNull
private final List<JsExpression> arguments;
@NotNull
private final FunctionDescriptor descriptor;
private CallTranslator(@Nullable JsExpression receiver, @NotNull List<JsExpression> arguments,
@NotNull FunctionDescriptor descriptor, @NotNull TranslationContext context) {
super(context);
this.receiver = receiver;
this.arguments = arguments;
this.descriptor = descriptor;
}
@NotNull
private JsExpression translate() {
if (context().intrinsics().hasDescriptor(descriptor)) {
Intrinsic intrinsic = context().intrinsics().getIntrinsic(descriptor);
assert receiver != null : "Functions that have intrinsic implementation should have a receiver.";
return intrinsic.apply(receiver, arguments, context());
}
if (isConstructorDescriptor(descriptor)) {
return constructorCall();
}
return AstUtil.newInvocation(qualifiedMethodReference(), arguments);
}
@NotNull
private JsNameRef qualifiedMethodReference() {
JsName methodName = context().getNameForDescriptor(descriptor);
if (receiver != null) {
return AstUtil.qualified(methodName, receiver);
}
return methodName.makeRef();
}
@NotNull
private JsExpression constructorCall() {
JsNew constructorCall = new JsNew(qualifiedMethodReference());
constructorCall.setArguments(arguments);
return constructorCall;
}
// //TODO: delete?
// @NotNull
// private JsExpression translateCallee(@NotNull JetCallExpression expression) {
// JetExpression callee = expression.getCalleeExpression();
// assert callee != null : "Call expression with no callee encountered!";
// return Translation.translateAsExpression(callee, context);
// }
}
@@ -18,7 +18,6 @@ import org.jetbrains.k2js.translate.general.Translation;
import org.jetbrains.k2js.translate.general.TranslationContext;
import org.jetbrains.k2js.translate.utils.BindingUtils;
import org.jetbrains.k2js.translate.utils.PsiUtils;
import org.jetbrains.k2js.translate.utils.TranslationUtils;
/**
* @author Talanov Pavel
@@ -147,17 +146,6 @@ public final class PropertyAccessTranslator extends AbstractTranslator {
return AstUtil.newInvocation(accessorReference);
}
@NotNull
private JsExpression defaultQualifier() {
if (BindingUtils.isOwnedByClass(propertyDescriptor)) {
return TranslationUtils.getThisQualifier(context());
}
assert BindingUtils.isOwnedByNamespace(propertyDescriptor)
: "Property can be a member of class or a namespace.";
//NOTE: qualifier for descriptor and it's accessor should be equal
return context().declarations().getQualifier(propertyDescriptor);
}
@NotNull
public JsInvocation translateAsPropertySetterCall() {
JsName setterName = getNotNullSetterName();
@@ -169,7 +157,9 @@ public final class PropertyAccessTranslator extends AbstractTranslator {
if (qualifier != null) {
return Translation.translateAsExpression(qualifier, context());
}
return defaultQualifier();
JsExpression implicitReceiver = ReferenceTranslator.getImplicitReceiver(propertyDescriptor, context());
assert implicitReceiver != null : "Property can only be a member of class or a namespace.";
return implicitReceiver;
}
@@ -2,11 +2,11 @@ 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.util.AstUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.k2js.translate.general.AbstractTranslator;
import org.jetbrains.k2js.translate.general.TranslationContext;
import org.jetbrains.k2js.translate.utils.BindingUtils;
@@ -38,10 +38,9 @@ public class ReferenceTranslator extends AbstractTranslator {
@NotNull
//TODO: make this process simpler and clearer
public JsExpression translateSimpleName() {
tryResolveAsPropertyAccess();
tryResolveAsThisQualifiedExpression();
tryResolveAsAliasReference();
tryResolveAsGlobalReference();
tryResolveAsPropertyAccess();
tryResolveAsImplicitlyQualifiedExpression();
tryResolveAsLocalReference();
if (result != null) {
return result;
@@ -49,7 +48,8 @@ public class ReferenceTranslator extends AbstractTranslator {
throw new AssertionError("Undefined name in this scope: " + simpleName.getReferencedName());
}
private void tryResolveAsThisQualifiedExpression() {
//TODO: refactor
private void tryResolveAsImplicitlyQualifiedExpression() {
if (alreadyResolved()) return;
DeclarationDescriptor referencedDescriptor =
@@ -59,24 +59,24 @@ public class ReferenceTranslator extends AbstractTranslator {
if (!context().isDeclared(referencedDescriptor)) return;
JsName referencedName = context().getNameForDescriptor(referencedDescriptor);
JsExpression implicitReceiver = getImplicitReceiver(referencedDescriptor, context());
if (!requiresThisQualifier(simpleName, referencedName)) return;
if (implicitReceiver == null) return;
if (BindingUtils.isOwnedByClass(referencedDescriptor)) {
result = TranslationUtils.getThisQualifiedNameReference(context(), referencedName);
}
if (BindingUtils.isOwnedByNamespace(referencedDescriptor)) {
result = TranslationUtils.getQualifiedReference(context(), referencedDescriptor);
}
result = AstUtil.qualified(referencedName, implicitReceiver);
}
private boolean requiresThisQualifier(@NotNull JetSimpleNameExpression expression,
@NotNull JsName referencedName) {
@Nullable
public static JsExpression getImplicitReceiver(@NotNull DeclarationDescriptor referencedDescriptor,
@NotNull TranslationContext context) {
if (!context.isDeclared(referencedDescriptor)) return null;
JsName name = context().enclosingScope().findExistingName(referencedName.getIdent());
boolean isClassMember = context().classScope().ownsName(name);
boolean isBackingFieldAccess = expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER;
return (isBackingFieldAccess || isClassMember);
if (BindingUtils.isOwnedByClass(referencedDescriptor)) {
return TranslationUtils.getThisQualifier(context);
}
if (!BindingUtils.isOwnedByNamespace(referencedDescriptor)) return null;
return context.declarations().getQualifier(referencedDescriptor);
}
private void tryResolveAsAliasReference() {
@@ -104,18 +104,6 @@ public class ReferenceTranslator extends AbstractTranslator {
result = PropertyAccessTranslator.translateAsPropertyGetterCall(simpleName, context());
}
private void tryResolveAsGlobalReference() {
if (alreadyResolved()) return;
DeclarationDescriptor referencedDescriptor =
BindingUtils.getDescriptorForReferenceExpression(context().bindingContext(), simpleName);
if (referencedDescriptor == null) return;
if (!context().isDeclared(referencedDescriptor)) return;
result = TranslationUtils.getQualifiedReference(context(), referencedDescriptor);
}
private void tryResolveAsLocalReference() {
if (alreadyResolved()) return;
@@ -36,37 +36,37 @@ public final class BindingUtils {
}
@NotNull
static public ClassDescriptor getClassDescriptor(@NotNull BindingContext context, @NotNull JetClass declaration) {
public static ClassDescriptor getClassDescriptor(@NotNull BindingContext context, @NotNull JetClass declaration) {
return getDescriptorForExpression(context, declaration, ClassDescriptor.class);
}
@NotNull
static public NamespaceDescriptor getNamespaceDescriptor(@NotNull BindingContext context,
public static NamespaceDescriptor getNamespaceDescriptor(@NotNull BindingContext context,
@NotNull JetNamespace declaration) {
return getDescriptorForExpression(context, declaration, NamespaceDescriptor.class);
}
@NotNull
static public FunctionDescriptor getFunctionDescriptor(@NotNull BindingContext context,
public static FunctionDescriptor getFunctionDescriptor(@NotNull BindingContext context,
@NotNull JetNamedFunction declaration) {
return getDescriptorForExpression(context, declaration, FunctionDescriptor.class);
}
@NotNull
static public PropertyAccessorDescriptor getPropertyAccessorDescriptor(@NotNull BindingContext context,
public static PropertyAccessorDescriptor getPropertyAccessorDescriptor(@NotNull BindingContext context,
@NotNull JetPropertyAccessor declaration) {
return getDescriptorForExpression(context, declaration, PropertyAccessorDescriptor.class);
}
@NotNull
static public PropertyDescriptor getPropertyDescriptor(@NotNull BindingContext context,
public static PropertyDescriptor getPropertyDescriptor(@NotNull BindingContext context,
@NotNull JetProperty declaration) {
return getDescriptorForExpression(context, declaration, PropertyDescriptor.class);
}
//TODO: possibly remove
// @NotNull
// static public PropertySetterDescriptor getPropertySetterDescriptorForProperty(@NotNull BindingContext context,
// public static PropertySetterDescriptor getPropertySetterDescriptorForProperty(@NotNull BindingContext context,
// @NotNull JetProperty property) {
// PropertySetterDescriptor result = getPropertyDescriptor(context, property).getSetter();
// assert result != null : "Property should have a setter descriptor";
@@ -74,7 +74,7 @@ public final class BindingUtils {
// }
//
// @NotNull
// static public PropertyGetterDescriptor getPropertyGetterDescriptorForProperty(@NotNull BindingContext context,
// public static PropertyGetterDescriptor getPropertyGetterDescriptorForProperty(@NotNull BindingContext context,
// @NotNull JetProperty property) {
// PropertyGetterDescriptor result = getPropertyDescriptor(context, property).getGetter();
// assert result != null : "Property should have a getter descriptor";
@@ -82,7 +82,7 @@ public final class BindingUtils {
// }
@NotNull
static public JetClass getClassForDescriptor(@NotNull BindingContext context,
public static JetClass getClassForDescriptor(@NotNull BindingContext context,
@NotNull ClassDescriptor descriptor) {
PsiElement result = context.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor);
assert result instanceof JetClass : "ClassDescriptor should have declaration of type JetClass";
@@ -91,7 +91,7 @@ public final class BindingUtils {
//TODO: delete?
@Nullable
static public JetDeclaration getDeclarationForDescriptor(@NotNull BindingContext context,
public static JetDeclaration getDeclarationForDescriptor(@NotNull BindingContext context,
@NotNull DeclarationDescriptor descriptor) {
PsiElement result = context.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor);
if (!(result instanceof JetDeclaration)) {
@@ -101,14 +101,14 @@ public final class BindingUtils {
}
@NotNull
static public List<ClassDescriptor> getSuperclassDescriptors(@NotNull BindingContext context,
public static List<ClassDescriptor> getSuperclassDescriptors(@NotNull BindingContext context,
@NotNull JetClass classDeclaration) {
ClassDescriptor classDescriptor = getClassDescriptor(context, classDeclaration);
return getSuperclassDescriptors(classDescriptor);
}
@NotNull
static public List<ClassDescriptor> getSuperclassDescriptors(@NotNull ClassDescriptor classDescriptor) {
public static List<ClassDescriptor> getSuperclassDescriptors(@NotNull ClassDescriptor classDescriptor) {
Collection<? extends JetType> superclassTypes = classDescriptor.getTypeConstructor().getSupertypes();
List<ClassDescriptor> superClassDescriptors = new ArrayList<ClassDescriptor>();
for (JetType type : superclassTypes) {
@@ -121,7 +121,7 @@ public final class BindingUtils {
}
@NotNull
static public ClassDescriptor getClassDescriptorForType(@NotNull JetType type) {
public static ClassDescriptor getClassDescriptorForType(@NotNull JetType type) {
DeclarationDescriptor superClassDescriptor =
type.getConstructor().getDeclarationDescriptor();
assert superClassDescriptor instanceof ClassDescriptor
@@ -129,19 +129,19 @@ public final class BindingUtils {
return (ClassDescriptor) superClassDescriptor;
}
static public boolean hasAncestorClass(@NotNull BindingContext context, @NotNull JetClass classDeclaration) {
public static boolean hasAncestorClass(@NotNull BindingContext context, @NotNull JetClass classDeclaration) {
List<ClassDescriptor> superclassDescriptors = getSuperclassDescriptors(context, classDeclaration);
return (findAncestorClass(superclassDescriptors) != null);
}
static public boolean isStatement(@NotNull BindingContext context, @NotNull JetExpression expression) {
public static boolean isStatement(@NotNull BindingContext context, @NotNull JetExpression expression) {
Boolean isStatement = context.get(BindingContext.STATEMENT, expression);
assert isStatement != null : "Invalid behaviour of get(BindingContext.STATEMENT)";
return isStatement;
}
@NotNull
static public JetType getTypeByReference(@NotNull BindingContext context,
public static JetType getTypeByReference(@NotNull BindingContext context,
@NotNull JetTypeReference typeReference) {
JetType result = context.get(BindingContext.TYPE, typeReference);
assert result != null : "TypeReference should reference a type";
@@ -149,19 +149,19 @@ public final class BindingUtils {
}
@NotNull
static public ClassDescriptor getClassDescriptorForTypeReference(@NotNull BindingContext context,
public static ClassDescriptor getClassDescriptorForTypeReference(@NotNull BindingContext context,
@NotNull JetTypeReference typeReference) {
return getClassDescriptorForType(getTypeByReference(context, typeReference));
}
@Nullable
static public PropertyDescriptor getPropertyDescriptorForConstructorParameter(@NotNull BindingContext context,
public static PropertyDescriptor getPropertyDescriptorForConstructorParameter(@NotNull BindingContext context,
@NotNull JetParameter parameter) {
return context.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter);
}
@Nullable
static public JetProperty getPropertyForDescriptor(@NotNull BindingContext context,
public static JetProperty getPropertyForDescriptor(@NotNull BindingContext context,
@NotNull PropertyDescriptor property) {
PsiElement result = context.get(BindingContext.DESCRIPTOR_TO_DECLARATION, property);
if (!(result instanceof JetProperty)) {
@@ -171,7 +171,7 @@ public final class BindingUtils {
}
@Nullable
static public DeclarationDescriptor getDescriptorForReferenceExpression(@NotNull BindingContext context,
public static DeclarationDescriptor getDescriptorForReferenceExpression(@NotNull BindingContext context,
@NotNull JetReferenceExpression reference) {
return context.get(BindingContext.REFERENCE_TARGET, reference);
}
@@ -182,7 +182,7 @@ public final class BindingUtils {
//TODO move unrelated utils to other class
@Nullable
static public ClassDescriptor findAncestorClass(@NotNull List<ClassDescriptor> superclassDescriptors) {
public static ClassDescriptor findAncestorClass(@NotNull List<ClassDescriptor> superclassDescriptors) {
for (ClassDescriptor descriptor : superclassDescriptors) {
if (descriptor.getKind() == ClassKind.CLASS) {
return descriptor;
@@ -191,11 +191,11 @@ public final class BindingUtils {
return null;
}
static public boolean isOwnedByNamespace(@NotNull DeclarationDescriptor descriptor) {
public static boolean isOwnedByNamespace(@NotNull DeclarationDescriptor descriptor) {
return (descriptor.getContainingDeclaration() instanceof NamespaceDescriptor);
}
static public boolean isOwnedByClass(@NotNull DeclarationDescriptor descriptor) {
public static boolean isOwnedByClass(@NotNull DeclarationDescriptor descriptor) {
return (descriptor.getContainingDeclaration() instanceof ClassDescriptor);
}
@@ -204,31 +204,44 @@ public final class BindingUtils {
@Nullable
public static PropertyDescriptor getPropertyDescriptorForSimpleName(@NotNull BindingContext context,
@NotNull JetSimpleNameExpression expression) {
ResolvedCall<?> resolvedCall =
BindingUtils.getResolvedCall(context, expression);
if (resolvedCall != null) {
DeclarationDescriptor descriptor = resolvedCall.getCandidateDescriptor();
if (descriptor instanceof PropertyDescriptor) {
return (PropertyDescriptor) descriptor;
}
if (descriptor instanceof VariableAsFunctionDescriptor) {
VariableAsFunctionDescriptor functionVariable = (VariableAsFunctionDescriptor) descriptor;
VariableDescriptor variableDescriptor = functionVariable.getVariableDescriptor();
if (variableDescriptor instanceof PropertyDescriptor) {
return (PropertyDescriptor) variableDescriptor;
}
ResolvedCall<?> resolvedCall = BindingUtils.getResolvedCall(context, expression);
if (resolvedCall == null) return null;
DeclarationDescriptor descriptor = resolvedCall.getCandidateDescriptor();
if (descriptor instanceof PropertyDescriptor) {
return (PropertyDescriptor) descriptor;
}
if (descriptor instanceof VariableAsFunctionDescriptor) {
VariableAsFunctionDescriptor functionVariable = (VariableAsFunctionDescriptor) descriptor;
VariableDescriptor variableDescriptor = functionVariable.getVariableDescriptor();
if (variableDescriptor instanceof PropertyDescriptor) {
return (PropertyDescriptor) variableDescriptor;
}
}
return null;
}
@Nullable
static public ResolvedCall<?> getResolvedCall(@NotNull BindingContext context,
public static ResolvedCall<?> getResolvedCall(@NotNull BindingContext context,
@NotNull JetExpression expression) {
return (context.get(BindingContext.RESOLVED_CALL, expression));
}
static public boolean isVariableReassignment(@NotNull BindingContext context, @NotNull JetExpression expression) {
@NotNull
public static FunctionDescriptor getFunctionDescriptorForCallExpression(@NotNull BindingContext context,
@NotNull JetCallExpression expression) {
//TODO: move to PSI utils
JetExpression calleeExpression = expression.getCalleeExpression();
assert calleeExpression != null;
ResolvedCall<?> resolvedCall = getResolvedCall(context, calleeExpression);
//TODO
CallableDescriptor descriptor = resolvedCall.getCandidateDescriptor();
assert descriptor instanceof FunctionDescriptor :
"Callee expression must have resolved call with descriptor of type FunctionDescriptor";
return (FunctionDescriptor) descriptor;
}
public static boolean isVariableReassignment(@NotNull BindingContext context, @NotNull JetExpression expression) {
Boolean result = context.get(BindingContext.VARIABLE_REASSIGNMENT, expression);
assert result != null;
return result;
@@ -4,12 +4,11 @@ import com.google.dart.compiler.backend.js.ast.*;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor;
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.*;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
import org.jetbrains.k2js.translate.general.Translation;
import org.jetbrains.k2js.translate.general.TranslationContext;
@@ -43,8 +42,8 @@ public final class TranslationUtils {
@NotNull
public static List<JsExpression> translateArgumentList(@NotNull List<? extends ValueArgument> jetArguments,
@NotNull TranslationContext context) {
public static List<JsExpression> translateArgumentList(@NotNull TranslationContext context,
@NotNull List<? extends ValueArgument> jetArguments) {
List<JsExpression> jsArguments = new ArrayList<JsExpression>();
for (ValueArgument argument : jetArguments) {
jsArguments.add(translateArgument(context, argument));
@@ -102,15 +101,8 @@ public final class TranslationUtils {
return jsInitExpression;
}
public static boolean isConstructorInvocation(@NotNull TranslationContext context,
@NotNull JetCallExpression expression) {
JetExpression calleeExpression = expression.getCalleeExpression();
assert calleeExpression != null : "JetCallExpression should have not null callee";
ResolvedCall<?> resolvedCall = BindingUtils.getResolvedCall(context.bindingContext(), calleeExpression);
if (resolvedCall == null) {
return false;
}
CallableDescriptor descriptor = resolvedCall.getCandidateDescriptor();
//TODO: move to descriptor UTILS
public static boolean isConstructorDescriptor(@NotNull FunctionDescriptor descriptor) {
return (descriptor instanceof ConstructorDescriptor);
}
@@ -184,4 +176,42 @@ public final class TranslationUtils {
return (context.intrinsics().hasDescriptor(descriptor));
}
@NotNull
public static JsExpression translateBaseExpression(@NotNull TranslationContext context,
@NotNull JetUnaryExpression expression) {
JetExpression baseExpression = getBaseExpression(expression);
return Translation.translateAsExpression(baseExpression, context);
}
//TODO: move to psi utils
@NotNull
public static JetExpression getBaseExpression(@NotNull JetUnaryExpression expression) {
JetExpression baseExpression = expression.getBaseExpression();
assert baseExpression != null : "Unary expression should have a base expression";
return baseExpression;
}
@NotNull
public static JsExpression translateReceiver(@NotNull TranslationContext context,
@NotNull JetDotQualifiedExpression expression) {
return Translation.translateAsExpression(expression.getReceiverExpression(), context);
}
@NotNull
public static JsExpression translateLeftExpression(@NotNull TranslationContext context,
@NotNull JetBinaryExpression expression) {
return Translation.translateAsExpression(expression.getLeft(), context);
}
@NotNull
public static JsExpression translateRightExpression(@NotNull TranslationContext context,
@NotNull JetBinaryExpression expression) {
JetExpression rightExpression = expression.getRight();
assert rightExpression != null : "Binary expression should have a right expression";
return Translation.translateAsExpression(rightExpression, context);
}
}