Rework logic in class declaration and namespace declaration.

Adapted from https://github.com/develar/kotlin/commit/a9e0a42fb1347fa8e21c86b5a073ef8a7c873da0.
This commit is contained in:
Pavel V. Talanov
2012-08-13 15:18:26 +04:00
parent 124ba541ac
commit 29391e6c92
9 changed files with 440 additions and 445 deletions
@@ -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
@@ -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);
}
@@ -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<JetClass, ListItem> openClassToItem = new THashMap<JetClass, ListItem>();
private final THashMap<ClassDescriptor, FinalListItem> openClassDescriptorToItem = new THashMap<ClassDescriptor, FinalListItem>();
private final TLinkedList<ListItem> openList = new TLinkedList<ListItem>();
private final List<ListItem> finalList = new ArrayList<ListItem>();
private final TLinkedList<FinalListItem> openList = new TLinkedList<FinalListItem>();
private final List<Pair<JetClassOrObject, JsInvocation>> finalList = new ArrayList<Pair<JetClassOrObject, JsInvocation>>();
@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<JsPropertyInitializer> propertyInitializers = valueLiteral.getPropertyInitializers();
List<JsVar> vars = new SmartList<JsVar>();
List<JsPropertyInitializer> propertyInitializers = new SmartList<JsPropertyInitializer>();
generateOpenClassDeclarations(vars, propertyInitializers);
generateFinalClassDeclarations(vars, propertyInitializers);
generateFinalClassDeclarations();
if (vars.isEmpty()) {
classesVar.setInitExpression(valueLiteral);
if (!propertyInitializers.isEmpty()) {
classesVar.setInitExpression(new JsObjectLiteral(propertyInitializers));
}
return;
}
List<JsStatement> result = new ArrayList<JsStatement>();
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<JsPropertyInitializer> propertyInitializers) {
private void generateOpenClassDeclarations(@NotNull List<JsVar> vars, @NotNull List<JsPropertyInitializer> 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<JsPropertyInitializer> 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<JetClassOrObject, JsInvocation> 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<JsPropertyInitializer> propertyInitializers,
@NotNull JsExpression definition,
@NotNull JsVars vars) {
@NotNull List<JsVar> 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<JetClassOrObject, JsInvocation>(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());
}
}
@@ -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<JsPropertyInitializer> 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<JsExpression> superClassReferences = getSuperclassNameReferences();
List<JsExpression> superClassReferences = getSupertypesNameReferences();
List<JsExpression> expressions = jsClassDeclaration.getArguments();
if (context().isEcma5()) {
if (superClassReferences.isEmpty()) {
@@ -188,37 +181,49 @@ public final class ClassTranslator extends AbstractTranslator {
}
@NotNull
private List<JsExpression> getSuperclassNameReferences() {
List<JsExpression> superclassReferences = new ArrayList<JsExpression>();
List<ClassDescriptor> superclassDescriptors = DescriptorUtils.getSuperclassDescriptors(descriptor);
addAncestorClass(superclassReferences, superclassDescriptors);
addTraits(superclassReferences, superclassDescriptors);
return superclassReferences;
}
private void addTraits(@NotNull List<JsExpression> superclassReferences,
@NotNull List<ClassDescriptor> superclassDescriptors) {
for (ClassDescriptor superClassDescriptor : superclassDescriptors) {
assert (superClassDescriptor.getKind() == ClassKind.TRAIT) : "Only traits are expected here";
superclassReferences.add(getClassReference(superClassDescriptor));
private List<JsExpression> getSupertypesNameReferences() {
Collection<? extends JetType> supertypes = descriptor.getTypeConstructor().getSupertypes();
if (supertypes.isEmpty()) {
return Collections.emptyList();
}
}
private void addAncestorClass(@NotNull List<JsExpression> superclassReferences,
@NotNull List<ClassDescriptor> superclassDescriptors) {
//here we remove ancestor class from the list
ClassDescriptor ancestorClass = findAndRemoveAncestorClass(superclassDescriptors);
if (ancestorClass != null) {
superclassReferences.add(getClassReference(ancestorClass));
JsExpression base = null;
List<JsExpression> 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<JsExpression>();
}
list.add(getClassReference(result));
break;
default:
throw new UnsupportedOperationException("unsupported super class kind " + result.getKind().name());
}
}
}
if (list == null) {
return base == null ? Collections.<JsExpression>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<ClassDescriptor> superclassDescriptors) {
ClassDescriptor ancestorClass = findAncestorClass(superclassDescriptors);
superclassDescriptors.remove(ancestorClass);
return ancestorClass;
}
@NotNull
private List<JsPropertyInitializer> translatePropertiesAsConstructorParameters(@NotNull TranslationContext classDeclarationContext) {
List<JsPropertyInitializer> result = new ArrayList<JsPropertyInitializer>();
for (JetParameter parameter : getPrimaryConstructorParameters(classDeclaration)) {
PropertyDescriptor descriptor =
getPropertyDescriptorForConstructorParameter(bindingContext(), parameter);
List<JetParameter> parameters = getPrimaryConstructorParameters(classDeclaration);
if (parameters.isEmpty()) {
return Collections.emptyList();
}
List<JsPropertyInitializer> result = new SmartList<JsPropertyInitializer>();
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());
}
}
@@ -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<List<JsPropertyInitializer>> {
@Nullable
private final ClassDeclarationTranslator classDeclarationTranslator;
public class DeclarationBodyVisitor extends TranslatorVisitor<Void> {
protected final List<JsPropertyInitializer> result = new SmartList<JsPropertyInitializer>();
public DeclarationBodyVisitor() {
classDeclarationTranslator = null;
}
public DeclarationBodyVisitor(ClassDeclarationTranslator classDeclarationTranslator) {
this.classDeclarationTranslator = classDeclarationTranslator;
@NotNull
public List<JsPropertyInitializer> getResult() {
return result;
}
@NotNull
public List<JsPropertyInitializer> traverseClass(@NotNull JetClassOrObject jetClass,
@NotNull TranslationContext context) {
List<JsPropertyInitializer> properties = new ArrayList<JsPropertyInitializer>();
for (JetDeclaration declaration : jetClass.getDeclarations()) {
properties.addAll(declaration.accept(this, context));
}
return properties;
}
@NotNull
public List<JsPropertyInitializer> traverseNamespace(@NotNull NamespaceDescriptor namespace,
@NotNull TranslationContext context) {
List<JsPropertyInitializer> properties = new ArrayList<JsPropertyInitializer>();
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<JsPropertyInitializer> 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<JsPropertyInitializer> 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<JsPropertyInitializer> 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<JsPropertyInitializer> visitObjectDeclaration(@NotNull JetObjectDeclaration expression,
@NotNull TranslationContext context) {
return Collections.singletonList(ClassTranslator.translateAsProperty(expression, context));
}
@Override
@NotNull
public List<JsPropertyInitializer> 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<JsPropertyInitializer> 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;
}
}
@@ -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<JetFile> files;
private final Map<NamespaceDescriptor,NamespaceTranslator> descriptorToTranslator =
new LinkedHashMap<NamespaceDescriptor, NamespaceTranslator>();
public static List<JsStatement> translateFiles(@NotNull Collection<JetFile> files, @NotNull TranslationContext context) {
Set<NamespaceDescriptor> 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<NamespaceDescriptor> namespaceDescriptors;
private NamespaceDeclarationTranslator(@NotNull List<NamespaceDescriptor> namespaceDescriptors,
@NotNull TranslationContext context) {
private NamespaceDeclarationTranslator(@NotNull Iterable<JetFile> files, @NotNull TranslationContext context) {
super(context);
this.namespaceDescriptors = namespaceDescriptors;
classDeclarationTranslator = new ClassDeclarationTranslator(context);
this.files = files;
}
@NotNull
private List<JsStatement> translate() {
List<JsStatement> result = new ArrayList<JsStatement>();
result.add(classDeclarationTranslator.getDeclarationsStatement());
namespacesDeclarations(result);
classDeclarationTranslator.generateDeclarations();
return result;
}
// predictable order
Map<NamespaceDescriptor, List<JsExpression>> descriptorToDefineInvocation = new THashMap<NamespaceDescriptor, List<JsExpression>>();
JsObjectLiteral rootNamespaceDefinition = null;
private void namespacesDeclarations(List<JsStatement> statements) {
List<NamespaceTranslator> 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<NamespaceTranslator> getTranslatorsForNonEmptyNamespaces() {
List<NamespaceTranslator> 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<NamespaceTranslator> namespaceTranslators,
@NotNull List<JsStatement> 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<JsStatement> result;
if (context().isEcma5()) {
result = Collections.<JsStatement>singletonList(vars);
}
else {
packageMapValue = objectLiteral;
result = new ArrayList<JsStatement>();
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<NamespaceTranslator> namespaceTranslators,
@NotNull List<JsStatement> statements) {
for (NamespaceTranslator translator : namespaceTranslators) {
for (JsExpression expression : translator.getInitializers()) {
statements.add(expression.makeStmt());
}
}
}
@NotNull
private static List<NamespaceDescriptor> filterTopLevelAndRootNamespaces(@NotNull List<NamespaceDescriptor> namespaceDescriptors) {
List<NamespaceDescriptor> 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<NamespaceDescriptor> filterNonEmptyNamespaces(@NotNull List<NamespaceDescriptor> namespaceDescriptors) {
List<NamespaceDescriptor> result = Lists.newArrayList();
for (NamespaceDescriptor descriptor : namespaceDescriptors) {
if (!JsDescriptorUtils.isNamespaceEmpty(descriptor, context().bindingContext())) {
result.add(descriptor);
}
private JsObjectLiteral getRootPackage(Map<NamespaceDescriptor, List<JsExpression>> descriptorToDefineInvocation,
NamespaceDescriptor descriptor) {
NamespaceDescriptor rootNamespace = descriptor;
while (rootNamespace.getContainingDeclaration() instanceof NamespaceDescriptor) {
rootNamespace = (NamespaceDescriptor) rootNamespace.getContainingDeclaration();
}
return result;
List<JsExpression> args;
JsObjectLiteral rootNamespaceDefinition = new JsObjectLiteral(true);
if (context().isEcma5()) {
args = Arrays.<JsExpression>asList(JsLiteral.NULL, rootNamespaceDefinition);
}
else {
args = Collections.<JsExpression>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);
}
}
@@ -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
* <p/>
* 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<JsExpression> initializers = new ArrayList<JsExpression>();
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<JsExpression> getInitializers() {
return initializers;
}
@NotNull
public JsPropertyInitializer getDeclarationAsInitializer() {
addNamespaceInitializer();
return new JsPropertyInitializer(namespaceName.makeRef(), getNamespaceDeclaration());
}
public void addNamespaceDeclaration(List<JsPropertyInitializer> 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<JsPropertyInitializer> getFunctionsAndClasses() {
return new DeclarationBodyVisitor(classDeclarationTranslator).traverseNamespace(descriptor, context());
}
@NotNull
private JsInvocation namespaceCreateMethodInvocation() {
return new JsInvocation(context().namer().packageDefinitionMethodReference());
}
private void addIfNeed(@NotNull List<JsPropertyInitializer> declarations, @NotNull List<JsExpression> expressions) {
// ecma5 expects strict number of arguments, but ecma3 doesn't
if (!declarations.isEmpty()) {
expressions.add(newObjectLiteral(declarations));
public void add(@NotNull Map<NamespaceDescriptor, List<JsExpression>> descriptorToDefineInvocation,
@NotNull List<JsStatement> 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<JsExpression> 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<JsPropertyInitializer> getNestedNamespaceDeclarations() {
List<JsPropertyInitializer> result = Lists.newArrayList();
List<NamespaceDescriptor> 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<JsExpression> createDefineInvocation(@Nullable JsExpression initializer, @NotNull JsObjectLiteral members) {
if (context().isEcma5()) {
return Arrays.asList(initializer == null ? JsLiteral.NULL : initializer, members);
}
else {
return Collections.<JsExpression>singletonList(members);
}
}
private JsPropertyInitializer getEntry(@NotNull NamespaceDescriptor descriptor, List<JsExpression> defineInvocation) {
return new JsPropertyInitializer(context().getNameForDescriptor(descriptor).makeRef(),
new JsInvocation(context().namer().packageDefinitionMethodReference(), defineInvocation));
}
private boolean addEntryIfParentExists(NamespaceDescriptor parentDescriptor,
JsPropertyInitializer entry,
Map<NamespaceDescriptor, List<JsExpression>> descriptorToDeclarationPlace) {
List<JsExpression> 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<NamespaceDescriptor, List<JsExpression>> descriptorToDefineInvocation) {
while (!addEntryIfParentExists(parentDescriptor, entry, descriptorToDefineInvocation)) {
List<JsExpression> defineInvocation =
createDefineInvocation(null, new JsObjectLiteral(new SmartList<JsPropertyInitializer>(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<JsStatement> 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;
}
}
@@ -377,7 +377,7 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
@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<JsNode> {
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);
}
@@ -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<JsStatement> translateFiles(@NotNull Collection<JetFile> files, @NotNull TranslationContext context) {
private static List<JsStatement> translateFiles(@NotNull Collection<JetFile> 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<JetFile> 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<JsStatement> 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<JetFile> files, @NotNull Config config,
@NotNull JsBlock rootBlock, @NotNull TranslationContext context) {
JSTester tester = config.getTester();