From 7d43131173c12e8a190053ae03be92739cbb90c6 Mon Sep 17 00:00:00 2001 From: Pavel Talanov Date: Mon, 21 Nov 2011 14:38:15 +0400 Subject: [PATCH] Rewrote reference translation a bit. Added support for when call expression. --- .../google/dart/compiler/util/AstUtil.java | 30 +++++++++++ .../k2js/translate/ClassBodyVisitor.java | 14 ++--- .../k2js/translate/ExpressionVisitor.java | 3 +- .../k2js/translate/InitializerVisitor.java | 8 +-- .../k2js/translate/OperationTranslator.java | 2 +- .../k2js/translate/PatternTranslator.java | 2 +- .../translate/PropertyAccessTranslator.java | 8 +-- .../k2js/translate/ReferenceTranslator.java | 42 +++------------ .../k2js/translate/TranslationUtils.java | 51 ++++++++++++++++--- .../k2js/translate/TranslatorVisitor.java | 9 +++- .../k2js/translate/WhenTranslator.java | 18 +++++++ .../jetbrains/k2js/test/BasicClassTest.java | 5 ++ .../k2js/test/PatternMatchingTest.java | 10 ++++ .../testFiles/class/cases/propertyAccess.kt | 9 ++++ .../cases/whenConditionMethodCall.kt | 16 ++++++ .../cases/whenConditionPropertyAccess.kt | 18 +++++++ 16 files changed, 178 insertions(+), 67 deletions(-) create mode 100644 translator/testFiles/class/cases/propertyAccess.kt create mode 100644 translator/testFiles/patternMatching/cases/whenConditionMethodCall.kt create mode 100644 translator/testFiles/patternMatching/cases/whenConditionPropertyAccess.kt diff --git a/js/src/com/google/dart/compiler/util/AstUtil.java b/js/src/com/google/dart/compiler/util/AstUtil.java index 0f34308d100..bf599da1cd7 100644 --- a/js/src/com/google/dart/compiler/util/AstUtil.java +++ b/js/src/com/google/dart/compiler/util/AstUtil.java @@ -289,4 +289,34 @@ public class AstUtil { public static JsBinaryOperation or(JsExpression op1, JsExpression op2) { return new JsBinaryOperation(JsBinaryOperator.OR, op1, op2); } + + public static void setQualifier(JsExpression selector, JsExpression receiver) { + if (selector instanceof JsInvocation) { + setQualifier(((JsInvocation) selector).getQualifier(), receiver); + return; + } + if (selector instanceof JsNameRef) { + JsNameRef nameRef = (JsNameRef) selector; + JsExpression qualifier = nameRef.getQualifier(); + if (qualifier == null) { + nameRef.setQualifier(receiver); + } else { + setQualifier(qualifier, receiver); + } + return; + } + throw new AssertionError("Set qualifier should be applied only to JsInvocation or JsNameRef instances"); + } + + public static JsExpression equals(JsExpression arg1, JsExpression arg2) { + return new JsBinaryOperation(JsBinaryOperator.REF_EQ, arg1, arg2); + } + + public static JsExpression equalsTrue(JsExpression expression, JsProgram program) { + return equals(expression, program.getTrueLiteral()); + } + + public static void thisQualify(JsExpression expression) { + setQualifier(expression, new JsThisRef()); + } } diff --git a/translator/src/org/jetbrains/k2js/translate/ClassBodyVisitor.java b/translator/src/org/jetbrains/k2js/translate/ClassBodyVisitor.java index 57798ae81e9..0efaf5f30bc 100644 --- a/translator/src/org/jetbrains/k2js/translate/ClassBodyVisitor.java +++ b/translator/src/org/jetbrains/k2js/translate/ClassBodyVisitor.java @@ -78,9 +78,7 @@ public final class ClassBodyVisitor extends TranslatorVisitor(), AstUtil.convertToBlock(returnExpression)); } @@ -108,13 +106,9 @@ public final class ClassBodyVisitor extends TranslatorVisitor { return null; } + //TODO: refactor and possibly move somewhere @Override @NotNull public JsNode visitDotQualifiedExpression(@NotNull JetDotQualifiedExpression expression, @@ -343,7 +344,7 @@ public final class ExpressionVisitor extends TranslatorVisitor { JsExpression receiver = translateReceiver(expression, context); JsNullLiteral nullLiteral = context.program().getNullLiteral(); JsExpression thenExpression = translateQualifiedExpression(expression, context); - return new JsConditional(TranslationUtils.notNullCheck(receiver, context), + return new JsConditional(TranslationUtils.notNullCheck(context, receiver), thenExpression, nullLiteral); } diff --git a/translator/src/org/jetbrains/k2js/translate/InitializerVisitor.java b/translator/src/org/jetbrains/k2js/translate/InitializerVisitor.java index 56bb69f26ab..0ca9b05165b 100644 --- a/translator/src/org/jetbrains/k2js/translate/InitializerVisitor.java +++ b/translator/src/org/jetbrains/k2js/translate/InitializerVisitor.java @@ -128,12 +128,8 @@ public class InitializerVisitor extends TranslatorVisitor> { @NotNull JsStatement assignmentToBackingField(@NotNull JetProperty property, @NotNull JsExpression initExpression, @NotNull TranslationContext context) { - String propertyName = property.getName(); - assert propertyName != null : "Named property expected."; - JsName backingFieldName = getBackingFieldName(propertyName, context); - JsNameRef backingFieldRef = backingFieldName.makeRef(); - backingFieldRef.setQualifier(new JsThisRef()); - return AstUtil.newAssignmentStatement(backingFieldRef, initExpression); + + return AstUtil.newAssignmentStatement(backingFieldReference(property, context), initExpression); } @Override diff --git a/translator/src/org/jetbrains/k2js/translate/OperationTranslator.java b/translator/src/org/jetbrains/k2js/translate/OperationTranslator.java index e114768b72c..8a16ccd3af6 100644 --- a/translator/src/org/jetbrains/k2js/translate/OperationTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/OperationTranslator.java @@ -72,7 +72,7 @@ public final class OperationTranslator extends AbstractTranslator { } JetExpression leftExpression = expression.getLeft(); JsInvocation setterCall = Translation.propertyAccessTranslator(translationContext()). - resolveAsPropertySetterCall(leftExpression); + translateAsPropertySetterCall(leftExpression); if (setterCall == null) { return null; } diff --git a/translator/src/org/jetbrains/k2js/translate/PatternTranslator.java b/translator/src/org/jetbrains/k2js/translate/PatternTranslator.java index 0da4906018a..caa33a25633 100644 --- a/translator/src/org/jetbrains/k2js/translate/PatternTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/PatternTranslator.java @@ -63,7 +63,7 @@ public final class PatternTranslator extends AbstractTranslator { @NotNull private JsExpression addNullCheck(@NotNull JsExpression expressionToMatch, @NotNull JsInvocation isCheck) { - return AstUtil.or(TranslationUtils.isNullCheck(expressionToMatch, translationContext()), isCheck); + return AstUtil.or(TranslationUtils.isNullCheck(translationContext(), expressionToMatch), isCheck); } private boolean isNullable(JetTypePattern pattern) { diff --git a/translator/src/org/jetbrains/k2js/translate/PropertyAccessTranslator.java b/translator/src/org/jetbrains/k2js/translate/PropertyAccessTranslator.java index d2998abc05b..462f947525e 100644 --- a/translator/src/org/jetbrains/k2js/translate/PropertyAccessTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/PropertyAccessTranslator.java @@ -49,7 +49,9 @@ public final class PropertyAccessTranslator extends AbstractTranslator { if (getterName == null) { return null; } - return AstUtil.newInvocation(AstUtil.thisQualifiedReference(getterName)); + JsNameRef getterReference = + TranslationUtils.generateCorrectReference(translationContext(), expression, getterName); + return AstUtil.newInvocation(getterReference); } @NotNull @@ -58,12 +60,12 @@ public final class PropertyAccessTranslator extends AbstractTranslator { JsExpression qualifier = Translation.translateAsExpression (qualifiedExpression.getReceiverExpression(), translationContext()); JsNameRef result = accessorName.makeRef(); - result.setQualifier(qualifier); + AstUtil.setQualifier(result, qualifier); return AstUtil.newInvocation(result); } @Nullable - public JsInvocation resolveAsPropertySetterCall(@NotNull JetExpression expression) { + public JsInvocation translateAsPropertySetterCall(@NotNull JetExpression expression) { if (expression instanceof JetDotQualifiedExpression) { return resolveAsPropertySet((JetDotQualifiedExpression) expression); } diff --git a/translator/src/org/jetbrains/k2js/translate/ReferenceTranslator.java b/translator/src/org/jetbrains/k2js/translate/ReferenceTranslator.java index 12cda448210..de16083df46 100644 --- a/translator/src/org/jetbrains/k2js/translate/ReferenceTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/ReferenceTranslator.java @@ -1,11 +1,12 @@ package org.jetbrains.k2js.translate; -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.JsName; 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; /** * @author Talanov Pavel @@ -55,47 +56,16 @@ public class ReferenceTranslator extends AbstractTranslator { return null; } JsName referencedName = translationContext().getNameForDescriptor(referencedDescriptor); - return generateCorrectReference(expression, referencedName); + return TranslationUtils.generateCorrectReference(translationContext(), expression, referencedName); } @Nullable private JsExpression resolveAsLocalReference(@NotNull JetSimpleNameExpression expression) { - JsName localReferencedName = getLocalReferencedName(expression); + JsName localReferencedName = TranslationUtils.getLocalReferencedName(translationContext(), expression); if (localReferencedName == null) { return null; } - return generateCorrectReference(expression, localReferencedName); - } - - @NotNull - private JsNameRef generateCorrectReference(@NotNull JetSimpleNameExpression expression, - @NotNull JsName referencedName) { - JsNameRef result; - if (requiresNamespaceQualifier(referencedName)) { - result = translationContext().getNamespaceQualifiedReference(referencedName); - } else { - result = referencedName.makeRef(); - if (requiresThisQualifier(expression)) { - result.setQualifier(new JsThisRef()); - } - } - return result; - } - - private boolean requiresNamespaceQualifier(@NotNull JsName referencedName) { - return translationContext().namespaceScope().ownsName(referencedName); - } - - private boolean requiresThisQualifier(@NotNull JetSimpleNameExpression expression) { - boolean isClassMember = translationContext().classScope().ownsName(getLocalReferencedName(expression)); - boolean isBackingFieldAccess = expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER; - return isClassMember || isBackingFieldAccess; - } - - @Nullable - private JsName getLocalReferencedName(@NotNull JetSimpleNameExpression expression) { - String referencedName = expression.getReferencedName(); - return translationContext().enclosingScope().findExistingName(referencedName); + return TranslationUtils.generateCorrectReference(translationContext(), expression, localReferencedName); } diff --git a/translator/src/org/jetbrains/k2js/translate/TranslationUtils.java b/translator/src/org/jetbrains/k2js/translate/TranslationUtils.java index f5d36e3b248..b8017f2aeb3 100644 --- a/translator/src/org/jetbrains/k2js/translate/TranslationUtils.java +++ b/translator/src/org/jetbrains/k2js/translate/TranslationUtils.java @@ -1,10 +1,11 @@ package org.jetbrains.k2js.translate; -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 com.google.dart.compiler.backend.js.ast.JsNullLiteral; +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.psi.JetSimpleNameExpression; +import org.jetbrains.jet.lexer.JetTokens; /** * @author Talanov Pavel @@ -12,19 +13,53 @@ import org.jetbrains.annotations.NotNull; public final class TranslationUtils { @NotNull - static public JsBinaryOperation notNullCheck(@NotNull JsExpression expressionToCheck, - @NotNull TranslationContext context) { + static public JsBinaryOperation notNullCheck(@NotNull TranslationContext context, + @NotNull JsExpression expressionToCheck) { JsNullLiteral nullLiteral = context.program().getNullLiteral(); return new JsBinaryOperation (JsBinaryOperator.NEQ, expressionToCheck, nullLiteral); } @NotNull - static public JsBinaryOperation isNullCheck(@NotNull JsExpression expressionToCheck, - @NotNull TranslationContext context) { + static public JsBinaryOperation isNullCheck(@NotNull TranslationContext context, + @NotNull JsExpression expressionToCheck) { JsNullLiteral nullLiteral = context.program().getNullLiteral(); return new JsBinaryOperation (JsBinaryOperator.REF_EQ, expressionToCheck, nullLiteral); } + //TODO: make logic clear + @NotNull + static public JsNameRef generateCorrectReference(@NotNull TranslationContext context, + @NotNull JetSimpleNameExpression expression, + @NotNull JsName referencedName) { + if (requiresNamespaceQualifier(context, referencedName)) { + return context.getNamespaceQualifiedReference(referencedName); + } else if (requiresThisQualifier(context, expression, referencedName)) { + return AstUtil.thisQualifiedReference(referencedName); + } + return referencedName.makeRef(); + } + + static private boolean requiresNamespaceQualifier(@NotNull TranslationContext context, + @NotNull JsName referencedName) { + return context.namespaceScope().ownsName(referencedName); + } + + static private boolean requiresThisQualifier(@NotNull TranslationContext context, + @NotNull JetSimpleNameExpression expression, + @NotNull JsName referencedName) { + JsName name = context.enclosingScope().findExistingName(referencedName.getIdent()); + boolean isClassMember = context.classScope().ownsName(name); + boolean isBackingFieldAccess = expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER; + return isClassMember || isBackingFieldAccess; + } + + @Nullable + static public JsName getLocalReferencedName(@NotNull TranslationContext context, + @NotNull JetSimpleNameExpression expression) { + String referencedName = expression.getReferencedName(); + return context.enclosingScope().findExistingName(referencedName); + } + } diff --git a/translator/src/org/jetbrains/k2js/translate/TranslatorVisitor.java b/translator/src/org/jetbrains/k2js/translate/TranslatorVisitor.java index 26c34290dc2..4ec33f7df8c 100644 --- a/translator/src/org/jetbrains/k2js/translate/TranslatorVisitor.java +++ b/translator/src/org/jetbrains/k2js/translate/TranslatorVisitor.java @@ -2,6 +2,8 @@ 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.psi.*; @@ -22,6 +24,11 @@ public class TranslatorVisitor extends JetVisitor { throw new RuntimeException("Unsupported expression encountered:" + expression.toString()); } + @NotNull + protected JsNameRef backingFieldReference(@NotNull JetProperty expression, @NotNull TranslationContext context) { + return AstUtil.thisQualifiedReference(getBackingFieldName(getPropertyName(expression), context)); + } + @NotNull protected String getPropertyName(@NotNull JetProperty expression) { String propertyName = expression.getName(); @@ -32,7 +39,7 @@ public class TranslatorVisitor extends JetVisitor { } @NotNull - protected JsName getBackingFieldName(@NotNull String propertyName, @NotNull TranslationContext context) { + private JsName getBackingFieldName(@NotNull String propertyName, @NotNull TranslationContext context) { String backingFieldName = Namer.getKotlinBackingFieldName(propertyName); return context.enclosingScope().findExistingName(backingFieldName); } diff --git a/translator/src/org/jetbrains/k2js/translate/WhenTranslator.java b/translator/src/org/jetbrains/k2js/translate/WhenTranslator.java index 4f3c467bb55..de94e3893e8 100644 --- a/translator/src/org/jetbrains/k2js/translate/WhenTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/WhenTranslator.java @@ -138,9 +138,27 @@ public class WhenTranslator extends AbstractTranslator { if (condition instanceof JetWhenConditionIsPattern) { return translatePatternCondition((JetWhenConditionIsPattern) condition); } + if (condition instanceof JetWhenConditionCall) { + return translateCallCondition((JetWhenConditionCall) condition); + } throw new AssertionError("Unsupported when condition " + condition.getClass()); } + @NotNull + private JsExpression translateCallCondition(@NotNull JetWhenConditionCall condition) { + JsExpression suffixExpression = + Translation.translateAsExpression(getSuffixExpression(condition), translationContext()); + AstUtil.setQualifier(suffixExpression, expressionToMatch); + return AstUtil.equalsTrue(suffixExpression, translationContext().program()); + } + + @NotNull + private JetExpression getSuffixExpression(@NotNull JetWhenConditionCall condition) { + JetExpression suffixExpression = condition.getCallSuffixExpression(); + assert suffixExpression != null : "When call condition should have suffix expression"; + return suffixExpression; + } + @NotNull private JsBlock addDummyBreak(@NotNull JsStatement statement) { return AstUtil.newBlock(statement, new JsBreak()); diff --git a/translator/test/org/jetbrains/k2js/test/BasicClassTest.java b/translator/test/org/jetbrains/k2js/test/BasicClassTest.java index efcad3444ce..2a1d665ef13 100644 --- a/translator/test/org/jetbrains/k2js/test/BasicClassTest.java +++ b/translator/test/org/jetbrains/k2js/test/BasicClassTest.java @@ -44,4 +44,9 @@ public class BasicClassTest extends IncludeLibraryTest { public void complexExpressionAsConstructorParameter() throws Exception { testFooBoxIsTrue("complexExpressionAsConstructorParameter.kt"); } + + @Test + public void propertyAccess() throws Exception { + testFooBoxIsTrue("propertyAccess.kt"); + } } diff --git a/translator/test/org/jetbrains/k2js/test/PatternMatchingTest.java b/translator/test/org/jetbrains/k2js/test/PatternMatchingTest.java index caa059f74d5..50af786df8f 100644 --- a/translator/test/org/jetbrains/k2js/test/PatternMatchingTest.java +++ b/translator/test/org/jetbrains/k2js/test/PatternMatchingTest.java @@ -54,4 +54,14 @@ public final class PatternMatchingTest extends IncludeLibraryTest { testFooBoxIsTrue("matchNullableType.kt"); } + @Test + public void whenConditionMethodCall() throws Exception { + testFooBoxIsTrue("whenConditionMethodCall.kt"); + } + + @Test + public void whenConditionPropertyAccess() throws Exception { + testFooBoxIsTrue("whenConditionPropertyAccess.kt"); + } + } diff --git a/translator/testFiles/class/cases/propertyAccess.kt b/translator/testFiles/class/cases/propertyAccess.kt new file mode 100644 index 00000000000..d7f6475999d --- /dev/null +++ b/translator/testFiles/class/cases/propertyAccess.kt @@ -0,0 +1,9 @@ +namespace foo + +class Test() { + val p = true +} + +fun box() : Boolean { + return Test().p +} \ No newline at end of file diff --git a/translator/testFiles/patternMatching/cases/whenConditionMethodCall.kt b/translator/testFiles/patternMatching/cases/whenConditionMethodCall.kt new file mode 100644 index 00000000000..4d9a470d615 --- /dev/null +++ b/translator/testFiles/patternMatching/cases/whenConditionMethodCall.kt @@ -0,0 +1,16 @@ +namespace foo + +class A() { + fun p() = true +} + +fun box() : Boolean { + var a = 0 + when(A()) { + .p() => a-- + is A? => a++; + is A => a++; + else => a++; + } + return (a == -1) +} \ No newline at end of file diff --git a/translator/testFiles/patternMatching/cases/whenConditionPropertyAccess.kt b/translator/testFiles/patternMatching/cases/whenConditionPropertyAccess.kt new file mode 100644 index 00000000000..f6ad5bb9884 --- /dev/null +++ b/translator/testFiles/patternMatching/cases/whenConditionPropertyAccess.kt @@ -0,0 +1,18 @@ +namespace foo + +class A() { + val pp = true + fun p() = true +} + +fun box() : Boolean { + var a = 0 + when(A()) { + .pp => a -=2 + .p() => a-- + is A? => a++; + is A => a++; + else => a++; + } + return (a == -2) +} \ No newline at end of file