From 29391e6c92df0fa947c548d5be172821abd35ef7 Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Mon, 13 Aug 2012 15:18:26 +0400 Subject: [PATCH] Rework logic in class declaration and namespace declaration. Adapted from https://github.com/develar/kotlin/commit/a9e0a42fb1347fa8e21c86b5a073ef8a7c873da0. --- .../jetbrains/k2js/facade/K2JSTranslator.java | 3 +- .../declaration/ClassAliasingMap.java | 4 +- .../ClassDeclarationTranslator.java | 136 +++++----- .../declaration/ClassTranslator.java | 245 ++++++++---------- .../declaration/DeclarationBodyVisitor.java | 97 +++---- .../NamespaceDeclarationTranslator.java | 146 +++++------ .../declaration/NamespaceTranslator.java | 224 ++++++++++------ .../expression/ExpressionVisitor.java | 4 +- .../k2js/translate/general/Translation.java | 26 +- 9 files changed, 440 insertions(+), 445 deletions(-) diff --git a/js/js.translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java b/js/js.translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java index 0176349f8f8..b04384242d0 100644 --- a/js/js.translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java @@ -34,7 +34,6 @@ import java.io.IOException; import java.util.Arrays; import java.util.List; -import static org.jetbrains.k2js.config.Config.withJsLibAdded; import static org.jetbrains.k2js.facade.FacadeUtils.parseString; import static org.jetbrains.k2js.generate.CodeGenerator.generateProgramToString; @@ -93,7 +92,7 @@ public final class K2JSTranslator { throws TranslationException { JetStandardLibrary.initialize(config.getProject()); BindingContext bindingContext = AnalyzerFacadeForJS.analyzeFilesAndCheckErrors(filesToTranslate, config); - return Translation.generateAst(bindingContext, withJsLibAdded(filesToTranslate, config), mainCallParameters, config); + return Translation.generateAst(bindingContext, filesToTranslate, mainCallParameters, config); } @NotNull diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassAliasingMap.java b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassAliasingMap.java index b38863d4232..5797d7b7a79 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassAliasingMap.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassAliasingMap.java @@ -18,9 +18,9 @@ package org.jetbrains.k2js.translate.declaration; import com.google.dart.compiler.backend.js.ast.JsNameRef; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.psi.JetClass; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; public interface ClassAliasingMap { @Nullable - JsNameRef get(JetClass declaration, JetClass referencedDeclaration); + JsNameRef get(ClassDescriptor descriptor, ClassDescriptor referencedDescriptor); } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassDeclarationTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassDeclarationTranslator.java index 7750d07f436..0c5367433a6 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassDeclarationTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassDeclarationTranslator.java @@ -17,6 +17,8 @@ package org.jetbrains.k2js.translate.declaration; import com.google.dart.compiler.backend.js.ast.*; +import com.intellij.openapi.util.Pair; +import com.intellij.util.SmartList; import gnu.trove.THashMap; import gnu.trove.TLinkable; import gnu.trove.TLinkableAdaptor; @@ -26,18 +28,20 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.Modality; import org.jetbrains.jet.lang.psi.JetClass; +import org.jetbrains.jet.lang.psi.JetClassOrObject; +import org.jetbrains.k2js.translate.LabelGenerator; import org.jetbrains.k2js.translate.context.Namer; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.general.AbstractTranslator; -import org.jetbrains.k2js.translate.utils.JsAstUtils; +import org.jetbrains.k2js.translate.initializer.InitializerUtils; import java.util.ArrayList; import java.util.List; +import static com.google.dart.compiler.backend.js.ast.JsVars.JsVar; import static org.jetbrains.k2js.translate.general.Translation.translateClassDeclaration; import static org.jetbrains.k2js.translate.utils.BindingUtils.getClassDescriptor; import static org.jetbrains.k2js.translate.utils.ErrorReportingUtils.message; -import static org.jetbrains.k2js.translate.utils.JsAstUtils.newBlock; /** * @author Pavel Talanov @@ -45,43 +49,44 @@ import static org.jetbrains.k2js.translate.utils.JsAstUtils.newBlock; * Generates a big block where are all the classes(objects representing them) are created. */ public final class ClassDeclarationTranslator extends AbstractTranslator { - private int localNameCounter; + private final LabelGenerator localLabelGenerator = new LabelGenerator('c'); @NotNull - private final THashMap openClassToItem = new THashMap(); + private final THashMap openClassDescriptorToItem = new THashMap(); - private final TLinkedList openList = new TLinkedList(); - private final List finalList = new ArrayList(); + private final TLinkedList openList = new TLinkedList(); + private final List> finalList = new ArrayList>(); @NotNull private final JsFunction dummyFunction; - private final JsName declarationsObject; - private final JsVars.JsVar classesVar; + private final JsNameRef declarationsObjectRef; + private final JsVar classesVar; public ClassDeclarationTranslator(@NotNull TranslationContext context) { super(context); dummyFunction = new JsFunction(context.scope()); - declarationsObject = context().scope().declareName(Namer.nameForClassesVariable()); + JsName declarationsObject = context().scope().declareName(Namer.nameForClassesVariable()); classesVar = new JsVars.JsVar(declarationsObject); + declarationsObjectRef = declarationsObject.makeRef(); } private final class OpenClassRefProvider implements ClassAliasingMap { @Override @Nullable - public JsNameRef get(JetClass declaration, JetClass referencedDeclaration) { - ListItem item = openClassToItem.get(declaration); + public JsNameRef get(ClassDescriptor descriptor, ClassDescriptor referencedDescriptor) { + FinalListItem item = openClassDescriptorToItem.get(descriptor); // class declared in library if (item == null) { return null; } - addAfter(item, openClassToItem.get(referencedDeclaration)); + addAfter(item, openClassDescriptorToItem.get(referencedDescriptor)); return item.label; } - private void addAfter(@NotNull ListItem item, @NotNull ListItem referencedItem) { + private void addAfter(@NotNull FinalListItem item, @NotNull FinalListItem referencedItem) { for (TLinkable link = item.getNext(); link != null; link = link.getNext()) { if (link == referencedItem) { return; @@ -89,65 +94,55 @@ public final class ClassDeclarationTranslator extends AbstractTranslator { } openList.remove(referencedItem); - openList.addBefore((ListItem) item.getNext(), referencedItem); + openList.addBefore((FinalListItem) item.getNext(), referencedItem); } } - private final class FinalClassRefProvider implements ClassAliasingMap { - @Override - public JsNameRef get(JetClass declaration, JetClass referencedDeclaration) { - ListItem item = openClassToItem.get(declaration); - return item == null ? null : item.label; - } - } - - private static class ListItem extends TLinkableAdaptor { + private static class FinalListItem extends TLinkableAdaptor { private final JetClass declaration; private final JsNameRef label; + private final JsNameRef qualifiedLabel; private JsExpression translatedDeclaration; - private ListItem(JetClass declaration, JsNameRef label) { + private FinalListItem(JetClass declaration, JsNameRef label, JsNameRef qualifiedLabel) { this.declaration = declaration; this.label = label; + this.qualifiedLabel = qualifiedLabel; } } @NotNull - public JsVars getDeclarationsStatement() { - JsVars vars = new JsVars(); - vars.add(classesVar); - return vars; + public JsVars.JsVar getDeclaration() { + return classesVar; } public void generateDeclarations() { - JsObjectLiteral valueLiteral = new JsObjectLiteral(); - JsVars vars = new JsVars(); - List propertyInitializers = valueLiteral.getPropertyInitializers(); + List vars = new SmartList(); + List propertyInitializers = new SmartList(); generateOpenClassDeclarations(vars, propertyInitializers); - generateFinalClassDeclarations(vars, propertyInitializers); + generateFinalClassDeclarations(); if (vars.isEmpty()) { - classesVar.setInitExpression(valueLiteral); + if (!propertyInitializers.isEmpty()) { + classesVar.setInitExpression(new JsObjectLiteral(propertyInitializers)); + } return; } - List result = new ArrayList(); - result.add(vars); - result.add(new JsReturn(valueLiteral)); - dummyFunction.setBody(newBlock(result)); + dummyFunction.setBody(new JsBlock(new JsVars(vars, true), new JsReturn(new JsObjectLiteral(propertyInitializers)))); classesVar.setInitExpression(new JsInvocation(dummyFunction)); } - private void generateOpenClassDeclarations(@NotNull JsVars vars, @NotNull List propertyInitializers) { + private void generateOpenClassDeclarations(@NotNull List vars, @NotNull List propertyInitializers) { ClassAliasingMap classAliasingMap = new OpenClassRefProvider(); // first pass: set up list order - for (ListItem item : openList) { + for (FinalListItem item : openList) { item.translatedDeclaration = translateClassDeclaration(item.declaration, classAliasingMap, context()); } // second pass: generate - for (ListItem item : openList) { + for (FinalListItem item : openList) { JsExpression translatedDeclaration = item.translatedDeclaration; if (translatedDeclaration == null) { throw new IllegalStateException(message(item.declaration, "Could not translate class declaration)")); @@ -156,24 +151,31 @@ public final class ClassDeclarationTranslator extends AbstractTranslator { } } - private void generateFinalClassDeclarations(@NotNull JsVars vars, @NotNull List propertyInitializers) { - ClassAliasingMap classAliasingMap = new FinalClassRefProvider(); - for (ListItem item : finalList) { - generate(item, propertyInitializers, translateClassDeclaration(item.declaration, classAliasingMap, context()), vars); + private void generateFinalClassDeclarations() { + ClassAliasingMap aliasingMap = new ClassAliasingMap() { + @Override + public JsNameRef get(ClassDescriptor descriptor, ClassDescriptor referencedDescriptor) { + FinalListItem item = openClassDescriptorToItem.get(descriptor); + return item == null ? null : item.qualifiedLabel; + } + }; + + for (Pair item : finalList) { + new ClassTranslator(item.first, aliasingMap, context()).translateClassOrObjectCreation(item.second); } } - private static void generate(@NotNull ListItem item, + private static void generate(@NotNull FinalListItem item, @NotNull List propertyInitializers, @NotNull JsExpression definition, - @NotNull JsVars vars) { + @NotNull List vars) { JsExpression value; if (item.label.getName() == null) { value = definition; } else { assert item.label.getName() != null; - vars.add(new JsVars.JsVar(item.label.getName(), definition)); + vars.add(new JsVar(item.label.getName(), definition)); value = item.label; } @@ -181,38 +183,24 @@ public final class ClassDeclarationTranslator extends AbstractTranslator { } @NotNull - public JsPropertyInitializer translateAndGetClassNameToClassObject(@NotNull JetClass declaration) { + public JsPropertyInitializer translate(@NotNull JetClassOrObject declaration) { ClassDescriptor descriptor = getClassDescriptor(context().bindingContext(), declaration); - - JsNameRef labelRef; - String label = 'c' + Integer.toString(localNameCounter++, 36); - boolean isFinal = descriptor.getModality() == Modality.FINAL; - if (isFinal) { - labelRef = new JsNameRef(label); - } - else { - labelRef = dummyFunction.getScope().declareName(label).makeRef(); - } - - ListItem item = new ListItem(declaration, labelRef); - if (isFinal) { - finalList.add(item); - } - else { - openList.add(item); - openClassToItem.put(declaration, item); - } - - JsNameRef qualifiedLabelRef = new JsNameRef(labelRef.getIdent()); - qualifiedLabelRef.setQualifier(declarationsObject.makeRef()); JsExpression value; - if (context().isEcma5()) { - value = JsAstUtils.createDataDescriptor(qualifiedLabelRef); + if (descriptor.getModality() == Modality.FINAL) { + JsInvocation invocation = context().namer().classCreateInvocation(descriptor); + finalList.add(new Pair(declaration, invocation)); + value = invocation; } else { - value = qualifiedLabelRef; + String label = localLabelGenerator.generate(); + JsNameRef labelRef = dummyFunction.getScope().declareName(label).makeRef(); + FinalListItem item = new FinalListItem((JetClass) declaration, labelRef, new JsNameRef(labelRef.getIdent(), declarationsObjectRef)); + openList.add(item); + openClassDescriptorToItem.put(descriptor, item); + + value = item.qualifiedLabel; } - return new JsPropertyInitializer(context().program().getStringLiteral(descriptor.getName().getName()), value); + return InitializerUtils.createPropertyInitializer(descriptor, value, context()); } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassTranslator.java index aba423e53c9..c9788084588 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassTranslator.java @@ -17,32 +17,34 @@ package org.jetbrains.k2js.translate.declaration; import com.google.dart.compiler.backend.js.ast.*; +import com.intellij.util.SmartList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ClassKind; import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; -import org.jetbrains.jet.lang.psi.*; -import org.jetbrains.jet.lang.resolve.DescriptorUtils; -import org.jetbrains.k2js.translate.context.TemporaryVariable; +import org.jetbrains.jet.lang.psi.JetClassOrObject; +import org.jetbrains.jet.lang.psi.JetObjectLiteralExpression; +import org.jetbrains.jet.lang.psi.JetParameter; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.k2js.translate.context.Namer; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.general.AbstractTranslator; import org.jetbrains.k2js.translate.general.Translation; -import org.jetbrains.k2js.translate.initializer.InitializerUtils; -import org.jetbrains.k2js.translate.utils.BindingUtils; -import org.jetbrains.k2js.translate.utils.JsAstUtils; +import org.jetbrains.k2js.translate.utils.AnnotationsUtils; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.List; -import static com.google.dart.compiler.util.AstUtil.newSequence; +import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getClassDescriptorForType; +import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isNotAny; import static org.jetbrains.k2js.translate.utils.BindingUtils.getClassDescriptor; import static org.jetbrains.k2js.translate.utils.BindingUtils.getPropertyDescriptorForConstructorParameter; -import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.findAncestorClass; import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getContainingClass; import static org.jetbrains.k2js.translate.utils.PsiUtils.getPrimaryConstructorParameters; import static org.jetbrains.k2js.translate.utils.TranslationUtils.getQualifiedReference; -import static org.jetbrains.k2js.translate.utils.TranslationUtils.getThisObject; /** * @author Pavel Talanov @@ -50,114 +52,105 @@ import static org.jetbrains.k2js.translate.utils.TranslationUtils.getThisObject; * Generates a definition of a single class. */ public final class ClassTranslator extends AbstractTranslator { - - @NotNull - public static JsPropertyInitializer translateAsProperty(@NotNull JetClassOrObject classDeclaration, - @NotNull TranslationContext context) { - JsExpression classCreationExpression = - generateClassCreationExpression(classDeclaration, context); - JsName className = context.getNameForElement(classDeclaration); - return new JsPropertyInitializer(className.makeRef(), classCreationExpression); - } - - @NotNull - public static JsExpression generateClassCreationExpression(@NotNull JetClassOrObject classDeclaration, - @NotNull ClassAliasingMap aliasingMap, - @NotNull TranslationContext context) { - return (new ClassTranslator(classDeclaration, aliasingMap, context)).translateClassOrObjectCreation(); - } - - @NotNull - public static JsExpression generateClassCreationExpression(@NotNull JetClassOrObject classDeclaration, - @NotNull TranslationContext context) { - return (new ClassTranslator(classDeclaration, null, context)).translateClassOrObjectCreation(); - } - - @NotNull - public static JsExpression generateObjectLiteralExpression(@NotNull JetObjectLiteralExpression objectLiteralExpression, - @NotNull TranslationContext outerContext) { - JetObjectDeclaration objectDeclaration = objectLiteralExpression.getObjectDeclaration(); - ClassTranslator classTranslator = new ClassTranslator(objectDeclaration, null, outerContext); - ClassDescriptor containingClass = getContainingClass(classTranslator.descriptor); - if (containingClass == null) { - return classTranslator.translateClassOrObjectCreation(); - } - return classTranslator.translateObjectLiteralWithThisAliased(containingClass, outerContext); - } - - @NotNull private final DeclarationBodyVisitor declarationBodyVisitor = new DeclarationBodyVisitor(); @NotNull private final JetClassOrObject classDeclaration; - @Nullable - private TemporaryVariable aliasForContainingClassThis = null; - @NotNull private final ClassDescriptor descriptor; @Nullable private final ClassAliasingMap aliasingMap; - private ClassTranslator(@NotNull JetClassOrObject classDeclaration, + @NotNull + public static JsExpression generateClassCreation(@NotNull JetClassOrObject classDeclaration, + @NotNull ClassAliasingMap aliasingMap, + @NotNull TranslationContext context) { + return new ClassTranslator(classDeclaration, aliasingMap, context).translateClassOrObjectCreation(context); + } + + @NotNull + public static JsExpression generateClassCreation(@NotNull JetClassOrObject classDeclaration, @NotNull TranslationContext context) { + return new ClassTranslator(classDeclaration, null, context).translateClassOrObjectCreation(context); + } + + @NotNull + public static JsExpression generateClassCreation(@NotNull JetClassOrObject classDeclaration, + @NotNull ClassDescriptor descriptor, + @NotNull TranslationContext context) { + return new ClassTranslator(classDeclaration, descriptor, null, context).translateClassOrObjectCreation(context); + } + + @NotNull + public static JsExpression generateObjectLiteral(@NotNull JetObjectLiteralExpression objectLiteralExpression, + @NotNull TranslationContext context) { + return new ClassTranslator(objectLiteralExpression.getObjectDeclaration(), null, context).translateObjectLiteralExpression(); + } + + ClassTranslator(@NotNull JetClassOrObject classDeclaration, @Nullable ClassAliasingMap aliasingMap, @NotNull TranslationContext context) { - super(context.newDeclaration(classDeclaration)); + this(classDeclaration, getClassDescriptor(context.bindingContext(), classDeclaration), aliasingMap, context); + } + + ClassTranslator(@NotNull JetClassOrObject classDeclaration, + @NotNull ClassDescriptor descriptor, + @Nullable ClassAliasingMap aliasingMap, + @NotNull TranslationContext context) { + super(context); this.aliasingMap = aliasingMap; - this.descriptor = getClassDescriptor(context.bindingContext(), classDeclaration); + this.descriptor = descriptor; this.classDeclaration = classDeclaration; } @NotNull - private JsExpression translateClassOrObjectCreation() { - JsInvocation jsClassDeclaration = classCreateMethodInvocation(); - if (!isObject()) { - addSuperclassReferences(jsClassDeclaration); + private JsExpression translateObjectLiteralExpression() { + ClassDescriptor containingClass = getContainingClass(descriptor); + if (containingClass == null) { + return translateClassOrObjectCreation(context()); } - addClassOwnDeclarations(jsClassDeclaration); - return jsClassDeclaration; + return translateAsObjectCreationExpressionWithEnclosingThisSaved(containingClass); } @NotNull - private JsInvocation classCreateMethodInvocation() { - if (isObject()) { - return new JsInvocation(context().namer().objectCreationMethodReference()); - } - else if (isTrait() && !context().isEcma5()) { - return new JsInvocation(context().namer().traitCreationMethodReference()); - } - else { - return new JsInvocation(context().namer().classCreationMethodReference()); - } + private JsExpression translateAsObjectCreationExpressionWithEnclosingThisSaved(@NotNull ClassDescriptor containingClass) { + return context().literalFunctionTranslator().translate(containingClass, classDeclaration, descriptor, this); } - private boolean isObject() { - return descriptor.getKind().equals(ClassKind.OBJECT); + @NotNull + public JsExpression translateClassOrObjectCreation(@NotNull TranslationContext declarationContext) { + JsInvocation createInvocation = context().namer().classCreateInvocation(descriptor); + translateClassOrObjectCreation(createInvocation, declarationContext); + return createInvocation; + } + + public void translateClassOrObjectCreation(@NotNull JsInvocation createInvocation) { + translateClassOrObjectCreation(createInvocation, context()); + } + + private void translateClassOrObjectCreation(@NotNull JsInvocation createInvocation, @NotNull TranslationContext context) { + addSuperclassReferences(createInvocation); + addClassOwnDeclarations(createInvocation, context); } private boolean isTrait() { return descriptor.getKind().equals(ClassKind.TRAIT); } - private void addClassOwnDeclarations(@NotNull JsInvocation jsClassDeclaration) { - TranslationContext classDeclarationContext = getClassDeclarationContext(); - JsObjectLiteral properties = new JsObjectLiteral(); + private void addClassOwnDeclarations(@NotNull JsInvocation jsClassDeclaration, @NotNull TranslationContext classDeclarationContext) { + JsObjectLiteral properties = new JsObjectLiteral(true); List propertyList = properties.getPropertyInitializers(); if (!isTrait()) { JsFunction initializer = Translation.generateClassInitializerMethod(classDeclaration, classDeclarationContext); if (context().isEcma5()) { - jsClassDeclaration.getArguments() - .add(initializer.getName() == null ? initializer : JsAstUtils.encloseFunction(initializer)); + jsClassDeclaration.getArguments().add(initializer.getBody().getStatements().isEmpty() ? JsLiteral.NULL : initializer); } else { - propertyList.add(InitializerUtils.generateInitializeMethod(initializer)); + propertyList.add(new JsPropertyInitializer(Namer.initializeMethodReference(), initializer)); } } - else if (context().isEcma5()) { - jsClassDeclaration.getArguments().add(JsLiteral.NULL); - } propertyList.addAll(translatePropertiesAsConstructorParameters(classDeclarationContext)); propertyList.addAll(declarationBodyVisitor.traverseClass(classDeclaration, classDeclarationContext)); @@ -168,7 +161,7 @@ public final class ClassTranslator extends AbstractTranslator { } private void addSuperclassReferences(@NotNull JsInvocation jsClassDeclaration) { - List superClassReferences = getSuperclassNameReferences(); + List superClassReferences = getSupertypesNameReferences(); List expressions = jsClassDeclaration.getArguments(); if (context().isEcma5()) { if (superClassReferences.isEmpty()) { @@ -188,37 +181,49 @@ public final class ClassTranslator extends AbstractTranslator { } @NotNull - private List getSuperclassNameReferences() { - List superclassReferences = new ArrayList(); - List superclassDescriptors = DescriptorUtils.getSuperclassDescriptors(descriptor); - addAncestorClass(superclassReferences, superclassDescriptors); - addTraits(superclassReferences, superclassDescriptors); - return superclassReferences; - } - - private void addTraits(@NotNull List superclassReferences, - @NotNull List superclassDescriptors) { - for (ClassDescriptor superClassDescriptor : superclassDescriptors) { - assert (superClassDescriptor.getKind() == ClassKind.TRAIT) : "Only traits are expected here"; - superclassReferences.add(getClassReference(superClassDescriptor)); + private List getSupertypesNameReferences() { + Collection supertypes = descriptor.getTypeConstructor().getSupertypes(); + if (supertypes.isEmpty()) { + return Collections.emptyList(); } - } - private void addAncestorClass(@NotNull List superclassReferences, - @NotNull List superclassDescriptors) { - //here we remove ancestor class from the list - ClassDescriptor ancestorClass = findAndRemoveAncestorClass(superclassDescriptors); - if (ancestorClass != null) { - superclassReferences.add(getClassReference(ancestorClass)); + JsExpression base = null; + List list = null; + for (JetType type : supertypes) { + ClassDescriptor result = getClassDescriptorForType(type); + if (isNotAny(result) && !AnnotationsUtils.isNativeObject(result)) { + switch (result.getKind()) { + case CLASS: + base = getClassReference(result); + break; + case TRAIT: + if (list == null) { + list = new ArrayList(); + } + list.add(getClassReference(result)); + break; + + default: + throw new UnsupportedOperationException("unsupported super class kind " + result.getKind().name()); + } + } } + + if (list == null) { + return base == null ? Collections.emptyList() : Collections.singletonList(base); + } + else if (base != null) { + list.add(0, base); + } + + return list; } @NotNull private JsExpression getClassReference(@NotNull ClassDescriptor superClassDescriptor) { // aliasing here is needed for the declaration generation step if (aliasingMap != null) { - JsNameRef name = aliasingMap.get(BindingUtils.getClassForDescriptor(bindingContext(), superClassDescriptor), - (JetClass) classDeclaration); + JsNameRef name = aliasingMap.get(superClassDescriptor, descriptor); if (name != null) { return name; } @@ -228,40 +233,20 @@ public final class ClassTranslator extends AbstractTranslator { return getQualifiedReference(context(), superClassDescriptor); } - @Nullable - private static ClassDescriptor findAndRemoveAncestorClass(@NotNull List superclassDescriptors) { - ClassDescriptor ancestorClass = findAncestorClass(superclassDescriptors); - superclassDescriptors.remove(ancestorClass); - return ancestorClass; - } - @NotNull private List translatePropertiesAsConstructorParameters(@NotNull TranslationContext classDeclarationContext) { - List result = new ArrayList(); - for (JetParameter parameter : getPrimaryConstructorParameters(classDeclaration)) { - PropertyDescriptor descriptor = - getPropertyDescriptorForConstructorParameter(bindingContext(), parameter); + List parameters = getPrimaryConstructorParameters(classDeclaration); + if (parameters.isEmpty()) { + return Collections.emptyList(); + } + + List result = new SmartList(); + for (JetParameter parameter : parameters) { + PropertyDescriptor descriptor = getPropertyDescriptorForConstructorParameter(bindingContext(), parameter); if (descriptor != null) { - result.addAll(PropertyTranslator.translateAccessors(descriptor, classDeclarationContext)); + PropertyTranslator.translateAccessors(descriptor, result, classDeclarationContext); } } return result; } - - @NotNull - private TranslationContext getClassDeclarationContext() { - if (aliasForContainingClassThis == null) { - return context(); - } - ClassDescriptor containingClass = getContainingClass(descriptor); - assert containingClass != null; - return context().innerContextWithThisAliased(containingClass, aliasForContainingClassThis.name()); - } - - @NotNull - private JsExpression translateObjectLiteralWithThisAliased(@NotNull ClassDescriptor containingClass, - @NotNull TranslationContext outerContext) { - aliasForContainingClassThis = outerContext.declareTemporary(getThisObject(outerContext, containingClass)); - return newSequence(aliasForContainingClassThis.assignmentExpression(), translateClassOrObjectCreation()); - } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/DeclarationBodyVisitor.java b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/DeclarationBodyVisitor.java index 5de5781badf..0bb8b66f1e0 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/DeclarationBodyVisitor.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/DeclarationBodyVisitor.java @@ -18,10 +18,10 @@ package org.jetbrains.k2js.translate.declaration; import com.google.dart.compiler.backend.js.ast.JsExpression; import com.google.dart.compiler.backend.js.ast.JsPropertyInitializer; +import com.intellij.util.SmartList; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; -import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; +import org.jetbrains.jet.lang.descriptors.Modality; import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.k2js.translate.context.TranslationContext; @@ -30,104 +30,77 @@ import org.jetbrains.k2js.translate.general.TranslatorVisitor; import org.jetbrains.k2js.translate.utils.BindingUtils; import org.jetbrains.k2js.translate.utils.JsAstUtils; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import static org.jetbrains.k2js.translate.utils.BindingUtils.*; +import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptor; +import static org.jetbrains.k2js.translate.utils.BindingUtils.getPropertyDescriptorForObjectDeclaration; /** * @author Pavel Talanov */ -public final class DeclarationBodyVisitor extends TranslatorVisitor> { - @Nullable - private final ClassDeclarationTranslator classDeclarationTranslator; +public class DeclarationBodyVisitor extends TranslatorVisitor { + protected final List result = new SmartList(); public DeclarationBodyVisitor() { - classDeclarationTranslator = null; } - public DeclarationBodyVisitor(ClassDeclarationTranslator classDeclarationTranslator) { - this.classDeclarationTranslator = classDeclarationTranslator; + @NotNull + public List getResult() { + return result; } @NotNull public List traverseClass(@NotNull JetClassOrObject jetClass, - @NotNull TranslationContext context) { - List properties = new ArrayList(); - for (JetDeclaration declaration : jetClass.getDeclarations()) { - properties.addAll(declaration.accept(this, context)); - } - return properties; - } - - @NotNull - public List traverseNamespace(@NotNull NamespaceDescriptor namespace, @NotNull TranslationContext context) { - List properties = new ArrayList(); - for (JetDeclaration declaration : getDeclarationsForNamespace(context.bindingContext(), namespace)) { - properties.addAll(declaration.accept(this, context)); + for (JetDeclaration declaration : jetClass.getDeclarations()) { + declaration.accept(this, context); } - return properties; + return result; } @Override - @NotNull - public List visitClass(@NotNull JetClass expression, @NotNull TranslationContext context) { - if (classDeclarationTranslator == null) { - return Collections.emptyList(); - } - - return Collections.singletonList(classDeclarationTranslator.translateAndGetClassNameToClassObject(expression)); + public Void visitClass(@NotNull JetClass expression, @NotNull TranslationContext context) { + return null; } @Override - @NotNull - public List visitNamedFunction(@NotNull JetNamedFunction expression, - @NotNull TranslationContext context) { + public Void visitNamedFunction(@NotNull JetNamedFunction expression, + @NotNull TranslationContext context) { + FunctionDescriptor descriptor = getFunctionDescriptor(context.bindingContext(), expression); + if (descriptor.getModality() == Modality.ABSTRACT) { + return null; + } + JsPropertyInitializer methodAsPropertyInitializer = Translation.functionTranslator(expression, context).translateAsMethod(); if (context.isEcma5()) { - FunctionDescriptor descriptor = getFunctionDescriptor(context.bindingContext(), expression); JsExpression methodBodyExpression = methodAsPropertyInitializer.getValueExpr(); methodAsPropertyInitializer.setValueExpr(JsAstUtils.createPropertyDataDescriptor(descriptor, methodBodyExpression)); } - return Collections.singletonList(methodAsPropertyInitializer); + result.add(methodAsPropertyInitializer); + return null; } @Override - @NotNull - public List visitProperty(@NotNull JetProperty expression, - @NotNull TranslationContext context) { - PropertyDescriptor propertyDescriptor = - BindingUtils.getPropertyDescriptor(context.bindingContext(), expression); - return PropertyTranslator.translateAccessors(propertyDescriptor, context); + public Void visitProperty(@NotNull JetProperty expression, @NotNull TranslationContext context) { + PropertyDescriptor propertyDescriptor = BindingUtils.getPropertyDescriptor(context.bindingContext(), expression); + PropertyTranslator.translateAccessors(propertyDescriptor, expression, result, context); + return null; } @Override - @NotNull - public List visitObjectDeclaration(@NotNull JetObjectDeclaration expression, - @NotNull TranslationContext context) { - return Collections.singletonList(ClassTranslator.translateAsProperty(expression, context)); - } - - @Override - @NotNull - public List visitObjectDeclarationName(@NotNull JetObjectDeclarationName expression, - @NotNull TranslationContext context) { - if (context.isEcma5()) { - return Collections.emptyList(); + public Void visitObjectDeclarationName(@NotNull JetObjectDeclarationName expression, + @NotNull TranslationContext context) { + if (!context.isEcma5()) { + PropertyTranslator + .translateAccessors(getPropertyDescriptorForObjectDeclaration(context.bindingContext(), expression), result, context); } - PropertyDescriptor propertyDescriptor = - getPropertyDescriptorForObjectDeclaration(context.bindingContext(), expression); - return PropertyTranslator.translateAccessors(propertyDescriptor, context); + return null; } @Override - @NotNull - public List visitAnonymousInitializer(@NotNull JetClassInitializer expression, - @NotNull TranslationContext context) { + public Void visitAnonymousInitializer(@NotNull JetClassInitializer expression, @NotNull TranslationContext context) { // parsed it in initializer visitor => no additional actions are needed - return Collections.emptyList(); + return null; } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/NamespaceDeclarationTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/NamespaceDeclarationTranslator.java index d3d69a119b9..589cea6b885 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/NamespaceDeclarationTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/NamespaceDeclarationTranslator.java @@ -16,116 +16,114 @@ package org.jetbrains.k2js.translate.declaration; -import com.google.common.collect.Lists; import com.google.dart.compiler.backend.js.ast.*; +import gnu.trove.THashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.psi.JetFile; -import org.jetbrains.jet.lang.resolve.DescriptorUtils; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.k2js.translate.context.Namer; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.general.AbstractTranslator; import org.jetbrains.k2js.translate.utils.JsAstUtils; -import org.jetbrains.k2js.translate.utils.JsDescriptorUtils; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Set; +import java.util.*; -import static org.jetbrains.k2js.translate.utils.BindingUtils.getAllNonNativeNamespaceDescriptors; +import static com.google.dart.compiler.backend.js.ast.JsVars.JsVar; /** * @author Pavel Talanov */ public final class NamespaceDeclarationTranslator extends AbstractTranslator { + private final Iterable files; + private final Map descriptorToTranslator = + new LinkedHashMap(); public static List translateFiles(@NotNull Collection files, @NotNull TranslationContext context) { - Set namespaceDescriptorSet = getAllNonNativeNamespaceDescriptors(context.bindingContext(), files); - return (new NamespaceDeclarationTranslator(Lists.newArrayList(namespaceDescriptorSet), context)).translate(); + return new NamespaceDeclarationTranslator(files, context).translate(); } - @NotNull - private final ClassDeclarationTranslator classDeclarationTranslator; - @NotNull - private final List namespaceDescriptors; - - private NamespaceDeclarationTranslator(@NotNull List namespaceDescriptors, - @NotNull TranslationContext context) { + private NamespaceDeclarationTranslator(@NotNull Iterable files, @NotNull TranslationContext context) { super(context); - this.namespaceDescriptors = namespaceDescriptors; - classDeclarationTranslator = new ClassDeclarationTranslator(context); + + this.files = files; } @NotNull private List translate() { - List result = new ArrayList(); - result.add(classDeclarationTranslator.getDeclarationsStatement()); - namespacesDeclarations(result); - classDeclarationTranslator.generateDeclarations(); - return result; - } + // predictable order + Map> descriptorToDefineInvocation = new THashMap>(); + JsObjectLiteral rootNamespaceDefinition = null; - private void namespacesDeclarations(List statements) { - List namespaceTranslators = getTranslatorsForNonEmptyNamespaces(); - declarationStatements(namespaceTranslators, statements); - initializeStatements(namespaceTranslators, statements); - } + ClassDeclarationTranslator classDeclarationTranslator = new ClassDeclarationTranslator(context()); + for (JetFile file : files) { + NamespaceDescriptor descriptor = context().bindingContext().get(BindingContext.FILE_TO_NAMESPACE, file); + assert descriptor != null; + NamespaceTranslator translator = descriptorToTranslator.get(descriptor); + if (translator == null) { + if (rootNamespaceDefinition == null) { + rootNamespaceDefinition = getRootPackage(descriptorToDefineInvocation, descriptor); + } + translator = new NamespaceTranslator(descriptor, classDeclarationTranslator, context()); + descriptorToTranslator.put(descriptor, translator); + } - @NotNull - private List getTranslatorsForNonEmptyNamespaces() { - List namespaceTranslators = Lists.newArrayList(); - for (NamespaceDescriptor descriptor : filterNonEmptyNamespaces(filterTopLevelAndRootNamespaces(namespaceDescriptors))) { - namespaceTranslators.add(new NamespaceTranslator(descriptor, classDeclarationTranslator, context())); + translator.translate(file); } - return namespaceTranslators; - } - private void declarationStatements(@NotNull List namespaceTranslators, - @NotNull List statements) { - JsObjectLiteral objectLiteral = new JsObjectLiteral(); - JsNameRef packageMapNameRef = context().scope().declareName("_").makeRef(); - JsExpression packageMapValue; - if (context().isNotEcma3()) { - packageMapValue = new JsInvocation(JsAstUtils.CREATE_OBJECT, JsLiteral.NULL, objectLiteral); + if (rootNamespaceDefinition == null) { + return Collections.emptyList(); + } + + JsVars vars = new JsVars(true); + List result; + if (context().isEcma5()) { + result = Collections.singletonList(vars); } else { - packageMapValue = objectLiteral; + result = new ArrayList(); + result.add(vars); } - statements.add(JsAstUtils.newVar(packageMapNameRef.getName(), packageMapValue)); - for (NamespaceTranslator translator : namespaceTranslators) { - translator.addNamespaceDeclaration(objectLiteral.getPropertyInitializers()); + classDeclarationTranslator.generateDeclarations(); + for (NamespaceTranslator translator : descriptorToTranslator.values()) { + translator.add(descriptorToDefineInvocation, result); } - } - private static void initializeStatements(@NotNull List namespaceTranslators, - @NotNull List statements) { - for (NamespaceTranslator translator : namespaceTranslators) { - for (JsExpression expression : translator.getInitializers()) { - statements.add(expression.makeStmt()); - } - } - } - - @NotNull - private static List filterTopLevelAndRootNamespaces(@NotNull List namespaceDescriptors) { - List result = Lists.newArrayList(); - for (NamespaceDescriptor descriptor : namespaceDescriptors) { - if (DescriptorUtils.isTopLevelNamespace(descriptor) || DescriptorUtils.isRootNamespace(descriptor)) { - result.add(descriptor); - } - } + vars.addIfHasInitializer(context().literalFunctionTranslator().getDeclaration()); + vars.addIfHasInitializer(classDeclarationTranslator.getDeclaration()); + vars.addIfHasInitializer(getDeclaration(rootNamespaceDefinition)); return result; } - @NotNull - private List filterNonEmptyNamespaces(@NotNull List namespaceDescriptors) { - List result = Lists.newArrayList(); - for (NamespaceDescriptor descriptor : namespaceDescriptors) { - if (!JsDescriptorUtils.isNamespaceEmpty(descriptor, context().bindingContext())) { - result.add(descriptor); - } + private JsObjectLiteral getRootPackage(Map> descriptorToDefineInvocation, + NamespaceDescriptor descriptor) { + NamespaceDescriptor rootNamespace = descriptor; + while (rootNamespace.getContainingDeclaration() instanceof NamespaceDescriptor) { + rootNamespace = (NamespaceDescriptor) rootNamespace.getContainingDeclaration(); } - return result; + + List args; + JsObjectLiteral rootNamespaceDefinition = new JsObjectLiteral(true); + if (context().isEcma5()) { + args = Arrays.asList(JsLiteral.NULL, rootNamespaceDefinition); + } + else { + args = Collections.singletonList(rootNamespaceDefinition); + } + + descriptorToDefineInvocation.put(rootNamespace, args); + return rootNamespaceDefinition; + } + + private JsVar getDeclaration(@NotNull JsObjectLiteral rootNamespaceDefinition) { + JsExpression packageMapValue; + if (context().isEcma5()) { + packageMapValue = new JsInvocation(JsAstUtils.CREATE_OBJECT, JsLiteral.NULL, rootNamespaceDefinition); + } + else { + packageMapValue = rootNamespaceDefinition; + } + return new JsVar(context().scope().declareName(Namer.getRootNamespaceName()), packageMapValue); } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/NamespaceTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/NamespaceTranslator.java index 77f10928e60..4570a364a7d 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/NamespaceTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/NamespaceTranslator.java @@ -16,125 +16,177 @@ package org.jetbrains.k2js.translate.declaration; -import com.google.common.collect.Lists; import com.google.dart.compiler.backend.js.ast.*; +import com.intellij.util.SmartList; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; -import org.jetbrains.jet.lang.resolve.DescriptorUtils; +import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; +import org.jetbrains.jet.lang.psi.*; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.general.AbstractTranslator; import org.jetbrains.k2js.translate.general.Translation; +import org.jetbrains.k2js.translate.initializer.InitializerUtils; +import org.jetbrains.k2js.translate.initializer.InitializerVisitor; +import org.jetbrains.k2js.translate.utils.AnnotationsUtils; +import org.jetbrains.k2js.translate.utils.BindingUtils; import org.jetbrains.k2js.translate.utils.JsAstUtils; -import org.jetbrains.k2js.translate.utils.JsDescriptorUtils; import org.jetbrains.k2js.translate.utils.TranslationUtils; -import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.Map; -import static org.jetbrains.k2js.translate.utils.JsAstUtils.newObjectLiteral; +import static org.jetbrains.k2js.translate.initializer.InitializerUtils.generateInitializerForProperty; +import static org.jetbrains.k2js.translate.utils.BindingUtils.getPropertyDescriptor; /** * @author Pavel.Talanov - *

