diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index a2b9194b3dd..381b9217ce2 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -8,15 +8,19 @@
-
-
-
+
+
+
-
+
+
-
-
+
+
+
+
+
@@ -47,21 +51,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -101,94 +90,96 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -198,64 +189,19 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
+
+
+
+
+
+
+
+
+
@@ -273,7 +219,52 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -282,7 +273,7 @@
-
+
@@ -309,22 +300,22 @@
@@ -399,6 +390,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -439,6 +474,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -626,113 +719,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -809,6 +795,111 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -905,11 +996,11 @@
-
-
-
-
-
+
+
+
+
+
localhost
@@ -945,7 +1036,7 @@
-
+
@@ -963,7 +1054,7 @@
-
+
@@ -1007,7 +1098,7 @@
-
+
@@ -1020,7 +1111,6 @@
-
@@ -1045,6 +1135,7 @@
+
@@ -1054,6 +1145,13 @@
+
+
+
+
+
+
+
@@ -1068,6 +1166,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1075,6 +1187,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1082,6 +1215,13 @@
+
+
+
+
+
+
+
@@ -1089,79 +1229,32 @@
-
+
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/js/src/com/google/dart/compiler/util/AstUtil.java b/js/src/com/google/dart/compiler/util/AstUtil.java
index 1b583c11257..09d37bbd348 100644
--- a/js/src/com/google/dart/compiler/util/AstUtil.java
+++ b/js/src/com/google/dart/compiler/util/AstUtil.java
@@ -8,6 +8,7 @@ import com.google.dart.compiler.InternalCompilerException;
import com.google.dart.compiler.backend.js.ast.*;
import com.google.dart.compiler.common.SourceInfo;
+import java.util.Arrays;
import java.util.List;
/**
@@ -320,4 +321,17 @@ public class AstUtil {
public static JsExpression equalsTrue(JsExpression expression, JsProgram program) {
return equals(expression, program.getTrueLiteral());
}
+
+ public static JsBinaryOperation comma(JsExpression... expressions) {
+ return comma(Arrays.asList(expressions));
+ }
+
+ public static JsBinaryOperation comma(List expressions) {
+ assert expressions.size() >= 2 : "Comma operator applicable to two or more expressions";
+ JsBinaryOperation result = new JsBinaryOperation(JsBinaryOperator.COMMA, expressions.get(0), expressions.get(1));
+ for (int i = 2; i < expressions.size(); ++i) {
+ result = new JsBinaryOperation(JsBinaryOperator.COMMA, result, expressions.get(i));
+ }
+ return result;
+ }
}
diff --git a/translator/src/org/jetbrains/k2js/translate/BinaryOperationTranslator.java b/translator/src/org/jetbrains/k2js/translate/BinaryOperationTranslator.java
index 27a11cc4568..4e87c499524 100644
--- a/translator/src/org/jetbrains/k2js/translate/BinaryOperationTranslator.java
+++ b/translator/src/org/jetbrains/k2js/translate/BinaryOperationTranslator.java
@@ -42,7 +42,7 @@ public final class BinaryOperationTranslator extends OperationTranslator {
return translateAsBinaryOperation();
}
- //TODO: think about the ways to improve logic here
+ //TODO: method too long
@Nullable
public JsInvocation translateAsSetterCall() {
JetToken jetOperationToken = getOperationToken();
@@ -50,11 +50,11 @@ public final class BinaryOperationTranslator extends OperationTranslator {
return null;
}
JetExpression leftExpression = expression.getLeft();
- JsInvocation setterCall = Translation.propertyAccessTranslator(translationContext()).
- translateAsPropertySetterCall(leftExpression);
- if (setterCall == null) {
+ PropertyAccessTranslator propertyAccessTranslator = Translation.propertyAccessTranslator(translationContext());
+ if (!propertyAccessTranslator.canBePropertySetterCall(leftExpression)) {
return null;
}
+ JsInvocation setterCall = propertyAccessTranslator.translateAsPropertySetterCall(leftExpression);
JsExpression right = translateRightExpression();
setterCall.setArguments(Arrays.asList(right));
return setterCall;
diff --git a/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java b/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java
index c5872ebd326..c7b051cc1a0 100644
--- a/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java
+++ b/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java
@@ -19,6 +19,12 @@ import java.util.List;
*/
public final class ExpressionVisitor extends TranslatorVisitor {
+ @NotNull
+ private JsExpression translateAsExpression(@NotNull JetExpression expression,
+ @NotNull TranslationContext context) {
+ return AstUtil.convertToExpression(expression.accept(this, context));
+ }
+
@Override
@NotNull
public JsNode visitConstantExpression(@NotNull JetConstantExpression expression,
@@ -157,7 +163,8 @@ public final class ExpressionVisitor extends TranslatorVisitor {
}
@Nullable
- private JsStatement translateElseAsStatement(JetIfExpression expression, TranslationContext context) {
+ private JsStatement translateElseAsStatement(@NotNull JetIfExpression expression,
+ @NotNull TranslationContext context) {
JetExpression jetElse = expression.getElse();
if (jetElse == null) {
return null;
@@ -203,10 +210,6 @@ public final class ExpressionVisitor extends TranslatorVisitor {
return translateAsExpression(expression, context);
}
- private JsExpression translateAsExpression(JetExpression expression, TranslationContext context) {
- return AstUtil.convertToExpression(expression.accept(this, context));
- }
-
@Override
@NotNull
public JsNode visitWhileExpression(@NotNull JetWhileExpression expression, @NotNull TranslationContext context) {
@@ -261,19 +264,13 @@ public final class ExpressionVisitor extends TranslatorVisitor {
@NotNull
private JsExpression translateQualifiedExpression(@NotNull JetQualifiedExpression expression,
@NotNull TranslationContext context) {
- JsInvocation getterCall = translateAsGetterCall(expression, context);
- if (getterCall != null) {
- return getterCall;
+ PropertyAccessTranslator propertyAccessTranslator = Translation.propertyAccessTranslator(context);
+ if (propertyAccessTranslator.canBePropertyGetterCall(expression)) {
+ return propertyAccessTranslator.translateAsPropertyGetterCall(expression);
}
return translateAsQualifiedAccess(expression, context);
}
- @Nullable
- private JsInvocation translateAsGetterCall(@NotNull JetQualifiedExpression expression,
- @NotNull TranslationContext context) {
- return Translation.propertyAccessTranslator(context).resolveAsPropertyGet(expression);
- }
-
@NotNull
private JsExpression translateAsQualifiedAccess(@NotNull JetQualifiedExpression expression,
@NotNull TranslationContext context) {
@@ -386,5 +383,12 @@ public final class ExpressionVisitor extends TranslatorVisitor {
return Translation.functionTranslator(context).translateAsLiteral(expression.getFunctionLiteral());
}
+ @Override
+ @NotNull
+ public JsNode visitThisExpression(@NotNull JetThisExpression expression,
+ @NotNull TranslationContext context) {
+ return new JsThisRef();
+ }
+
}
diff --git a/translator/src/org/jetbrains/k2js/translate/OperationTranslator.java b/translator/src/org/jetbrains/k2js/translate/OperationTranslator.java
index f8998f6fc18..f122d2f8dcf 100644
--- a/translator/src/org/jetbrains/k2js/translate/OperationTranslator.java
+++ b/translator/src/org/jetbrains/k2js/translate/OperationTranslator.java
@@ -1,6 +1,9 @@
package org.jetbrains.k2js.translate;
+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.util.AstUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
@@ -43,4 +46,33 @@ public class OperationTranslator extends AbstractTranslator {
return BindingUtils.getDescriptorForReferenceExpression
(translationContext().bindingContext(), operationReference);
}
+
+
+ protected final class TemporaryVariable {
+
+ @NotNull
+ private final JsExpression assignmentExpression;
+ @NotNull
+ private final JsName variableName;
+
+ private TemporaryVariable(@NotNull JsExpression initExpression) {
+ this.variableName = translationContext().enclosingScope().declareTemporary();
+ this.assignmentExpression = AstUtil.newAssignment(variableName.makeRef(), initExpression);
+ }
+
+ @NotNull
+ public JsNameRef nameReference() {
+ return variableName.makeRef();
+ }
+
+ @NotNull
+ public JsExpression assignmentExpression() {
+ return assignmentExpression;
+ }
+ }
+
+ @NotNull
+ public TemporaryVariable declareTemporary(@NotNull JsExpression initExpression) {
+ return new TemporaryVariable(initExpression);
+ }
}
diff --git a/translator/src/org/jetbrains/k2js/translate/PropertyAccessTranslator.java b/translator/src/org/jetbrains/k2js/translate/PropertyAccessTranslator.java
index 2ef432566fa..6ad3fc4bf4a 100644
--- a/translator/src/org/jetbrains/k2js/translate/PropertyAccessTranslator.java
+++ b/translator/src/org/jetbrains/k2js/translate/PropertyAccessTranslator.java
@@ -23,6 +23,9 @@ import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
//TODO ask for code review. Class has messy code.
public final class PropertyAccessTranslator extends AbstractTranslator {
+ private static String MESSAGE = "Cannot be accessor call. Use canBeProperty*Call to ensure this method " +
+ "can be called safely.";
+
@NotNull
public static PropertyAccessTranslator newInstance(@NotNull TranslationContext context) {
return new PropertyAccessTranslator(context);
@@ -32,28 +35,88 @@ public final class PropertyAccessTranslator extends AbstractTranslator {
super(context);
}
- @Nullable
- public JsInvocation resolveAsPropertyGet(@NotNull JetQualifiedExpression expression) {
- JetExpression selectorExpression = expression.getSelectorExpression();
- assert selectorExpression != null : "Selector should not be null.";
- JsName getterName = getPropertyGetterName(selectorExpression);
- if (getterName == null) {
- return null;
+
+ //TODO: ask if these methods can be more clear
+ public boolean canBePropertyGetterCall(@NotNull JetExpression expression) {
+ if (expression instanceof JetQualifiedExpression) {
+ JetSimpleNameExpression selector = getNullableSelector((JetQualifiedExpression) expression);
+ if (selector == null) {
+ return false;
+ }
+ return (getNullableGetterName(selector) != null);
}
+ if (expression instanceof JetSimpleNameExpression) {
+ return (getNullableGetterName((JetSimpleNameExpression) expression) != null);
+ }
+ return false;
+ }
+
+ public boolean canBePropertyAccess(@NotNull JetExpression expression) {
+ return canBePropertyGetterCall(expression);
+ }
+
+ public boolean canBePropertySetterCall(@NotNull JetExpression expression) {
+ if (expression instanceof JetQualifiedExpression) {
+ JetSimpleNameExpression selector = getNullableSelector((JetQualifiedExpression) expression);
+ if (selector == null) {
+ return false;
+ }
+ return (getNullableSetterName(selector) != null);
+ }
+ if (expression instanceof JetSimpleNameExpression) {
+ return (getNullableSetterName((JetSimpleNameExpression) expression) != null);
+ }
+ return false;
+ }
+
+ @NotNull
+ public JsInvocation translateAsPropertyGetterCall(@NotNull JetExpression expression) {
+ if (expression instanceof JetQualifiedExpression) {
+ return resolveAsPropertyGet((JetQualifiedExpression) expression);
+ }
+ if (expression instanceof JetSimpleNameExpression) {
+ return resolveAsPropertyGet((JetSimpleNameExpression) expression);
+ }
+ throw new AssertionError(MESSAGE);
+ }
+
+ @NotNull
+ private JsInvocation resolveAsPropertyGet(@NotNull JetQualifiedExpression expression) {
+ JsName getterName = getNotNullGetterName(getNotNullSelector(expression));
return translateReceiverAndReturnAccessorInvocation(expression, getterName);
}
- @Nullable
- JsInvocation resolveAsPropertyGet(@NotNull JetSimpleNameExpression expression) {
- JsName getterName = getPropertyGetterName(expression);
- if (getterName == null) {
- return null;
- }
- JsNameRef getterReference =
- TranslationUtils.getReference(translationContext(), expression, getterName);
+ @NotNull
+ private JsInvocation resolveAsPropertyGet(@NotNull JetSimpleNameExpression expression) {
+ JsName getterName = getNotNullGetterName(expression);
+ JsNameRef getterReference = TranslationUtils.getReference(translationContext(), expression, getterName);
return AstUtil.newInvocation(getterReference);
}
+ @NotNull
+ public JsInvocation translateAsPropertySetterCall(@NotNull JetExpression expression) {
+ if (expression instanceof JetDotQualifiedExpression) {
+ return resolveAsPropertySet((JetDotQualifiedExpression) expression);
+ }
+ if (expression instanceof JetSimpleNameExpression) {
+ return resolveAsPropertySet((JetSimpleNameExpression) expression);
+ }
+ throw new AssertionError(MESSAGE);
+ }
+
+ @NotNull
+ private JsInvocation resolveAsPropertySet(@NotNull JetDotQualifiedExpression dotQualifiedExpression) {
+ JsName setterName = getNotNullSetterName(getNotNullSelector(dotQualifiedExpression));
+ return translateReceiverAndReturnAccessorInvocation(dotQualifiedExpression, setterName);
+ }
+
+ @NotNull
+ private JsInvocation resolveAsPropertySet(@NotNull JetSimpleNameExpression expression) {
+ JsName setterName = getNotNullSetterName(expression);
+ JsNameRef setterReference = Translation.generateCorrectReference(translationContext(), expression, setterName);
+ return AstUtil.newInvocation(setterReference);
+ }
+
@NotNull
private JsInvocation translateReceiverAndReturnAccessorInvocation
(@NotNull JetQualifiedExpression qualifiedExpression, @NotNull JsName accessorName) {
@@ -65,39 +128,32 @@ public final class PropertyAccessTranslator extends AbstractTranslator {
}
@Nullable
- public JsInvocation translateAsPropertySetterCall(@NotNull JetExpression expression) {
- if (expression instanceof JetDotQualifiedExpression) {
- return resolveAsPropertySet((JetDotQualifiedExpression) expression);
- }
- if (expression instanceof JetSimpleNameExpression) {
- return resolveAsPropertySet((JetSimpleNameExpression) expression);
- }
- return null;
- }
-
- @Nullable
- private JsInvocation resolveAsPropertySet(@NotNull JetDotQualifiedExpression dotQualifiedExpression) {
- JetExpression selectorExpression = dotQualifiedExpression.getSelectorExpression();
+ private JetSimpleNameExpression getNullableSelector(@NotNull JetQualifiedExpression expression) {
+ JetExpression selectorExpression = expression.getSelectorExpression();
assert selectorExpression != null : "Selector should not be null.";
- JsName setterName = getPropertySetterName(selectorExpression);
- if (setterName == null) {
+ if (!(selectorExpression instanceof JetSimpleNameExpression)) {
return null;
}
- return translateReceiverAndReturnAccessorInvocation(dotQualifiedExpression, setterName);
+ return (JetSimpleNameExpression) selectorExpression;
+ }
+
+
+ @NotNull
+ private JetSimpleNameExpression getNotNullSelector(@NotNull JetQualifiedExpression expression) {
+ JetSimpleNameExpression selectorExpression = getNullableSelector(expression);
+ assert selectorExpression != null : MESSAGE;
+ return selectorExpression;
+ }
+
+ @NotNull
+ private JsName getNotNullGetterName(@NotNull JetSimpleNameExpression selectorExpression) {
+ JsName getterName = getNullableGetterName(selectorExpression);
+ assert getterName != null : MESSAGE;
+ return getterName;
}
@Nullable
- JsInvocation resolveAsPropertySet(@NotNull JetSimpleNameExpression expression) {
- JsName setterName = getPropertySetterName(expression);
- if (setterName == null) {
- return null;
- }
- JsNameRef setterReference = Translation.generateCorrectReference(translationContext(), expression, setterName);
- return AstUtil.newInvocation(setterReference);
- }
-
- @Nullable
- public JsName getPropertyGetterName(@NotNull JetExpression expression) {
+ private JsName getNullableGetterName(@NotNull JetSimpleNameExpression expression) {
PropertyDescriptor property = getPropertyDescriptor(expression);
if (property == null) {
return null;
@@ -109,8 +165,16 @@ public final class PropertyAccessTranslator extends AbstractTranslator {
return translationContext().getNameForDescriptor(getter);
}
+
+ @NotNull
+ private JsName getNotNullSetterName(@NotNull JetSimpleNameExpression selectorExpression) {
+ JsName setterName = getNullableSetterName(selectorExpression);
+ assert setterName != null : MESSAGE;
+ return setterName;
+ }
+
@Nullable
- public JsName getPropertySetterName(@NotNull JetExpression expression) {
+ private JsName getNullableSetterName(@NotNull JetSimpleNameExpression expression) {
PropertyDescriptor property = getPropertyDescriptor(expression);
if (property == null) {
return null;
@@ -123,7 +187,7 @@ public final class PropertyAccessTranslator extends AbstractTranslator {
}
@Nullable
- private PropertyDescriptor getPropertyDescriptor(@NotNull JetExpression expression) {
+ private PropertyDescriptor getPropertyDescriptor(@NotNull JetSimpleNameExpression expression) {
ResolvedCall> resolvedCall =
BindingUtils.getResolvedCall(translationContext().bindingContext(), expression);
if (resolvedCall != null) {
diff --git a/translator/src/org/jetbrains/k2js/translate/ReferenceTranslator.java b/translator/src/org/jetbrains/k2js/translate/ReferenceTranslator.java
index eba33d226df..9f69645da31 100644
--- a/translator/src/org/jetbrains/k2js/translate/ReferenceTranslator.java
+++ b/translator/src/org/jetbrains/k2js/translate/ReferenceTranslator.java
@@ -43,7 +43,12 @@ public class ReferenceTranslator extends AbstractTranslator {
@Nullable
private JsInvocation resolveAsPropertyAccess(@NotNull JetSimpleNameExpression expression) {
- return Translation.propertyAccessTranslator(translationContext()).resolveAsPropertyGet(expression);
+
+ PropertyAccessTranslator propertyAccessTranslator = Translation.propertyAccessTranslator(translationContext());
+ if (propertyAccessTranslator.canBePropertyGetterCall(expression)) {
+ return propertyAccessTranslator.translateAsPropertyGetterCall(expression);
+ }
+ return null;
}
@Nullable
diff --git a/translator/src/org/jetbrains/k2js/translate/TranslationUtils.java b/translator/src/org/jetbrains/k2js/translate/TranslationUtils.java
index 235ce06ceca..68311099c28 100644
--- a/translator/src/org/jetbrains/k2js/translate/TranslationUtils.java
+++ b/translator/src/org/jetbrains/k2js/translate/TranslationUtils.java
@@ -38,5 +38,4 @@ public final class TranslationUtils {
@NotNull String name) {
return context.enclosingScope().findExistingName(name);
}
-
}
diff --git a/translator/src/org/jetbrains/k2js/translate/UnaryOperationTranslator.java b/translator/src/org/jetbrains/k2js/translate/UnaryOperationTranslator.java
index 493061298cd..249b50ee6a0 100644
--- a/translator/src/org/jetbrains/k2js/translate/UnaryOperationTranslator.java
+++ b/translator/src/org/jetbrains/k2js/translate/UnaryOperationTranslator.java
@@ -4,9 +4,12 @@ import com.google.dart.compiler.backend.js.ast.*;
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.lexer.JetToken;
+import java.util.Arrays;
+
/**
* @author Talanov Pavel
*/
@@ -27,34 +30,120 @@ public final class UnaryOperationTranslator extends OperationTranslator {
@NotNull
private final JetUnaryExpression expression;
+ @NotNull
+ private final JsExpression baseExpression;
private final boolean isPrefix;
private final boolean isVariableReassignment;
+ private final boolean isStatement;
+ private final boolean isPropertyAccess;
+ @Nullable
+ private final JsNameRef operationReference;
private UnaryOperationTranslator(@NotNull TranslationContext context, @NotNull JetUnaryExpression expression,
boolean isPrefix) {
super(context);
this.expression = expression;
this.isPrefix = isPrefix;
- this.isVariableReassignment = BindingUtils.isVariableReassignment
+ this.isVariableReassignment = isVariableReassignment(expression);
+ this.isStatement = BindingUtils.isStatement(translationContext().bindingContext(), expression);
+ this.baseExpression = translateBaseExpression();
+ this.isPropertyAccess = isPropertyAccess();
+ this.operationReference = getOverloadedOperationReference(expression);
+ }
+
+ private boolean isPropertyAccess() {
+ return Translation.propertyAccessTranslator(translationContext()).canBePropertyAccess(getBaseExpression());
+
+ }
+
+ private boolean isVariableReassignment(JetUnaryExpression expression) {
+ return BindingUtils.isVariableReassignment
(translationContext().bindingContext(), expression);
}
@NotNull
JsExpression translate() {
- JsExpression baseExpression = translateBaseExpression();
- JsNameRef operationReference = getOverloadedOperationReference(expression);
if (operationReference != null) {
- if (isPrefix && !isVariableReassignment) {
- return overloadedMethodInvocation(baseExpression, operationReference);
- } else if (isPrefix) {
-
- }
+ return translateOverload();
}
- return jsUnaryExpression(baseExpression);
+ return jsUnaryExpression();
}
@NotNull
- private JsExpression jsUnaryExpression(@NotNull JsExpression baseExpression) {
+ private JsExpression translateOverload() {
+ if (isStatement || isPrefix) {
+ return asPrefix();
+ }
+ if (isVariableReassignment) {
+ return asPostfixWithReassignment();
+ } else {
+ return asPostfixWithNoReassignment();
+ }
+ }
+
+ @NotNull
+ private JsExpression asPrefix() {
+ if (isVariableReassignment) {
+ return variableReassignment();
+ }
+ return overloadedMethodInvocation(baseExpression);
+ }
+
+ @NotNull
+ private JsExpression asPostfixWithReassignment() {
+ // code fragment: expr(a++)
+ // generate: expr( (t = a, a = a.inc(), t) )
+ TemporaryVariable t = declareTemporary(baseExpression);
+ JsExpression variableReassignment = variableReassignment();
+ return AstUtil.comma(t.assignmentExpression(), variableReassignment, t.nameReference());
+ }
+
+ @NotNull
+ 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 = overloadedMethodInvocation(t2.nameReference());
+ JsExpression returnedValue = t1.nameReference();
+ return AstUtil.comma(t1.assignmentExpression(), t2.assignmentExpression(), methodCall, returnedValue);
+ }
+
+
+ //TODO: should modify this for properties
+ @NotNull
+ private JsExpression variableReassignment() {
+ if (isPropertyAccess) {
+ return propertyReassignment();
+ }
+ return localVariableReassignment();
+ }
+
+ private JsExpression localVariableReassignment() {
+ assert baseExpression instanceof JsNameRef : "Base expression should be an l-value";
+ return AstUtil.newAssignment((JsNameRef) baseExpression, overloadedMethodInvocation(baseExpression));
+ }
+
+ @NotNull
+ private JsExpression propertyReassignment() {
+ JetExpression jetBaseExpression = getBaseExpression();
+ PropertyAccessTranslator propertyAccessTranslator = Translation.propertyAccessTranslator(translationContext());
+ JsInvocation setterCall = propertyAccessTranslator.translateAsPropertySetterCall(jetBaseExpression);
+ assert propertyAccessTranslator.canBePropertyGetterCall(jetBaseExpression) : "Should be a getter call";
+ JsExpression overloadedMethodCallOnPropertyGetter = overloadedMethodInvocation(baseExpression);
+ setterCall.setArguments(Arrays.asList(overloadedMethodCallOnPropertyGetter));
+ return setterCall;
+ }
+
+ @NotNull
+ private JsExpression overloadedMethodInvocation(@NotNull JsExpression receiver) {
+ AstUtil.setQualifier(operationReference, receiver);
+ return AstUtil.newInvocation(operationReference);
+ }
+
+ @NotNull
+ private JsExpression jsUnaryExpression() {
JsUnaryOperator operator = OperatorTable.getUnaryOperator(getOperationToken());
if (isPrefix) {
return new JsPrefixOperation(operator, baseExpression);
@@ -65,16 +154,14 @@ public final class UnaryOperationTranslator extends OperationTranslator {
@NotNull
private JsExpression translateBaseExpression() {
- JetExpression baseExpression = expression.getBaseExpression();
- assert baseExpression != null : "Unary expression should have a base expression";
+ JetExpression baseExpression = getBaseExpression();
return Translation.translateAsExpression(baseExpression, translationContext());
}
- @NotNull
- private JsExpression overloadedMethodInvocation(@NotNull JsExpression receiver,
- @NotNull JsNameRef operationReference) {
- AstUtil.setQualifier(operationReference, receiver);
- return AstUtil.newInvocation(operationReference);
+ private JetExpression getBaseExpression() {
+ JetExpression baseExpression = expression.getBaseExpression();
+ assert baseExpression != null : "Unary expression should have a base expression";
+ return baseExpression;
}
@NotNull
diff --git a/translator/test/org/jetbrains/k2js/test/OperatorOverloadingTest.java b/translator/test/org/jetbrains/k2js/test/OperatorOverloadingTest.java
index 01e57d2b0cc..60c4a939d53 100644
--- a/translator/test/org/jetbrains/k2js/test/OperatorOverloadingTest.java
+++ b/translator/test/org/jetbrains/k2js/test/OperatorOverloadingTest.java
@@ -28,4 +28,19 @@ public class OperatorOverloadingTest extends TranslationTest {
public void prefixInc() throws Exception {
testFooBoxIsTrue("prefixDecOverload.kt");
}
+
+ @Test
+ public void prefixIncReturnsCorrectValue() throws Exception {
+ testFooBoxIsTrue("prefixIncReturnsCorrectValue.kt");
+ }
+
+ @Test
+ public void overloadedCallOnProperty() throws Exception {
+ testFooBoxIsTrue("overloadedCallOnProperty.kt");
+ }
+
+ @Test
+ public void postfixOnProperty() throws Exception {
+ testFooBoxIsTrue("postfixOnProperty.kt");
+ }
}
diff --git a/translator/testFiles/operatorOverloading/cases/overloadedCallOnProperty.kt b/translator/testFiles/operatorOverloading/cases/overloadedCallOnProperty.kt
new file mode 100644
index 00000000000..6fb191134c1
--- /dev/null
+++ b/translator/testFiles/operatorOverloading/cases/overloadedCallOnProperty.kt
@@ -0,0 +1,17 @@
+namespace foo
+
+var a = MyInt()
+
+class MyInt() {
+ var b = 0
+
+ fun inc() {
+ b = b + 1;
+ }
+}
+
+
+fun box() : Boolean {
+ a++;
+ return (a.b == 1);
+}
\ No newline at end of file
diff --git a/translator/testFiles/operatorOverloading/cases/postfixOnProperty.kt b/translator/testFiles/operatorOverloading/cases/postfixOnProperty.kt
new file mode 100644
index 00000000000..2b2eff8fb5d
--- /dev/null
+++ b/translator/testFiles/operatorOverloading/cases/postfixOnProperty.kt
@@ -0,0 +1,18 @@
+namespace foo
+
+var a = MyInt()
+
+class MyInt() {
+ var b = 0
+
+ fun inc() : MyInt {
+ b = b + 1;
+ return this;
+ }
+}
+
+
+fun box() : Boolean {
+ val d = a++;
+ return (a.b == 1) && (d.b == 1);
+}
\ No newline at end of file
diff --git a/translator/testFiles/operatorOverloading/cases/prefixIncReturnsCorrectValue.kt b/translator/testFiles/operatorOverloading/cases/prefixIncReturnsCorrectValue.kt
new file mode 100644
index 00000000000..841ece2f555
--- /dev/null
+++ b/translator/testFiles/operatorOverloading/cases/prefixIncReturnsCorrectValue.kt
@@ -0,0 +1,17 @@
+namespace foo
+
+class MyInt() {
+ var b = 0
+
+ fun dec() : MyInt {
+ b = b + 1;
+ return this;
+ }
+}
+
+
+ fun box() : Boolean {
+ var c = MyInt()
+ val d = --c;
+ return (c.b == 1);
+ }
\ No newline at end of file