refactor and fix assignment operator on property bug

This commit is contained in:
Pavel Talanov
2011-12-02 20:58:16 +04:00
parent d2b4778029
commit a775c61ccf
18 changed files with 501 additions and 742 deletions
+341 -630
View File
File diff suppressed because it is too large Load Diff
@@ -102,7 +102,8 @@ public final class DeclarationVisitor extends DeclarationDescriptorVisitor<Void,
public void extractAccessor(@Nullable PropertyAccessorDescriptor descriptor, boolean isGetter,
@NotNull String propertyName, @NotNull DeclarationContext context) {
assert descriptor != null : "Accessor descriptor should not be null";
if (descriptor == null) return;
String accessorName = Namer.getNameForAccessor(propertyName, isGetter);
declareName(descriptor, context, accessorName);
declareScope(descriptor, context, (isGetter ? "getter " : "setter ") + propertyName);
@@ -11,6 +11,7 @@ import org.jetbrains.k2js.translate.reference.AccessTranslator;
import static org.jetbrains.k2js.translate.utils.BindingUtils.isVariableReassignment;
import static org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken;
import static org.jetbrains.k2js.translate.utils.PsiUtils.isAssignment;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.isIntrinsicOperation;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateRightExpression;
@@ -22,7 +23,7 @@ public abstract class AssignmentTranslator extends AbstractTranslator {
public static boolean isAssignmentOperator(JetBinaryExpression expression) {
JetToken operationToken = getOperationToken(expression);
return (OperatorConventions.ASSIGNMENT_OPERATIONS.keySet().contains(operationToken)
|| OperatorTable.isAssignment(operationToken));
|| isAssignment(operationToken));
}
@NotNull
@@ -49,8 +50,4 @@ public abstract class AssignmentTranslator extends AbstractTranslator {
this.accessTranslator = AccessTranslator.getAccessTranslator(expression.getLeft(), context());
this.right = translateRightExpression(context(), expression);
}
@NotNull
abstract protected JsExpression translate();
}
@@ -5,10 +5,8 @@ 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.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.psi.JetBinaryExpression;
import org.jetbrains.jet.lang.psi.JetOperationExpression;
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
import org.jetbrains.jet.lexer.JetToken;
import org.jetbrains.jet.lexer.JetTokens;
@@ -20,8 +18,8 @@ import org.jetbrains.k2js.translate.reference.CallTranslator;
import java.util.Arrays;
import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression;
import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptorForOperationExpression;
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.isEquals;
import static org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateLeftExpression;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateRightExpression;
@@ -32,17 +30,6 @@ import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateRight
*/
public final class BinaryOperationTranslator extends AbstractTranslator {
//TODO: move to utils
@NotNull
private static DeclarationDescriptor getOperationDescriptor(@NotNull JetOperationExpression expression,
@NotNull TranslationContext context) {
DeclarationDescriptor descriptorForReferenceExpression = getDescriptorForReferenceExpression
(context.bindingContext(), expression.getOperation());
assert descriptorForReferenceExpression != null;
return descriptorForReferenceExpression;
}
@NotNull
public static JsExpression translate(@NotNull JetBinaryExpression expression,
@NotNull TranslationContext context) {
@@ -68,32 +55,22 @@ public final class BinaryOperationTranslator extends AbstractTranslator {
if (AssignmentTranslator.isAssignmentOperator(expression)) {
return AssignmentTranslator.translate(expression, context());
}
if (operationDescriptor == null) {
return translateAsUnOverloadableBinaryOperation();
}
if (CompareToTranslator.isCompareToCall(expression, context())) {
return CompareToTranslator.translate(expression, context());
}
if (isEqualsCall()) {
if (isEquals(operationDescriptor)) {
return translateAsEqualsCall();
}
if (operationDescriptor == null) {
return translateAsUnOverloadableBinaryOperation();
}
return CallTranslator.translate(expression, context());
}
private boolean isEqualsCall() {
//TODO: add descriptor is equals utils
if (operationDescriptor == null) {
return false;
}
boolean isEquals = operationDescriptor.getName().equals("equals");
boolean isIntrinsic = context().intrinsics().hasDescriptor(operationDescriptor);
return isEquals && isIntrinsic;
}
@NotNull
private JsExpression translateAsEqualsCall() {
Intrinsic intrinsic = context().intrinsics().
getIntrinsic(getOperationDescriptor(expression, context()));
assert operationDescriptor != null : "Equals operation must resolve to descriptor.";
Intrinsic intrinsic = context().intrinsics().getIntrinsic(operationDescriptor);
//TODO
((EqualsIntrinsic) intrinsic).setNegated(expression.getOperationToken().equals(JetTokens.EXCLEQ));
JsExpression left = translateLeftExpression(context(), expression);
@@ -18,6 +18,7 @@ import org.jetbrains.k2js.translate.reference.CallTranslator;
import java.util.Arrays;
import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptorForOperationExpression;
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.isCompareTo;
import static org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.*;
@@ -28,13 +29,12 @@ public final class CompareToTranslator extends AbstractTranslator {
public static boolean isCompareToCall(@NotNull JetBinaryExpression expression,
@NotNull TranslationContext context) {
//move to util
FunctionDescriptor operationDescriptor =
getFunctionDescriptorForOperationExpression(context.bindingContext(), expression);
if (operationDescriptor == null) return false;
return (operationDescriptor.getName().equals("compareTo"));
return (isCompareTo(operationDescriptor));
}
@NotNull
@@ -88,6 +88,4 @@ public final class CompareToTranslator extends AbstractTranslator {
JsExpression right = translateRightExpression(context(), expression);
return intrinsic.apply(left, Arrays.asList(right), context());
}
}
@@ -6,7 +6,6 @@ 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.JetExpression;
import org.jetbrains.jet.lang.psi.JetPrefixExpression;
import org.jetbrains.jet.lang.psi.JetUnaryExpression;
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
import org.jetbrains.k2js.translate.context.TranslationContext;
@@ -15,7 +14,7 @@ import org.jetbrains.k2js.translate.reference.AccessTranslator;
import static org.jetbrains.k2js.translate.utils.BindingUtils.isStatement;
import static org.jetbrains.k2js.translate.utils.BindingUtils.isVariableReassignment;
import static org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken;
import static org.jetbrains.k2js.translate.utils.PsiUtils.*;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.isIntrinsicOperation;
/**
@@ -41,20 +40,14 @@ public abstract class IncrementTranslator extends AbstractTranslator {
protected final JetUnaryExpression expression;
@NotNull
protected final AccessTranslator accessTranslator;
protected final boolean isPrefix;
private final boolean isVariableReassignment;
private final boolean isStatement;
protected IncrementTranslator(@NotNull JetUnaryExpression expression,
@NotNull TranslationContext context) {
super(context);
this.expression = expression;
this.isPrefix = isPrefix(expression);
this.isVariableReassignment = isVariableReassignment(context.bindingContext(), expression);
this.isStatement = isStatement(context().bindingContext(), expression);
//TODO: use util method
JetExpression baseExpression = expression.getBaseExpression();
assert baseExpression != null;
JetExpression baseExpression = getBaseExpression(expression);
this.accessTranslator = AccessTranslator.getAccessTranslator(baseExpression, context());
}
@@ -63,7 +56,7 @@ public abstract class IncrementTranslator extends AbstractTranslator {
@NotNull
protected JsExpression translateAsMethodCall() {
if (isStatement || isPrefix) {
if (returnValueIgnored() || isPrefix(expression)) {
return asPrefix();
}
if (isVariableReassignment) {
@@ -73,6 +66,10 @@ public abstract class IncrementTranslator extends AbstractTranslator {
}
}
private boolean returnValueIgnored() {
return isStatement(context().bindingContext(), expression);
}
@NotNull
private JsExpression asPrefix() {
JsExpression getExpression = accessTranslator.translateAsGet();
@@ -114,11 +111,6 @@ public abstract class IncrementTranslator extends AbstractTranslator {
@NotNull
abstract JsExpression operationExpression(@NotNull JsExpression receiver);
private boolean isPrefix(@NotNull JetUnaryExpression expression) {
return (expression instanceof JetPrefixExpression);
}
//TODO: consider moving into context
protected final class TemporaryVariable {
@@ -1,13 +1,17 @@
package org.jetbrains.k2js.translate.operation;
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.lang.psi.JetBinaryExpression;
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
import org.jetbrains.jet.lexer.JetToken;
import org.jetbrains.k2js.translate.context.TranslationContext;
import org.jetbrains.k2js.translate.reference.ReferenceAccessTranslator;
import static org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken;
import static org.jetbrains.k2js.translate.utils.PsiUtils.isAssignment;
/**
* @author Talanov Pavel
@@ -27,24 +31,56 @@ public final class IntrinsicAssignmentTranslator extends AssignmentTranslator {
}
@NotNull
@Override
protected JsExpression translate() {
return asBinaryOperation();
if (isAssignment(getOperationToken(expression))) {
return translateAsPlainAssignment();
}
return translateAsAssignmentOperation();
}
//TODO: refactor
@NotNull
private JsExpression asBinaryOperation() {
if (OperatorTable.isAssignment(getOperationToken(expression))) {
return accessTranslator.translateAsSet(right);
private JsExpression translateAsAssignmentOperation() {
if (accessTranslator instanceof ReferenceAccessTranslator) {
return translateAsPlainAssignmentOperation();
}
//TODO: logic broken
JetToken token = getOperationToken(expression);
if (OperatorTable.hasCorrespondingBinaryOperator(token)) {
return new JsBinaryOperation(OperatorTable.getBinaryOperator(token),
accessTranslator.translateAsGet(), right);
}
throw new AssertionError("Unsupported token encountered: " + token.toString());
return translateAsAssignToCounterpart();
}
@NotNull
private JsExpression translateAsAssignToCounterpart() {
JsBinaryOperator operator = getCounterpartOperator();
JsBinaryOperation counterpartOperation =
new JsBinaryOperation(operator, accessTranslator.translateAsGet(), right);
return accessTranslator.translateAsSet(counterpartOperation);
}
@NotNull
private JsBinaryOperator getCounterpartOperator() {
JetToken assignmentOperationToken = getOperationToken(expression);
assert OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(assignmentOperationToken);
JetToken counterpartToken = OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(assignmentOperationToken);
assert OperatorTable.hasCorrespondingBinaryOperator(counterpartToken) :
"Unsupported token encountered: " + counterpartToken.toString();
return OperatorTable.getBinaryOperator(counterpartToken);
}
@NotNull
private JsExpression translateAsPlainAssignmentOperation() {
JsBinaryOperator operator = getAssignmentOperator();
return new JsBinaryOperation(operator, accessTranslator.translateAsGet(), right);
}
@NotNull
private JsBinaryOperator getAssignmentOperator() {
JetToken token = getOperationToken(expression);
assert OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(token);
assert OperatorTable.hasCorrespondingBinaryOperator(token) :
"Unsupported token encountered: " + token.toString();
return OperatorTable.getBinaryOperator(token);
}
@NotNull
private JsExpression translateAsPlainAssignment() {
return accessTranslator.translateAsSet(right);
}
}
@@ -9,6 +9,7 @@ import org.jetbrains.k2js.translate.context.TranslationContext;
import org.jetbrains.k2js.translate.reference.ReferenceAccessTranslator;
import static org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken;
import static org.jetbrains.k2js.translate.utils.PsiUtils.isPrefix;
/**
@@ -46,7 +47,7 @@ public final class IntrinsicIncrementTranslator extends IncrementTranslator {
private JsExpression jsUnaryExpression() {
JsUnaryOperator operator = OperatorTable.getUnaryOperator(getOperationToken(expression));
JsExpression getExpression = accessTranslator.translateAsGet();
if (isPrefix) {
if (isPrefix(expression)) {
return new JsPrefixOperation(operator, getExpression);
} else {
return new JsPostfixOperation(operator, getExpression);
@@ -56,16 +57,17 @@ public final class IntrinsicIncrementTranslator extends IncrementTranslator {
@Override
@NotNull
protected JsExpression operationExpression(@NotNull JsExpression receiver) {
return unaryAsBinary(getOperationToken(expression), receiver);
return unaryAsBinary(receiver);
}
public JsBinaryOperation unaryAsBinary(@NotNull JetToken token, @NotNull JsExpression expression) {
public JsBinaryOperation unaryAsBinary(@NotNull JsExpression leftExpression) {
JsNumberLiteral oneLiteral = context().program().getNumberLiteral(1);
JetToken token = getOperationToken(expression);
if (token.equals(JetTokens.PLUSPLUS)) {
return new JsBinaryOperation(JsBinaryOperator.ADD, expression, oneLiteral);
return new JsBinaryOperation(JsBinaryOperator.ADD, leftExpression, oneLiteral);
}
if (token.equals(JetTokens.MINUSMINUS)) {
return new JsBinaryOperation(JsBinaryOperator.SUB, expression, oneLiteral);
return new JsBinaryOperation(JsBinaryOperator.SUB, leftExpression, oneLiteral);
}
throw new AssertionError("This method should be called only for increment and decrement operators");
}
@@ -63,8 +63,4 @@ public final class OperatorTable {
assert JetTokens.OPERATIONS.contains(token) : "Token should represent an operation!";
return unaryOperatorsMap.get(token);
}
static public boolean isAssignment(JetToken token) {
return (token == JetTokens.EQ);
}
}
@@ -36,7 +36,6 @@ public final class OverloadedAssignmentTranslator extends AssignmentTranslator {
this.operationReference = overloadedOperationReference;
}
@Override
@NotNull
protected JsExpression translate() {
if (isVariableReassignment) {
@@ -21,6 +21,7 @@ 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.DescriptorUtils.isConstructorDescriptor;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.*;
/**
@@ -1,7 +1,9 @@
package org.jetbrains.k2js.translate.utils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
/**
* @author Talanov Pavel
@@ -11,7 +13,6 @@ public final class DescriptorUtils {
private DescriptorUtils() {
}
private static int valueParametersCount(@NotNull FunctionDescriptor functionDescriptor) {
return functionDescriptor.getValueParameters().size();
}
@@ -20,4 +21,15 @@ public final class DescriptorUtils {
return (valueParametersCount(functionDescriptor) > 0);
}
public static boolean isEquals(@NotNull FunctionDescriptor functionDescriptor) {
return (functionDescriptor.getName().equals(OperatorConventions.EQUALS));
}
public static boolean isCompareTo(@NotNull FunctionDescriptor functionDescriptor) {
return (functionDescriptor.getName().equals(OperatorConventions.COMPARE_TO));
}
public static boolean isConstructorDescriptor(@NotNull FunctionDescriptor descriptor) {
return (descriptor instanceof ConstructorDescriptor);
}
}
@@ -3,11 +3,9 @@ package org.jetbrains.k2js.translate.utils;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetOperationExpression;
import org.jetbrains.jet.lang.psi.JetQualifiedExpression;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lexer.JetToken;
import org.jetbrains.jet.lexer.JetTokens;
/**
* @author Talanov Pavel
@@ -34,4 +32,19 @@ public final class PsiUtils {
assert elementType instanceof JetToken : "Unary expression should have operation token of type JetToken";
return (JetToken) elementType;
}
@NotNull
public static JetExpression getBaseExpression(@NotNull JetUnaryExpression expression) {
JetExpression baseExpression = expression.getBaseExpression();
assert baseExpression != null;
return baseExpression;
}
public static boolean isPrefix(@NotNull JetUnaryExpression expression) {
return (expression instanceof JetPrefixExpression);
}
public static boolean isAssignment(JetToken token) {
return (token == JetTokens.EQ);
}
}
@@ -4,7 +4,6 @@ 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.ConstructorDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
@@ -72,7 +71,13 @@ public final class TranslationUtils {
public static JsNameRef backingFieldReference(@NotNull TranslationContext context,
@NotNull PropertyDescriptor descriptor) {
JsName backingFieldName = getBackingFieldName(descriptor.getName(), context);
return getThisQualifiedNameReference(context, backingFieldName);
if (BindingUtils.isOwnedByClass(descriptor)) {
return getThisQualifiedNameReference(context, backingFieldName);
}
assert BindingUtils.isOwnedByNamespace(descriptor)
: "Only classes and namespaces may own descriptors";
JsNameRef qualifier = context.declarations().getQualifier(descriptor);
return AstUtil.qualified(backingFieldName, qualifier);
}
@NotNull
@@ -102,11 +107,6 @@ public final class TranslationUtils {
return jsInitExpression;
}
//TODO: move to descriptor UTILS
public static boolean isConstructorDescriptor(@NotNull FunctionDescriptor descriptor) {
return (descriptor instanceof ConstructorDescriptor);
}
@NotNull
public static JsStatement assignmentToBackingFieldFromParameter(@NotNull TranslationContext context,
@NotNull PropertyDescriptor descriptor,
@@ -168,32 +168,13 @@ public final class TranslationUtils {
return result;
}
public static boolean isIntrinsicOperation(@NotNull TranslationContext context,
@NotNull JetReferenceExpression expression) {
DeclarationDescriptor descriptor =
BindingUtils.getDescriptorForReferenceExpression(context.bindingContext(), expression);
if (descriptor == null) return true;
return (context.intrinsics().hasDescriptor(descriptor));
}
@NotNull
public static JsExpression translateBaseExpression(@NotNull TranslationContext context,
@NotNull JetUnaryExpression expression) {
JetExpression baseExpression = getBaseExpression(expression);
JetExpression baseExpression = PsiUtils.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) {
@@ -215,7 +196,6 @@ public final class TranslationUtils {
return Translation.translateAsExpression(rightExpression, context);
}
//TODO: check function with same name
public static boolean isIntrinsicOperation(@NotNull TranslationContext context,
@NotNull JetOperationExpression expression) {
FunctionDescriptor operationDescriptor =
@@ -24,7 +24,6 @@ public class BasicClassTest extends TranslationTest {
testFooBoxIsTrue("methodDeclarationAndCall.kt");
}
//TODO: wait for bugfix and implement properties as constructor parameter declaration
@Test
public void constructorWithParameter() throws Exception {
testFooBoxIsTrue("constructorWithParameter.kt");
@@ -0,0 +1,27 @@
package org.jetbrains.k2js.test;
import org.junit.Test;
/**
* @author Talanov Pavel
*/
public class IntrinsicTest extends AbstractExpressionTest {
final private static String MAIN = "intrinsic/";
@Override
protected String mainDirectory() {
return MAIN;
}
@Test
public void intrinsicPlusAssign() throws Exception {
testFooBoxIsTrue("plusAssign.kt");
}
@Test
public void minusAssignOnProperty() throws Exception {
testFooBoxIsTrue("minusAssignOnProperty.kt");
}
}
@@ -0,0 +1,10 @@
namespace foo
var a = 3
fun box() : Boolean {
a -= 10
return (a == -7)
}
@@ -0,0 +1,8 @@
namespace foo
fun box() : Boolean {
var a = 3
a += 3
return (a == 6)
}