Rewrote reference translation a bit. Added support for when call expression.

This commit is contained in:
Pavel Talanov
2011-11-21 14:38:15 +04:00
parent 2d84d17555
commit 7d43131173
16 changed files with 178 additions and 67 deletions
@@ -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());
}
}
@@ -78,9 +78,7 @@ public final class ClassBodyVisitor extends TranslatorVisitor<List<JsPropertyIni
@NotNull
private JsFunction generateDefaultGetterFunction(@NotNull JetProperty expression,
@NotNull TranslationContext context) {
JsNameRef backingFieldRef = getBackingFieldName(getPropertyName(expression), context).makeRef();
backingFieldRef.setQualifier(new JsThisRef());
JsReturn returnExpression = new JsReturn(backingFieldRef);
JsReturn returnExpression = new JsReturn(backingFieldReference(expression, context));
return AstUtil.newFunction
(context.enclosingScope(), null, new ArrayList<JsParameter>(), AstUtil.convertToBlock(returnExpression));
}
@@ -108,13 +106,9 @@ public final class ClassBodyVisitor extends TranslatorVisitor<List<JsPropertyIni
@NotNull
private JsBinaryOperation assignmentToBackingFieldFromDefaultParameter
(@NotNull JetProperty expression, @NotNull TranslationContext context, @NotNull JsParameter defaultParameter) {
JsNameRef backingFieldRef = getBackingFieldName(getPropertyName(expression), context).makeRef();
backingFieldRef.setQualifier(new JsThisRef());
JsBinaryOperation assignExpression = new JsBinaryOperation(JsBinaryOperator.ASG);
assignExpression.setArg1(backingFieldRef);
assignExpression.setArg2(defaultParameter.getName().makeRef());
return assignExpression;
(@NotNull JetProperty expression, @NotNull TranslationContext context,
@NotNull JsParameter defaultParameter) {
return AstUtil.newAssignment(backingFieldReference(expression, context), defaultParameter.getName().makeRef());
}
@Override
@@ -249,6 +249,7 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
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<JsNode> {
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);
}
@@ -128,12 +128,8 @@ public class InitializerVisitor extends TranslatorVisitor<List<JsStatement>> {
@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
@@ -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;
}
@@ -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) {
@@ -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);
}
@@ -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);
}
@@ -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);
}
}
@@ -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<T> extends JetVisitor<T, TranslationContext> {
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<T> extends JetVisitor<T, TranslationContext> {
}
@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);
}
@@ -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());
@@ -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");
}
}
@@ -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");
}
}
@@ -0,0 +1,9 @@
namespace foo
class Test() {
val p = true
}
fun box() : Boolean {
return Test().p
}
@@ -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)
}
@@ -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)
}