- * Genereate code for a single descriptor. */ -public final class NamespaceTranslator extends AbstractTranslator { - +final class NamespaceTranslator extends AbstractTranslator { @NotNull private final NamespaceDescriptor descriptor; @NotNull - private final JsName namespaceName; - @NotNull private final ClassDeclarationTranslator classDeclarationTranslator; - @NotNull - private final List initializers = new ArrayList(); + private final FileDeclarationVisitor visitor; - /*package*/ NamespaceTranslator(@NotNull NamespaceDescriptor descriptor, - @NotNull ClassDeclarationTranslator classDeclarationTranslator, - @NotNull TranslationContext context) { + NamespaceTranslator(@NotNull NamespaceDescriptor descriptor, + @NotNull ClassDeclarationTranslator classDeclarationTranslator, + @NotNull TranslationContext context) { super(context.newDeclaration(descriptor)); this.descriptor = descriptor; - this.namespaceName = context.getNameForDescriptor(descriptor); this.classDeclarationTranslator = classDeclarationTranslator; + + visitor = new FileDeclarationVisitor(); } - @NotNull - public List getInitializers() { - return initializers; - } - - @NotNull - public JsPropertyInitializer getDeclarationAsInitializer() { - addNamespaceInitializer(); - return new JsPropertyInitializer(namespaceName.makeRef(), getNamespaceDeclaration()); - } - - public void addNamespaceDeclaration(List list) { - addNamespaceInitializer(); - - if (DescriptorUtils.isRootNamespace(descriptor)) { - list.addAll(getFunctionsAndClasses()); - return; - } - - JsExpression value = getNamespaceDeclaration(); - if (context().isNotEcma3()) { - value = JsAstUtils.createDataDescriptor(value); - } - - list.add(new JsPropertyInitializer(namespaceName.makeRef(), value)); - } - - @NotNull - private JsInvocation getNamespaceDeclaration() { - JsInvocation namespaceDeclaration = namespaceCreateMethodInvocation(); - addIfNeed(getFunctionsAndClasses(), namespaceDeclaration.getArguments()); - addIfNeed(getNestedNamespaceDeclarations(), namespaceDeclaration.getArguments()); - return namespaceDeclaration; - } - - private void addNamespaceInitializer() { - JsFunction initializer = Translation.generateNamespaceInitializerMethod(descriptor, context()); - if (!initializer.getBody().getStatements().isEmpty()) { - JsNameRef call = new JsNameRef("call"); - call.setQualifier(initializer); - JsInvocation invocation = new JsInvocation(); - invocation.setQualifier(call); - invocation.getArguments().add(TranslationUtils.getQualifiedReference(context(), descriptor)); - initializers.add(invocation); + public void translate(JetFile file) { + for (JetDeclaration declaration : file.getDeclarations()) { + if (!AnnotationsUtils.isNativeObject(BindingUtils.getDescriptorForElement(bindingContext(), declaration))) { + declaration.accept(visitor, context()); + } } } - private List getFunctionsAndClasses() { - return new DeclarationBodyVisitor(classDeclarationTranslator).traverseNamespace(descriptor, context()); - } - - @NotNull - private JsInvocation namespaceCreateMethodInvocation() { - return new JsInvocation(context().namer().packageDefinitionMethodReference()); - } - - private void addIfNeed(@NotNull List declarations, @NotNull List expressions) { - // ecma5 expects strict number of arguments, but ecma3 doesn't - if (!declarations.isEmpty()) { - expressions.add(newObjectLiteral(declarations)); + public void add(@NotNull Map> descriptorToDefineInvocation, + @NotNull List initializers) { + JsExpression initializer; + if (visitor.initializerStatements.isEmpty()) { + initializer = null; } - else if (context().isNotEcma3()) { - expressions.add(JsLiteral.NULL); + else { + initializer = visitor.initializer; + if (!context().isEcma5()) { + initializers.add(new JsInvocation(new JsNameRef("call", initializer), + TranslationUtils.getQualifiedReference(context(), descriptor)).makeStmt()); + } + } + + List defineInvocation = descriptorToDefineInvocation.get(descriptor); + if (defineInvocation == null) { + defineInvocation = createDefineInvocation(initializer, new JsObjectLiteral(visitor.getResult(), true)); + descriptorToDefineInvocation.put(descriptor, defineInvocation); + addToParent((NamespaceDescriptor) descriptor.getContainingDeclaration(), getEntry(descriptor, defineInvocation), + descriptorToDefineInvocation); + } + else { + if (context().isEcma5() && initializer != null) { + assert defineInvocation.get(0) == JsLiteral.NULL; + defineInvocation.set(0, initializer); + } + ((JsObjectLiteral) defineInvocation.get(context().isEcma5() ? 1 : 0)).getPropertyInitializers().addAll(visitor.getResult()); } } - @NotNull - private List getNestedNamespaceDeclarations() { - List result = Lists.newArrayList(); - List nestedNamespaces = JsDescriptorUtils.getNestedNamespaces(descriptor, context().bindingContext()); - for (NamespaceDescriptor nestedNamespace : nestedNamespaces) { - NamespaceTranslator nestedNamespaceTranslator = new NamespaceTranslator(nestedNamespace, classDeclarationTranslator, context()); - result.add(nestedNamespaceTranslator.getDeclarationAsInitializer()); - - initializers.addAll(nestedNamespaceTranslator.getInitializers()); + private List createDefineInvocation(@Nullable JsExpression initializer, @NotNull JsObjectLiteral members) { + if (context().isEcma5()) { + return Arrays.asList(initializer == null ? JsLiteral.NULL : initializer, members); + } + else { + return Collections.singletonList(members); + } + } + + private JsPropertyInitializer getEntry(@NotNull NamespaceDescriptor descriptor, List defineInvocation) { + return new JsPropertyInitializer(context().getNameForDescriptor(descriptor).makeRef(), + new JsInvocation(context().namer().packageDefinitionMethodReference(), defineInvocation)); + } + + private boolean addEntryIfParentExists(NamespaceDescriptor parentDescriptor, + JsPropertyInitializer entry, + Map> descriptorToDeclarationPlace) { + List parentDefineInvocation = descriptorToDeclarationPlace.get(parentDescriptor); + if (parentDefineInvocation != null) { + ((JsObjectLiteral) parentDefineInvocation.get(context().isEcma5() ? 1 : 0)).getPropertyInitializers().add(entry); + return true; + } + return false; + } + + private void addToParent(NamespaceDescriptor parentDescriptor, + JsPropertyInitializer entry, + Map> descriptorToDefineInvocation) { + while (!addEntryIfParentExists(parentDescriptor, entry, descriptorToDefineInvocation)) { + List defineInvocation = + createDefineInvocation(null, new JsObjectLiteral(new SmartList(entry), true)); + entry = getEntry(parentDescriptor, defineInvocation); + + descriptorToDefineInvocation.put(parentDescriptor, defineInvocation); + parentDescriptor = (NamespaceDescriptor) parentDescriptor.getContainingDeclaration(); + } + } + + private class FileDeclarationVisitor extends DeclarationBodyVisitor { + private final JsFunction initializer; + private final TranslationContext initializerContext; + private final List initializerStatements; + private final InitializerVisitor initializerVisitor; + + private FileDeclarationVisitor() { + initializer = JsAstUtils.createFunctionWithEmptyBody(context().scope()); + initializerContext = context().contextWithScope(initializer); + initializerStatements = initializer.getBody().getStatements(); + initializerVisitor = new InitializerVisitor(initializerStatements); + } + + @Override + public Void visitClass(@NotNull JetClass expression, @NotNull TranslationContext context) { + JsPropertyInitializer value = classDeclarationTranslator.translate(expression); + result.add(value); + return null; + } + + @Override + public Void visitObjectDeclaration(@NotNull JetObjectDeclaration declaration, @NotNull TranslationContext context) { + InitializerUtils.generate(declaration, initializerStatements, result, context); + return null; + } + + @Override + public Void visitProperty(@NotNull JetProperty property, @NotNull TranslationContext context) { + super.visitProperty(property, context); + JetExpression initializer = property.getInitializer(); + if (initializer != null) { + JsExpression value = Translation.translateAsExpression(initializer, initializerContext); + PropertyDescriptor propertyDescriptor = getPropertyDescriptor(context.bindingContext(), property); + if (value instanceof JsLiteral) { + result.add(new JsPropertyInitializer(context.getNameForDescriptor(propertyDescriptor).makeRef(), + context().isEcma5() ? JsAstUtils + .createPropertyDataDescriptor(propertyDescriptor, value) : value)); + } + else { + initializerStatements.add(generateInitializerForProperty(context, propertyDescriptor, value)); + } + } + return null; + } + + @Override + public Void visitAnonymousInitializer(@NotNull JetClassInitializer expression, @NotNull TranslationContext context) { + expression.accept(initializerVisitor, initializerContext); + return null; } - return result; } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java b/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java index cf29de1bedd..90e15ae8bb6 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java @@ -377,7 +377,7 @@ public final class ExpressionVisitor extends TranslatorVisitor { @NotNull public JsNode visitObjectLiteralExpression(@NotNull JetObjectLiteralExpression expression, @NotNull TranslationContext context) { - return ClassTranslator.generateObjectLiteralExpression(expression, context); + return ClassTranslator.generateObjectLiteral(expression, context); } @Override @@ -387,7 +387,7 @@ public final class ExpressionVisitor extends TranslatorVisitor { JetObjectDeclarationName objectDeclarationName = getObjectDeclarationName(expression); DeclarationDescriptor descriptor = getDescriptorForElement(context.bindingContext(), objectDeclarationName); JsName propertyName = context.getNameForDescriptor(descriptor); - JsExpression value = ClassTranslator.generateClassCreationExpression(expression, context); + JsExpression value = ClassTranslator.generateClassCreation(expression, context); return newVar(propertyName, value); } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/general/Translation.java b/js/js.translator/src/org/jetbrains/k2js/translate/general/Translation.java index 6fba5903a26..dab85b16597 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/general/Translation.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/general/Translation.java @@ -20,7 +20,6 @@ import com.google.dart.compiler.backend.js.ast.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; -import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.k2js.config.Config; @@ -29,6 +28,7 @@ import org.jetbrains.k2js.facade.exceptions.MainFunctionNotFoundException; import org.jetbrains.k2js.facade.exceptions.TranslationException; import org.jetbrains.k2js.facade.exceptions.TranslationInternalException; import org.jetbrains.k2js.facade.exceptions.UnsupportedFeatureException; +import org.jetbrains.k2js.translate.context.Namer; import org.jetbrains.k2js.translate.context.StaticContext; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.declaration.ClassAliasingMap; @@ -39,12 +39,10 @@ import org.jetbrains.k2js.translate.expression.FunctionTranslator; import org.jetbrains.k2js.translate.expression.PatternTranslator; import org.jetbrains.k2js.translate.expression.WhenTranslator; import org.jetbrains.k2js.translate.initializer.ClassInitializerTranslator; -import org.jetbrains.k2js.translate.initializer.NamespaceInitializerTranslator; import org.jetbrains.k2js.translate.reference.CallBuilder; import org.jetbrains.k2js.translate.test.JSTestGenerator; import org.jetbrains.k2js.translate.test.JSTester; import org.jetbrains.k2js.translate.utils.JsAstUtils; -import org.jetbrains.k2js.translate.utils.TranslationUtils; import org.jetbrains.k2js.translate.utils.dangerous.DangerousData; import org.jetbrains.k2js.translate.utils.dangerous.DangerousTranslator; @@ -75,7 +73,7 @@ public final class Translation { } @NotNull - public static List translateFiles(@NotNull Collection files, @NotNull TranslationContext context) { + private static List translateFiles(@NotNull Collection files, @NotNull TranslationContext context) { return NamespaceDeclarationTranslator.translateFiles(files, context); } @@ -83,7 +81,7 @@ public final class Translation { public static JsExpression translateClassDeclaration(@NotNull JetClass classDeclaration, @NotNull ClassAliasingMap classAliasingMap, @NotNull TranslationContext context) { - return ClassTranslator.generateClassCreationExpression(classDeclaration, classAliasingMap, context); + return ClassTranslator.generateClassCreation(classDeclaration, classAliasingMap, context); } @NotNull @@ -136,13 +134,6 @@ public final class Translation { return classInitializerTranslator.generateInitializeMethod(); } - @NotNull - public static JsFunction generateNamespaceInitializerMethod(@NotNull NamespaceDescriptor namespace, - @NotNull TranslationContext context) { - final NamespaceInitializerTranslator namespaceInitializerTranslator = new NamespaceInitializerTranslator(namespace, context); - return namespaceInitializerTranslator.generateInitializeMethod(); - } - @NotNull public static JsProgram generateAst(@NotNull BindingContext bindingContext, @NotNull Collection files, @NotNull MainCallParameters mainCallParameters, @@ -174,8 +165,9 @@ public final class Translation { statements.add(program.getStringLiteral("use strict").makeStmt()); TranslationContext context = TranslationContext.rootContext(staticContext); + staticContext.getLiteralFunctionTranslator().setRootContext(context); statements.addAll(translateFiles(files, context)); - TranslationUtils.defineModule(context, statements, config.getModuleId()); + defineModule(context, statements, config.getModuleId()); if (mainCallParameters.shouldBeGenerated()) { JsStatement statement = generateCallToMain(context, files, mainCallParameters.arguments()); @@ -187,6 +179,14 @@ public final class Translation { return context.program(); } + private static void defineModule(@NotNull TranslationContext context, @NotNull List statements, @NotNull String moduleId) { + JsName rootNamespaceName = context.scope().findName(Namer.getRootNamespaceName()); + if (rootNamespaceName != null) { + statements.add(new JsInvocation(context.namer().kotlin("defineModule"), context.program().getStringLiteral(moduleId), + rootNamespaceName.makeRef()).makeStmt()); + } + } + private static void mayBeGenerateTests(@NotNull Collection files, @NotNull Config config, @NotNull JsBlock rootBlock, @NotNull TranslationContext context) { JSTester tester = config.getTester();