Introduce BackingFieldAccessTranslator.

Refactor AccessTranslationUtils, ReferenceTranslator.
Add test for namespace properties.
This commit is contained in:
pTalanov
2012-03-13 20:16:48 +04:00
parent b3e306ac32
commit e331f27483
15 changed files with 145 additions and 48 deletions
@@ -36,5 +36,9 @@ public class MultiNamespaceTest extends MultipleFilesTranslationTest {
checkFooBoxIsTrue("classesInheritedFromOtherNamespace");
}
public void testNamespaceVariableVisibleFromOtherNamespace() throws Exception {
checkFooBoxIsTrue("namespaceVariableVisibleFromOtherNamespace");
}
}
@@ -142,7 +142,7 @@ public final class PropertyTranslator extends AbstractTranslator {
JsFunction result = context().getFunctionObject(propertySetterDescriptor);
JsParameter defaultParameter =
new JsParameter(propertyAccessContext(propertySetterDescriptor).jsScope().declareTemporary());
JsStatement assignment = assignmentToBackingField(context(), property, defaultParameter.getName().makeRef());
JsStatement assignment = assignmentToBackingField(context(), property, defaultParameter.getName().makeRef()).makeStmt();
setParameters(result, defaultParameter);
result.setBody(convertToBlock(assignment));
return result;
@@ -140,7 +140,7 @@ public final class ClassInitializerTranslator extends AbstractInitializerTransla
getPropertyDescriptorForConstructorParameter(bindingContext(), jetParameter);
if (propertyDescriptor != null) {
JsStatement assignmentToBackingFieldExpression = assignmentToBackingField
(context(), propertyDescriptor, jsParameter.getName().makeRef());
(context(), propertyDescriptor, jsParameter.getName().makeRef()).makeStmt();
initializerStatements.add(assignmentToBackingFieldExpression);
}
}
@@ -16,6 +16,7 @@
package org.jetbrains.k2js.translate.initializer;
import com.google.dart.compiler.backend.js.ast.JsExprStmt;
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.JsStatement;
@@ -33,7 +34,6 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static java.util.Collections.singletonList;
import static org.jetbrains.k2js.translate.general.Translation.translateAsStatement;
import static org.jetbrains.k2js.translate.utils.BindingUtils.getDeclarationsForNamespace;
import static org.jetbrains.k2js.translate.utils.BindingUtils.getPropertyDescriptorForObjectDeclaration;
@@ -62,7 +62,7 @@ public final class InitializerVisitor extends TranslatorVisitor<List<JsStatement
private static JsStatement translateInitializer(@NotNull JetProperty property, @NotNull TranslationContext context,
@NotNull JetExpression initializer) {
JsExpression initExpression = Translation.translateAsExpression(initializer, context);
return assignmentToBackingField(context, property, initExpression);
return assignmentToBackingField(context, property, initExpression).makeStmt();
}
@Override
@@ -87,7 +87,9 @@ public final class InitializerVisitor extends TranslatorVisitor<List<JsStatement
= getPropertyDescriptorForObjectDeclaration(context.bindingContext(), objectName);
JetObjectDeclaration objectDeclaration = getObjectDeclarationForName(objectName);
JsInvocation objectValue = ClassTranslator.generateClassCreationExpression(objectDeclaration, context);
return singletonList(assignmentToBackingField(context, propertyDescriptorForObjectDeclaration, objectValue));
JsExprStmt assignment = assignmentToBackingField(context, propertyDescriptorForObjectDeclaration, objectValue)
.makeStmt();
return Collections.<JsStatement>singletonList(assignment);
}
@NotNull
@@ -28,24 +28,19 @@ public final class AccessTranslationUtils {
private AccessTranslationUtils() {
}
//TODO: this piece of code represents dangerously convoluted logic, think of the ways it can be improved
@NotNull
public static AccessTranslator getAccessTranslator(@NotNull JetExpression referenceExpression,
@NotNull TranslationContext context) {
assert ((referenceExpression instanceof JetReferenceExpression) ||
(referenceExpression instanceof JetQualifiedExpression));
if (PropertyAccessTranslator.canBePropertyAccess(referenceExpression, context)) {
if (referenceExpression instanceof JetQualifiedExpression) {
return QualifiedExpressionTranslator.getAccessTranslator((JetQualifiedExpression) referenceExpression, context);
}
assert referenceExpression instanceof JetSimpleNameExpression;
return PropertyAccessTranslator.newInstance((JetSimpleNameExpression) referenceExpression,
null, CallType.NORMAL, context);
if (referenceExpression instanceof JetQualifiedExpression) {
return QualifiedExpressionTranslator.getAccessTranslator((JetQualifiedExpression) referenceExpression, context);
}
if (referenceExpression instanceof JetArrayAccessExpression) {
return ArrayAccessTranslator.newInstance((JetArrayAccessExpression) referenceExpression, context);
if (referenceExpression instanceof JetSimpleNameExpression) {
return ReferenceTranslator.getAccessTranslator((JetSimpleNameExpression) referenceExpression, context);
}
return ReferenceAccessTranslator.newInstance((JetSimpleNameExpression) referenceExpression, context);
assert referenceExpression instanceof JetArrayAccessExpression;
return ArrayAccessTranslator.newInstance((JetArrayAccessExpression) referenceExpression, context);
}
@NotNull
@@ -0,0 +1,81 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.k2js.translate.reference;
import com.google.dart.compiler.backend.js.ast.JsExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.k2js.translate.context.TemporaryVariable;
import org.jetbrains.k2js.translate.context.TranslationContext;
import org.jetbrains.k2js.translate.general.AbstractTranslator;
import org.jetbrains.k2js.translate.utils.PsiUtils;
import java.util.Collections;
import java.util.List;
import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.assignmentToBackingField;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.backingFieldReference;
/**
* @author Pavel Talanov
*/
public final class BackingFieldAccessTranslator extends AbstractTranslator implements CachedAccessTranslator {
@NotNull
private final PropertyDescriptor descriptor;
/*package*/
static BackingFieldAccessTranslator newInstance(@NotNull JetSimpleNameExpression expression,
@NotNull TranslationContext context) {
assert PsiUtils.isBackingFieldReference(expression);
DeclarationDescriptor referencedProperty = getDescriptorForReferenceExpression(context.bindingContext(), expression);
assert referencedProperty instanceof PropertyDescriptor;
return new BackingFieldAccessTranslator((PropertyDescriptor) referencedProperty, context);
}
private BackingFieldAccessTranslator(@NotNull PropertyDescriptor descriptor, @NotNull TranslationContext context) {
super(context);
this.descriptor = descriptor;
}
@NotNull
@Override
public JsExpression translateAsGet() {
return backingFieldReference(context(), descriptor);
}
@NotNull
@Override
public JsExpression translateAsSet(@NotNull JsExpression setTo) {
return assignmentToBackingField(context(), descriptor, setTo);
}
@NotNull
@Override
public CachedAccessTranslator getCached() {
return this;
}
@NotNull
@Override
public List<TemporaryVariable> declaredTemporaries() {
return Collections.emptyList();
}
}
@@ -16,6 +16,7 @@
package org.jetbrains.k2js.translate.reference;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.k2js.translate.context.TemporaryVariable;
import java.util.List;
@@ -26,5 +27,6 @@ import java.util.List;
* Represents a translator which guaranties that all expression will be computed only once.
*/
public interface CachedAccessTranslator extends AccessTranslator {
@NotNull
List<TemporaryVariable> declaredTemporaries();
}
@@ -57,6 +57,7 @@ public final class CachedArrayAccessTranslator extends ArrayAccessTranslator imp
return translateAsSet(arrayExpression.reference(), toExpressionList(indexExpressions), setTo);
}
@NotNull
@Override
public List<TemporaryVariable> declaredTemporaries() {
List<TemporaryVariable> result = Lists.newArrayList();
@@ -68,6 +68,7 @@ public final class CachedPropertyAccessTranslator implements CachedAccessTransla
return this;
}
@NotNull
@Override
public List<TemporaryVariable> declaredTemporaries() {
return cachedReceiver != null ? singletonList(cachedReceiver) : Collections.<TemporaryVariable>emptyList();
@@ -20,6 +20,7 @@ import com.google.dart.compiler.backend.js.ast.JsExpression;
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.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.k2js.translate.context.TemporaryVariable;
import org.jetbrains.k2js.translate.context.TranslationContext;
@@ -28,6 +29,9 @@ import org.jetbrains.k2js.translate.general.AbstractTranslator;
import java.util.Collections;
import java.util.List;
import static org.jetbrains.k2js.translate.reference.ReferenceTranslator.translateAsLocalNameReference;
import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression;
/**
* @author Pavel Talanov
*/
@@ -36,30 +40,27 @@ public final class ReferenceAccessTranslator extends AbstractTranslator implemen
@NotNull
/*package*/ static ReferenceAccessTranslator newInstance(@NotNull JetSimpleNameExpression expression,
@NotNull TranslationContext context) {
return new ReferenceAccessTranslator(expression, context);
DeclarationDescriptor referenceDescriptor = getDescriptorForReferenceExpression(context.bindingContext(), expression);
return new ReferenceAccessTranslator(referenceDescriptor, context);
}
@NotNull
private final JetSimpleNameExpression expression;
private final JsExpression reference;
private ReferenceAccessTranslator(@NotNull JetSimpleNameExpression expression,
@NotNull TranslationContext context) {
private ReferenceAccessTranslator(@NotNull DeclarationDescriptor descriptor, @NotNull TranslationContext context) {
super(context);
this.expression = expression;
this.reference = translateAsLocalNameReference(descriptor, context());
}
@Override
@NotNull
public JsExpression translateAsGet() {
//TODO: consider evaluating only once
return ReferenceTranslator.translateSimpleName(expression, context());
return reference;
}
@Override
@NotNull
public JsExpression translateAsSet(@NotNull JsExpression toSetTo) {
//TODO: consider evaluating only once
JsExpression reference = ReferenceTranslator.translateSimpleName(expression, context());
assert reference instanceof JsNameRef;
return AstUtil.newAssignment((JsNameRef) reference, toSetTo);
}
@@ -70,6 +71,7 @@ public final class ReferenceAccessTranslator extends AbstractTranslator implemen
return this;
}
@NotNull
@Override
public List<TemporaryVariable> declaredTemporaries() {
return Collections.emptyList();
@@ -23,8 +23,8 @@ import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.k2js.translate.context.TranslationContext;
import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression;
import static org.jetbrains.k2js.translate.utils.JsAstUtils.qualified;
import static org.jetbrains.k2js.translate.utils.PsiUtils.isBackingFieldReference;
/**
* @author Pavel Talanov
@@ -37,12 +37,7 @@ public final class ReferenceTranslator {
@NotNull
public static JsExpression translateSimpleName(@NotNull JetSimpleNameExpression expression,
@NotNull TranslationContext context) {
if (PropertyAccessTranslator.canBePropertyGetterCall(expression, context)) {
return PropertyAccessTranslator.translateAsPropertyGetterCall(expression, null, CallType.NORMAL, context);
}
DeclarationDescriptor referencedDescriptor =
getDescriptorForReferenceExpression(context.bindingContext(), expression);
return translateAsLocalNameReference(referencedDescriptor, context);
return getAccessTranslator(expression, context).translateAsGet();
}
@NotNull
@@ -62,4 +57,15 @@ public final class ReferenceTranslator {
JsName referencedName = context.getNameForDescriptor(referencedDescriptor);
return referencedName.makeRef();
}
public static AccessTranslator getAccessTranslator(JetSimpleNameExpression referenceExpression, TranslationContext context) {
if (isBackingFieldReference(referenceExpression)) {
return BackingFieldAccessTranslator.newInstance(referenceExpression, context);
}
if (PropertyAccessTranslator.canBePropertyAccess(referenceExpression, context)) {
return PropertyAccessTranslator.newInstance(referenceExpression,
null, CallType.NORMAL, context);
}
return ReferenceAccessTranslator.newInstance(referenceExpression, context);
}
}
@@ -201,7 +201,7 @@ public final class BindingUtils {
//TODO: refactor duplication
//TODO: check where we use there, suspicious
//TODO: check where we use these, suspicious
public static boolean isOwnedByNamespace(@NotNull DeclarationDescriptor descriptor) {
if (descriptor instanceof ConstructorDescriptor) {
DeclarationDescriptor classDescriptor = descriptor.getContainingDeclaration();
@@ -30,7 +30,9 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static org.jetbrains.k2js.translate.utils.BindingUtils.*;
import static com.google.dart.compiler.util.AstUtil.newAssignment;
import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptorForOperationExpression;
import static org.jetbrains.k2js.translate.utils.BindingUtils.getPropertyDescriptor;
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getExpectedReceiverDescriptor;
import static org.jetbrains.k2js.translate.utils.JsAstUtils.*;
@@ -77,21 +79,15 @@ public final class TranslationUtils {
public static JsNameRef backingFieldReference(@NotNull TranslationContext context,
@NotNull PropertyDescriptor descriptor) {
JsName backingFieldName = context.getNameForDescriptor(descriptor);
if (isOwnedByClass(descriptor)) {
return qualified(backingFieldName, new JsThisRef());
}
assert isOwnedByNamespace(descriptor)
: "Only classes and namespaces may own backing fields.";
JsNameRef qualifier = context.getQualifierForDescriptor(descriptor);
return qualified(backingFieldName, qualifier);
return qualified(backingFieldName, new JsThisRef());
}
@NotNull
public static JsStatement assignmentToBackingField(@NotNull TranslationContext context,
@NotNull PropertyDescriptor descriptor,
@NotNull JsExpression assignTo) {
public static JsExpression assignmentToBackingField(@NotNull TranslationContext context,
@NotNull PropertyDescriptor descriptor,
@NotNull JsExpression assignTo) {
JsNameRef backingFieldReference = backingFieldReference(context, descriptor);
return newAssignmentStatement(backingFieldReference, assignTo);
return newAssignment(backingFieldReference, assignTo);
}
@Nullable
@@ -223,9 +219,8 @@ public final class TranslationUtils {
}
@NotNull
public static JsStatement assignmentToBackingField(@NotNull TranslationContext context, @NotNull JetProperty property,
@NotNull JsExpression initExpression) {
public static JsExpression assignmentToBackingField(@NotNull TranslationContext context, @NotNull JetProperty property,
@NotNull JsExpression initExpression) {
PropertyDescriptor propertyDescriptor = getPropertyDescriptor(context.bindingContext(), property);
return assignmentToBackingField(context, propertyDescriptor, initExpression);
}
@@ -0,0 +1,5 @@
package foo
val a = 2
fun box() = (a + bar.a) == 5
@@ -0,0 +1,3 @@
package bar
val a = 3