From 66b3790798602c5178b74e2506c91d0601650475 Mon Sep 17 00:00:00 2001 From: Pavel Talanov Date: Wed, 23 Nov 2011 20:13:23 +0400 Subject: [PATCH] Refactoring operation translator code. --- .idea/workspace.xml | 492 ++++++++++-------- .../translate/BinaryOperationTranslator.java | 105 ++++ .../k2js/translate/BindingUtils.java | 6 + .../k2js/translate/ExpressionVisitor.java | 6 +- .../k2js/translate/OperationTranslator.java | 136 +---- .../jetbrains/k2js/translate/Translation.java | 5 - .../translate/UnaryOperationTranslator.java | 87 ++++ .../jetbrains/k2js/test/KotlinLibTest.java | 6 + .../kotlinLib/cases/commaExpression.js | 6 + 9 files changed, 495 insertions(+), 354 deletions(-) create mode 100644 translator/src/org/jetbrains/k2js/translate/BinaryOperationTranslator.java create mode 100644 translator/src/org/jetbrains/k2js/translate/UnaryOperationTranslator.java create mode 100644 translator/testFiles/kotlinLib/cases/commaExpression.js diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 55a6fbcb1f7..a2b9194b3dd 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -7,17 +7,16 @@ - - - - + + + + - - + @@ -102,94 +101,94 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - - - - - - - - - - + - + - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -199,46 +198,91 @@ - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -265,22 +309,22 @@ @@ -323,21 +367,6 @@ - - - - - - - - - - - @@ -384,11 +413,7 @@ @@ -406,7 +431,7 @@ + + + + + + + + + + + @@ -555,9 +609,9 @@ - - + + @@ -813,17 +867,6 @@ - + @@ -908,8 +962,8 @@ - - + + @@ -953,7 +1007,7 @@ @@ -1000,86 +1054,58 @@ - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - + - + - + - - - - - - - - + @@ -1098,16 +1124,44 @@ - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/translator/src/org/jetbrains/k2js/translate/BinaryOperationTranslator.java b/translator/src/org/jetbrains/k2js/translate/BinaryOperationTranslator.java new file mode 100644 index 00000000000..27a11cc4568 --- /dev/null +++ b/translator/src/org/jetbrains/k2js/translate/BinaryOperationTranslator.java @@ -0,0 +1,105 @@ +package org.jetbrains.k2js.translate; + +import com.google.dart.compiler.backend.js.ast.JsBinaryOperation; +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 org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.psi.JetBinaryExpression; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lexer.JetToken; + +import java.util.Arrays; + +/** + * @author Talanov Pavel + */ +public final class BinaryOperationTranslator extends OperationTranslator { + + @NotNull + static public JsExpression translate(@NotNull JetBinaryExpression expression, + @NotNull TranslationContext context) { + return (new BinaryOperationTranslator(expression, context)).translate(); + } + + @NotNull + private final JetBinaryExpression expression; + + private BinaryOperationTranslator(@NotNull JetBinaryExpression expression, + @NotNull TranslationContext context) { + super(context); + this.expression = expression; + } + + @NotNull + JsExpression translate() { + JsInvocation setterCall = translateAsSetterCall(); + if (setterCall != null) { + return setterCall; + } + return translateAsBinaryOperation(); + } + + //TODO: think about the ways to improve logic here + @Nullable + public JsInvocation translateAsSetterCall() { + JetToken jetOperationToken = getOperationToken(); + if (!OperatorTable.isAssignment(jetOperationToken)) { + return null; + } + JetExpression leftExpression = expression.getLeft(); + JsInvocation setterCall = Translation.propertyAccessTranslator(translationContext()). + translateAsPropertySetterCall(leftExpression); + if (setterCall == null) { + return null; + } + JsExpression right = translateRightExpression(); + setterCall.setArguments(Arrays.asList(right)); + return setterCall; + } + + @NotNull + private JsExpression translateAsBinaryOperation() { + + JsExpression left = Translation.translateAsExpression(expression.getLeft(), translationContext()); + JsExpression right = translateRightExpression(); + + JsNameRef operationReference = getOverloadedOperationReference(expression); + if (operationReference != null) { + return overloadedMethodInvocation(left, right, operationReference); + } + JetToken token = getOperationToken(); + if (OperatorTable.hasCorrespondingBinaryOperator(token)) { + return new JsBinaryOperation(OperatorTable.getBinaryOperator(token), left, right); + } + if (OperatorTable.hasCorrespondingFunctionInvocation(token)) { + JsInvocation functionInvocation = OperatorTable.getCorrespondingFunctionInvocation(token); + functionInvocation.setArguments(Arrays.asList(left, right)); + return functionInvocation; + } + throw new AssertionError("Unsupported token encountered: " + token.toString()); + } + + @NotNull + private JsExpression overloadedMethodInvocation(@NotNull JsExpression left, @NotNull JsExpression right, + @NotNull JsNameRef operationReference) { + AstUtil.setQualifier(operationReference, left); + return AstUtil.newInvocation(operationReference, right); + } + + @NotNull + private JsExpression translateRightExpression() { + JetExpression rightExpression = expression.getRight(); + assert rightExpression != null : "Binary expression should have a right expression"; + return Translation.translateAsExpression(rightExpression, translationContext()); + } + + @NotNull + private JetToken getOperationToken() { + return (JetToken) expression.getOperationToken(); + } + + +} diff --git a/translator/src/org/jetbrains/k2js/translate/BindingUtils.java b/translator/src/org/jetbrains/k2js/translate/BindingUtils.java index cea0f6f2076..3a97c3b2184 100644 --- a/translator/src/org/jetbrains/k2js/translate/BindingUtils.java +++ b/translator/src/org/jetbrains/k2js/translate/BindingUtils.java @@ -172,4 +172,10 @@ public final class BindingUtils { @NotNull JetExpression expression) { return (context.get(BindingContext.RESOLVED_CALL, expression)); } + + static public boolean isVariableReassignment(@NotNull BindingContext context, @NotNull JetExpression expression) { + Boolean result = context.get(BindingContext.VARIABLE_REASSIGNMENT, expression); + assert result != null; + return result; + } } diff --git a/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java b/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java index 22dfd364f83..c5872ebd326 100644 --- a/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java +++ b/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java @@ -81,7 +81,7 @@ public final class ExpressionVisitor extends TranslatorVisitor { @NotNull public JsNode visitBinaryExpression(@NotNull JetBinaryExpression expression, @NotNull TranslationContext context) { - return Translation.operationTranslator(context).translate(expression); + return BinaryOperationTranslator.translate(expression, context); } @Override @@ -320,7 +320,7 @@ public final class ExpressionVisitor extends TranslatorVisitor { @NotNull public JsNode visitPrefixExpression(@NotNull JetPrefixExpression expression, @NotNull TranslationContext context) { - return Translation.operationTranslator(context).translatePrefixOperation(expression); + return UnaryOperationTranslator.translate(expression, context); } @@ -328,7 +328,7 @@ public final class ExpressionVisitor extends TranslatorVisitor { @NotNull public JsNode visitPostfixExpression(@NotNull JetPostfixExpression expression, @NotNull TranslationContext context) { - return Translation.operationTranslator(context).translatePostfixOperation(expression); + return UnaryOperationTranslator.translate(expression, context); } @Override diff --git a/translator/src/org/jetbrains/k2js/translate/OperationTranslator.java b/translator/src/org/jetbrains/k2js/translate/OperationTranslator.java index f4a6efdb004..f8998f6fc18 100644 --- a/translator/src/org/jetbrains/k2js/translate/OperationTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/OperationTranslator.java @@ -1,129 +1,25 @@ package org.jetbrains.k2js.translate; -import com.google.dart.compiler.backend.js.ast.*; -import com.google.dart.compiler.util.AstUtil; -import com.intellij.psi.tree.IElementType; +import com.google.dart.compiler.backend.js.ast.JsNameRef; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.psi.*; -import org.jetbrains.jet.lexer.JetToken; - -import java.util.Arrays; +import org.jetbrains.jet.lang.psi.JetBinaryExpression; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; +import org.jetbrains.jet.lang.psi.JetUnaryExpression; /** * @author Talanov Pavel */ -public final class OperationTranslator extends AbstractTranslator { +public class OperationTranslator extends AbstractTranslator { - @NotNull - static public OperationTranslator newInstance(@NotNull TranslationContext context) { - return new OperationTranslator(context); - } - - private OperationTranslator(@NotNull TranslationContext context) { + protected OperationTranslator(@NotNull TranslationContext context) { super(context); } - @NotNull - JsExpression translatePostfixOperation(@NotNull JetPostfixExpression expression) { - JsExpression baseExpression = translateBaseExpression(expression); - JsNameRef operationReference = getOverloadedOperationReference(expression); - if (operationReference != null) { - return overloadedMethodInvocation(baseExpression, operationReference); - } - JsUnaryOperator operator = OperatorTable.getUnaryOperator(getOperationToken(expression)); - return new JsPostfixOperation(operator, baseExpression); - } - - @NotNull - JsExpression translatePrefixOperation(@NotNull JetPrefixExpression expression) { - JsExpression baseExpression = translateBaseExpression(expression); - JsNameRef operationReference = getOverloadedOperationReference(expression); - if (operationReference != null) { - return overloadedMethodInvocation(baseExpression, operationReference); - } - JsUnaryOperator operator = OperatorTable.getUnaryOperator(getOperationToken(expression)); - return new JsPrefixOperation(operator, baseExpression); - } - - @NotNull - private JsExpression translateBaseExpression(@NotNull JetUnaryExpression expression) { - JetExpression baseExpression = expression.getBaseExpression(); - assert baseExpression != null : "Unary operation should have a base expression"; - return Translation.translateAsExpression(baseExpression, translationContext()); - } - - @NotNull - private JsExpression overloadedMethodInvocation(@NotNull JsExpression base, @NotNull JsNameRef operationReference) { - AstUtil.setQualifier(operationReference, base); - return AstUtil.newInvocation(operationReference); - } - - @NotNull - private JetToken getOperationToken(@NotNull JetUnaryExpression expression) { - JetSimpleNameExpression operationExpression = expression.getOperationSign(); - IElementType elementType = operationExpression.getReferencedNameElementType(); - assert elementType instanceof JetToken : "Unary operation should have IElementType of type JetToken"; - return (JetToken) elementType; - } - - @NotNull - JsExpression translate(@NotNull JetBinaryExpression expression) { - JsInvocation setterCall = translateAsSetterCall(expression); - if (setterCall != null) { - return setterCall; - } - return translateAsBinaryOperation(expression); - } - - //TODO: think about the ways to improve logic here @Nullable - public JsInvocation translateAsSetterCall(@NotNull JetBinaryExpression expression) { - JetToken jetOperationToken = getOperationToken(expression); - if (!OperatorTable.isAssignment(jetOperationToken)) { - return null; - } - JetExpression leftExpression = expression.getLeft(); - JsInvocation setterCall = Translation.propertyAccessTranslator(translationContext()). - translateAsPropertySetterCall(leftExpression); - if (setterCall == null) { - return null; - } - JsExpression right = translateRightExpression(expression); - setterCall.setArguments(Arrays.asList(right)); - return setterCall; - } - - @NotNull - private JsExpression translateAsBinaryOperation(@NotNull JetBinaryExpression expression) { - - JsExpression left = Translation.translateAsExpression(expression.getLeft(), translationContext()); - JsExpression right = translateRightExpression(expression); - - JsNameRef operationReference = getOverloadedOperationReference(expression); - if (operationReference != null) { - return overloadedMethodInvocation(left, right, operationReference); - } - JetToken token = getOperationToken(expression); - if (OperatorTable.hasCorrespondingBinaryOperator(token)) { - return new JsBinaryOperation(OperatorTable.getBinaryOperator(token), left, right); - } - if (OperatorTable.hasCorrespondingFunctionInvocation(token)) { - JsInvocation functionInvocation = OperatorTable.getCorrespondingFunctionInvocation(token); - functionInvocation.setArguments(Arrays.asList(left, right)); - return functionInvocation; - } - throw new AssertionError("Unsupported token encountered: " + token.toString()); - } - - private JsExpression overloadedMethodInvocation(JsExpression left, JsExpression right, JsNameRef operationReference) { - AstUtil.setQualifier(operationReference, left); - return AstUtil.newInvocation(operationReference, right); - } - - @Nullable - private JsNameRef getOverloadedOperationReference(@NotNull JetExpression expression) { + protected JsNameRef getOverloadedOperationReference(@NotNull JetExpression expression) { DeclarationDescriptor operationDescriptor = getOperationDescriptor(expression); if (operationDescriptor == null) { return null; @@ -143,22 +39,8 @@ public final class OperationTranslator extends AbstractTranslator { if (expression instanceof JetUnaryExpression) { operationReference = ((JetUnaryExpression) expression).getOperationSign(); } - assert operationReference != null : "should be applied only to unary or binary operations"; + assert operationReference != null : "Should be applied only to unary or binary operations"; return BindingUtils.getDescriptorForReferenceExpression (translationContext().bindingContext(), operationReference); } - - @NotNull - private JsExpression translateRightExpression(@NotNull JetBinaryExpression expression) { - JetExpression rightExpression = expression.getRight(); - assert rightExpression != null : "Binary expression should have a right expression"; - return Translation.translateAsExpression(rightExpression, translationContext()); - } - - @NotNull - private JetToken getOperationToken(@NotNull JetBinaryExpression expression) { - return (JetToken) expression.getOperationToken(); - } - - } diff --git a/translator/src/org/jetbrains/k2js/translate/Translation.java b/translator/src/org/jetbrains/k2js/translate/Translation.java index 0ce9bc0f75b..1b870236386 100644 --- a/translator/src/org/jetbrains/k2js/translate/Translation.java +++ b/translator/src/org/jetbrains/k2js/translate/Translation.java @@ -44,11 +44,6 @@ public final class Translation { return ClassTranslator.newInstance(context); } - @NotNull - static public OperationTranslator operationTranslator(@NotNull TranslationContext context) { - return OperationTranslator.newInstance(context); - } - @NotNull static public PatternTranslator patternTranslator(@NotNull TranslationContext context) { return PatternTranslator.newInstance(context); diff --git a/translator/src/org/jetbrains/k2js/translate/UnaryOperationTranslator.java b/translator/src/org/jetbrains/k2js/translate/UnaryOperationTranslator.java new file mode 100644 index 00000000000..493061298cd --- /dev/null +++ b/translator/src/org/jetbrains/k2js/translate/UnaryOperationTranslator.java @@ -0,0 +1,87 @@ +package org.jetbrains.k2js.translate; + +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.jet.lang.psi.*; +import org.jetbrains.jet.lexer.JetToken; + +/** + * @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(); + } + + @NotNull + private final JetUnaryExpression expression; + private final boolean isPrefix; + private final boolean isVariableReassignment; + + private UnaryOperationTranslator(@NotNull TranslationContext context, @NotNull JetUnaryExpression expression, + boolean isPrefix) { + super(context); + this.expression = expression; + this.isPrefix = isPrefix; + this.isVariableReassignment = 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 jsUnaryExpression(baseExpression); + } + + @NotNull + private JsExpression jsUnaryExpression(@NotNull JsExpression baseExpression) { + JsUnaryOperator operator = OperatorTable.getUnaryOperator(getOperationToken()); + if (isPrefix) { + return new JsPrefixOperation(operator, baseExpression); + } else { + return new JsPostfixOperation(operator, baseExpression); + } + } + + @NotNull + private JsExpression translateBaseExpression() { + JetExpression baseExpression = expression.getBaseExpression(); + assert baseExpression != null : "Unary expression should have a base expression"; + return Translation.translateAsExpression(baseExpression, translationContext()); + } + + @NotNull + private JsExpression overloadedMethodInvocation(@NotNull JsExpression receiver, + @NotNull JsNameRef operationReference) { + AstUtil.setQualifier(operationReference, receiver); + return AstUtil.newInvocation(operationReference); + } + + @NotNull + private JetToken getOperationToken() { + JetSimpleNameExpression operationExpression = expression.getOperationSign(); + IElementType elementType = operationExpression.getReferencedNameElementType(); + assert elementType instanceof JetToken : "Unary expression should have IElementType of type JetToken"; + return (JetToken) elementType; + } +} diff --git a/translator/test/org/jetbrains/k2js/test/KotlinLibTest.java b/translator/test/org/jetbrains/k2js/test/KotlinLibTest.java index 3c393a51d4f..4f67514c292 100644 --- a/translator/test/org/jetbrains/k2js/test/KotlinLibTest.java +++ b/translator/test/org/jetbrains/k2js/test/KotlinLibTest.java @@ -107,5 +107,11 @@ public class KotlinLibTest extends TranslationTest { new RhinoFunctionResultChecker("test", true)); } + @Test + public void commaExpression() throws Exception { + runRhinoTest(Arrays.asList(kotlinLibraryPath(), cases("commaExpression.js")), + new RhinoFunctionResultChecker("test", true)); + } + } diff --git a/translator/testFiles/kotlinLib/cases/commaExpression.js b/translator/testFiles/kotlinLib/cases/commaExpression.js new file mode 100644 index 00000000000..f145440e08c --- /dev/null +++ b/translator/testFiles/kotlinLib/cases/commaExpression.js @@ -0,0 +1,6 @@ +a = 0 +f = (t = a, t1 = t, a = ++t1, t) + +test = function () { + return (f == 0) && (a == 1) +} \ No newline at end of file