JS backend: ensure enumerability for object literal properties.

Namespace lends annotation improved (root).

(cherry picked from commit 246c001)
This commit is contained in:
develar
2013-08-14 14:56:41 +04:00
committed by Zalim Bashorov
parent 0daf2c6a79
commit 481cee16c5
7 changed files with 61 additions and 59 deletions
@@ -35,6 +35,7 @@ import org.jetbrains.k2js.translate.context.TranslationContext;
import org.jetbrains.k2js.translate.general.AbstractTranslator; import org.jetbrains.k2js.translate.general.AbstractTranslator;
import org.jetbrains.k2js.translate.initializer.ClassInitializerTranslator; import org.jetbrains.k2js.translate.initializer.ClassInitializerTranslator;
import org.jetbrains.k2js.translate.utils.AnnotationsUtils; import org.jetbrains.k2js.translate.utils.AnnotationsUtils;
import org.jetbrains.k2js.translate.utils.JsAstUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@@ -200,14 +201,14 @@ public final class ClassTranslator extends AbstractTranslator {
} }
else { else {
if (qualifiedReference != null) { if (qualifiedReference != null) {
// about "prototype" -- see http://code.google.com/p/jsdoc-toolkit/wiki/TagLends // about "prototype" - see http://code.google.com/p/jsdoc-toolkit/wiki/TagLends
invocationArguments.add(new JsDocComment("lends", new JsNameRef("prototype", qualifiedReference))); invocationArguments.add(new JsDocComment(JsAstUtils.LENDS_JS_DOC_TAG, new JsNameRef("prototype", qualifiedReference)));
} }
invocationArguments.add(new JsObjectLiteral(properties, true)); invocationArguments.add(new JsObjectLiteral(properties, true));
} }
} }
if (hasStaticProperties) { if (hasStaticProperties) {
invocationArguments.add(new JsDocComment("lends", qualifiedReference)); invocationArguments.add(new JsDocComment(JsAstUtils.LENDS_JS_DOC_TAG, qualifiedReference));
invocationArguments.add(new JsObjectLiteral(staticProperties, true)); invocationArguments.add(new JsObjectLiteral(staticProperties, true));
} }
} }
@@ -19,6 +19,7 @@ package org.jetbrains.k2js.translate.declaration;
import com.google.dart.compiler.backend.js.ast.*; import com.google.dart.compiler.backend.js.ast.*;
import gnu.trove.THashMap; import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
@@ -31,6 +32,7 @@ import org.jetbrains.k2js.translate.utils.JsAstUtils;
import java.util.*; import java.util.*;
import static com.google.dart.compiler.backend.js.ast.JsVars.JsVar; import static com.google.dart.compiler.backend.js.ast.JsVars.JsVar;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.getQualifiedReference;
public final class NamespaceDeclarationTranslator extends AbstractTranslator { public final class NamespaceDeclarationTranslator extends AbstractTranslator {
private final Iterable<JetFile> files; private final Iterable<JetFile> files;
@@ -99,23 +101,33 @@ public final class NamespaceDeclarationTranslator extends AbstractTranslator {
rootNamespace = (NamespaceDescriptor) rootNamespace.getContainingDeclaration(); rootNamespace = (NamespaceDescriptor) rootNamespace.getContainingDeclaration();
} }
List<JsExpression> args;
JsObjectLiteral rootNamespaceDefinition = new JsObjectLiteral(true); JsObjectLiteral rootNamespaceDefinition = new JsObjectLiteral(true);
if (context().isEcma5()) { descriptorToDefineInvocation.put(rootNamespace, createDefineInvocation(rootNamespace, null, rootNamespaceDefinition, context()));
args = Arrays.<JsExpression>asList(JsLiteral.NULL, rootNamespaceDefinition); return rootNamespaceDefinition;
}
static List<JsExpression> createDefineInvocation(
@NotNull NamespaceDescriptor descriptor,
@Nullable JsExpression initializer,
@NotNull JsObjectLiteral members,
@NotNull TranslationContext context
) {
if (context.isEcma5()) {
return Arrays.asList(initializer == null ? JsLiteral.NULL : initializer,
new JsDocComment(JsAstUtils.LENDS_JS_DOC_TAG, getQualifiedReference(context, descriptor)),
members);
} }
else { else {
args = Collections.<JsExpression>singletonList(rootNamespaceDefinition); return Collections.<JsExpression>singletonList(members);
} }
descriptorToDefineInvocation.put(rootNamespace, args);
return rootNamespaceDefinition;
} }
private JsVar getDeclaration(@NotNull JsObjectLiteral rootNamespaceDefinition) { private JsVar getDeclaration(@NotNull JsObjectLiteral rootNamespaceDefinition) {
JsExpression packageMapValue; JsExpression packageMapValue;
if (context().isEcma5()) { if (context().isEcma5()) {
packageMapValue = new JsInvocation(JsAstUtils.CREATE_OBJECT, JsLiteral.NULL, rootNamespaceDefinition); packageMapValue = new JsInvocation(JsAstUtils.CREATE_OBJECT, JsLiteral.NULL,
new JsDocComment(JsAstUtils.LENDS_JS_DOC_TAG, Namer.getRootNamespaceName()),
rootNamespaceDefinition);
} }
else { else {
packageMapValue = rootNamespaceDefinition; packageMapValue = rootNamespaceDefinition;
@@ -35,8 +35,6 @@ import org.jetbrains.k2js.translate.utils.AnnotationsUtils;
import org.jetbrains.k2js.translate.utils.BindingUtils; import org.jetbrains.k2js.translate.utils.BindingUtils;
import org.jetbrains.k2js.translate.utils.JsAstUtils; import org.jetbrains.k2js.translate.utils.JsAstUtils;
import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -130,18 +128,11 @@ final class NamespaceTranslator extends AbstractTranslator {
} }
private List<JsPropertyInitializer> getListFromPlace(List<JsExpression> defineInvocation) { private List<JsPropertyInitializer> getListFromPlace(List<JsExpression> defineInvocation) {
return ((JsObjectLiteral) defineInvocation.get(context().isEcma5() ? 1 : 0)).getPropertyInitializers(); return ((JsObjectLiteral) defineInvocation.get(context().isEcma5() ? 2 : 0)).getPropertyInitializers();
} }
private List<JsExpression> createDefineInvocation(@Nullable JsExpression initializer, @NotNull JsObjectLiteral members) { private List<JsExpression> createDefineInvocation(@Nullable JsExpression initializer, @NotNull JsObjectLiteral members) {
if (context().isEcma5()) { return NamespaceDeclarationTranslator.createDefineInvocation(descriptor, initializer, members, context());
return Arrays.asList(initializer == null ? JsLiteral.NULL : initializer,
new JsDocComment("lends", getQualifiedReference(context(), descriptor)),
members);
}
else {
return Collections.<JsExpression>singletonList(members);
}
} }
private JsPropertyInitializer getEntry(@NotNull NamespaceDescriptor descriptor, List<JsExpression> defineInvocation) { private JsPropertyInitializer getEntry(@NotNull NamespaceDescriptor descriptor, List<JsExpression> defineInvocation) {
@@ -154,7 +145,7 @@ final class NamespaceTranslator extends AbstractTranslator {
Map<NamespaceDescriptor, List<JsExpression>> descriptorToDeclarationPlace) { Map<NamespaceDescriptor, List<JsExpression>> descriptorToDeclarationPlace) {
List<JsExpression> parentDefineInvocation = descriptorToDeclarationPlace.get(parentDescriptor); List<JsExpression> parentDefineInvocation = descriptorToDeclarationPlace.get(parentDescriptor);
if (parentDefineInvocation != null) { if (parentDefineInvocation != null) {
((JsObjectLiteral) parentDefineInvocation.get(context().isEcma5() ? 1 : 0)).getPropertyInitializers().add(entry); getListFromPlace(parentDefineInvocation).add(entry);
return true; return true;
} }
return false; return false;
@@ -19,9 +19,7 @@ package org.jetbrains.k2js.translate.initializer;
import com.google.dart.compiler.backend.js.ast.*; import com.google.dart.compiler.backend.js.ast.*;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.Named;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetObjectDeclaration; import org.jetbrains.jet.lang.psi.JetObjectDeclaration;
import org.jetbrains.jet.lang.psi.JetProperty; import org.jetbrains.jet.lang.psi.JetProperty;
@@ -72,16 +70,16 @@ public final class InitializerUtils {
) { ) {
ClassDescriptor descriptor = getClassDescriptor(context.bindingContext(), declaration); ClassDescriptor descriptor = getClassDescriptor(context.bindingContext(), declaration);
JsExpression value = ClassTranslator.generateObjectLiteral(declaration, descriptor, context); JsExpression value = ClassTranslator.generateObjectLiteral(declaration, descriptor, context);
initializers.add(create(descriptor, value, context)); initializers.add(create(descriptor, !(descriptor.getContainingDeclaration() instanceof NamespaceDescriptor), value, context));
} }
public static JsStatement create(Named named, JsExpression value, TranslationContext context) { private static JsStatement create(DeclarationDescriptor descriptor, boolean enumerable, JsExpression value, TranslationContext context) {
JsExpression expression; JsExpression expression;
if (context.isEcma5()) { if (context.isEcma5()) {
expression = JsAstUtils.defineProperty(named.getName().asString(), JsAstUtils.createDataDescriptor(value), context); expression = JsAstUtils.defineProperty(descriptor.getName().asString(), JsAstUtils.createDataDescriptor(value, false, enumerable), context);
} }
else { else {
expression = assignment(new JsNameRef(named.getName().asString(), JsLiteral.THIS), value); expression = assignment(new JsNameRef(descriptor.getName().asString(), JsLiteral.THIS), value);
} }
return expression.makeStmt(); return expression.makeStmt();
} }
@@ -101,8 +101,8 @@ public final class AnnotationsUtils {
} }
ClassDescriptor containingClass = getContainingClass(descriptor); ClassDescriptor containingClass = getContainingClass(descriptor);
return containingClass != null && return containingClass != null &&
(getAnnotationByName(containingClass, ENUMERABLE) != null || ((containingClass.getKind().equals(ClassKind.OBJECT) && containingClass.getName().isSpecial()) ||
(containingClass.getKind().equals(ClassKind.OBJECT) && containingClass.getName().isSpecial())); getAnnotationByName(containingClass, ENUMERABLE) != null);
} }
public static boolean isLibraryObject(@NotNull DeclarationDescriptor descriptor) { public static boolean isLibraryObject(@NotNull DeclarationDescriptor descriptor) {
@@ -39,6 +39,8 @@ public final class JsAstUtils {
private static final JsPropertyInitializer WRITABLE = new JsPropertyInitializer(new JsNameRef("writable"), JsLiteral.TRUE); private static final JsPropertyInitializer WRITABLE = new JsPropertyInitializer(new JsNameRef("writable"), JsLiteral.TRUE);
private static final JsPropertyInitializer ENUMERABLE = new JsPropertyInitializer(new JsNameRef("enumerable"), JsLiteral.TRUE); private static final JsPropertyInitializer ENUMERABLE = new JsPropertyInitializer(new JsNameRef("enumerable"), JsLiteral.TRUE);
public static final String LENDS_JS_DOC_TAG = "lends";
static { static {
JsNameRef globalObjectReference = new JsNameRef("Object"); JsNameRef globalObjectReference = new JsNameRef("Object");
DEFINE_PROPERTY.setQualifier(globalObjectReference); DEFINE_PROPERTY.setQualifier(globalObjectReference);
@@ -228,20 +230,18 @@ public final class JsAstUtils {
} }
@NotNull @NotNull
public static JsInvocation defineProperty(@NotNull String name, public static JsInvocation defineProperty(
@NotNull String name,
@NotNull JsObjectLiteral value, @NotNull JsObjectLiteral value,
@NotNull TranslationContext context) { @NotNull TranslationContext context
JsInvocation invocation = new JsInvocation(DEFINE_PROPERTY); ) {
invocation.getArguments().add(JsLiteral.THIS); return new JsInvocation(DEFINE_PROPERTY, JsLiteral.THIS, context.program().getStringLiteral(name), value);
invocation.getArguments().add(context.program().getStringLiteral(name));
invocation.getArguments().add(value);
return invocation;
} }
@NotNull @NotNull
public static JsStatement defineSimpleProperty(@NotNull String name, @NotNull JsExpression value, @NotNull TranslationContext context) { public static JsStatement defineSimpleProperty(@NotNull String name, @NotNull JsExpression value, @NotNull TranslationContext context) {
if (context.isEcma5()) { if (context.isEcma5()) {
return defineProperty(name, createDataDescriptor(value, false), context).makeStmt(); return defineProperty(name, createDataDescriptor(value, false, false), context).makeStmt();
} else { } else {
return assignment(new JsNameRef(name, JsLiteral.THIS), value).makeStmt(); return assignment(new JsNameRef(name, JsLiteral.THIS), value).makeStmt();
} }
@@ -250,41 +250,41 @@ public final class JsAstUtils {
@NotNull @NotNull
public static JsObjectLiteral createPropertyDataDescriptor(@NotNull FunctionDescriptor descriptor, public static JsObjectLiteral createPropertyDataDescriptor(@NotNull FunctionDescriptor descriptor,
@NotNull JsExpression value) { @NotNull JsExpression value) {
return createPropertyDataDescriptor(descriptor.getModality().isOverridable(), descriptor, value); return createPropertyDataDescriptor(descriptor, descriptor.getModality().isOverridable(), value);
} }
@NotNull @NotNull
public static JsObjectLiteral createDataDescriptor(@NotNull JsExpression value) { public static JsObjectLiteral createDataDescriptor(@NotNull JsExpression value) {
return createDataDescriptor(value, false); return createDataDescriptor(value, false, false);
} }
@NotNull @NotNull
public static JsObjectLiteral createDataDescriptor(@NotNull JsExpression value, boolean writable) { public static JsObjectLiteral createDataDescriptor(@NotNull JsExpression value, boolean writable, boolean enumerable) {
JsObjectLiteral dataDescriptor = new JsObjectLiteral(); JsObjectLiteral dataDescriptor = new JsObjectLiteral();
dataDescriptor.getPropertyInitializers().add(new JsPropertyInitializer(VALUE, value)); dataDescriptor.getPropertyInitializers().add(new JsPropertyInitializer(VALUE, value));
if (writable) { if (writable) {
dataDescriptor.getPropertyInitializers().add(WRITABLE); dataDescriptor.getPropertyInitializers().add(WRITABLE);
} }
return dataDescriptor; if (enumerable) {
}
@NotNull
public static JsObjectLiteral createPropertyDataDescriptor(@NotNull PropertyDescriptor descriptor,
@NotNull JsExpression value) {
return createPropertyDataDescriptor(descriptor.isVar() || descriptor.getModality() == Modality.OPEN, descriptor, value);
}
@NotNull
private static JsObjectLiteral createPropertyDataDescriptor(boolean writable,
@NotNull DeclarationDescriptor descriptor,
@NotNull JsExpression value) {
JsObjectLiteral dataDescriptor = createDataDescriptor(value, writable);
if (AnnotationsUtils.isEnumerable(descriptor)) {
dataDescriptor.getPropertyInitializers().add(ENUMERABLE); dataDescriptor.getPropertyInitializers().add(ENUMERABLE);
} }
return dataDescriptor; return dataDescriptor;
} }
@NotNull
public static JsObjectLiteral createPropertyDataDescriptor(@NotNull PropertyDescriptor descriptor, @NotNull JsExpression value) {
return createPropertyDataDescriptor(descriptor, descriptor.isVar() || descriptor.getModality() == Modality.OPEN, value);
}
@NotNull
private static JsObjectLiteral createPropertyDataDescriptor(
@NotNull DeclarationDescriptor descriptor,
boolean writable,
@NotNull JsExpression value
) {
return createDataDescriptor(value, writable, AnnotationsUtils.isEnumerable(descriptor));
}
@NotNull @NotNull
public static JsFunction createPackage(@NotNull List<JsStatement> to, @NotNull JsScope scope) { public static JsFunction createPackage(@NotNull List<JsStatement> to, @NotNull JsScope scope) {
JsFunction packageBlockFunction = createFunctionWithEmptyBody(scope); JsFunction packageBlockFunction = createFunctionWithEmptyBody(scope);
@@ -64,7 +64,7 @@ public final class TranslationUtils {
@NotNull @NotNull
private static JsPropertyInitializer translateExtensionFunctionAsEcma5DataDescriptor(@NotNull JsFunction function, private static JsPropertyInitializer translateExtensionFunctionAsEcma5DataDescriptor(@NotNull JsFunction function,
@NotNull FunctionDescriptor descriptor, @NotNull TranslationContext context) { @NotNull FunctionDescriptor descriptor, @NotNull TranslationContext context) {
JsObjectLiteral meta = createDataDescriptor(function, descriptor.getModality().isOverridable()); JsObjectLiteral meta = createDataDescriptor(function, descriptor.getModality().isOverridable(), false);
return new JsPropertyInitializer(context.getNameForDescriptor(descriptor).makeRef(), meta); return new JsPropertyInitializer(context.getNameForDescriptor(descriptor).makeRef(), meta);
} }