From 45449901886668a5cdc6f77f63a62cd248a684e4 Mon Sep 17 00:00:00 2001 From: develar Date: Wed, 14 Aug 2013 14:50:06 +0400 Subject: [PATCH] JS backend: refactoring -- prepare to fix KT-2696 --- .../k2js/translate/context/StaticContext.java | 15 ++- .../translate/context/TranslationContext.java | 8 ++ .../ClassDeclarationTranslator.java | 99 ++++++++++--------- .../declaration/DeclarationBodyVisitor.java | 11 --- .../NamespaceDeclarationTranslator.java | 7 +- .../declaration/NamespaceTranslator.java | 15 ++- .../expression/LiteralFunctionTranslator.java | 26 ++--- .../k2js/translate/general/Translation.java | 10 +- .../k2js/translate/utils/BindingUtils.java | 8 +- 9 files changed, 101 insertions(+), 98 deletions(-) diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/context/StaticContext.java b/js/js.translator/src/org/jetbrains/k2js/translate/context/StaticContext.java index 80b2e53fbef..9c9e5bb02a6 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/context/StaticContext.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/context/StaticContext.java @@ -30,6 +30,7 @@ import org.jetbrains.k2js.config.EcmaVersion; import org.jetbrains.k2js.config.LibrarySourcesConfig; import org.jetbrains.k2js.translate.context.generator.Generator; import org.jetbrains.k2js.translate.context.generator.Rule; +import org.jetbrains.k2js.translate.declaration.ClassDeclarationTranslator; import org.jetbrains.k2js.translate.expression.LiteralFunctionTranslator; import org.jetbrains.k2js.translate.intrinsic.Intrinsics; import org.jetbrains.k2js.translate.utils.AnnotationsUtils; @@ -89,7 +90,9 @@ public final class StaticContext { private final EcmaVersion ecmaVersion; @NotNull - private final LiteralFunctionTranslator literalFunctionTranslator = new LiteralFunctionTranslator(); + private LiteralFunctionTranslator literalFunctionTranslator; + @NotNull + private ClassDeclarationTranslator classDeclarationTranslator; //TODO: too many parameters in constructor private StaticContext(@NotNull JsProgram program, @NotNull BindingContext bindingContext, @@ -104,11 +107,21 @@ public final class StaticContext { this.ecmaVersion = ecmaVersion; } + public void initTranslators(TranslationContext programContext) { + literalFunctionTranslator = new LiteralFunctionTranslator(programContext); + classDeclarationTranslator = new ClassDeclarationTranslator(programContext); + } + @NotNull public LiteralFunctionTranslator getLiteralFunctionTranslator() { return literalFunctionTranslator; } + @NotNull + public ClassDeclarationTranslator getClassDeclarationTranslator() { + return classDeclarationTranslator; + } + public boolean isEcma5() { return ecmaVersion == EcmaVersion.v5; } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/context/TranslationContext.java b/js/js.translator/src/org/jetbrains/k2js/translate/context/TranslationContext.java index 5b18a31f162..ee679c07e74 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/context/TranslationContext.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/context/TranslationContext.java @@ -25,6 +25,7 @@ import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.Named; import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.k2js.translate.declaration.ClassDeclarationTranslator; import org.jetbrains.k2js.translate.expression.LiteralFunctionTranslator; import org.jetbrains.k2js.translate.intrinsic.Intrinsics; @@ -87,6 +88,7 @@ public class TranslationContext { usageTracker == null ? parent.usageTracker : usageTracker); } + @Nullable public UsageTracker usageTracker() { return usageTracker; } @@ -240,6 +242,11 @@ public class TranslationContext { return staticContext.getLiteralFunctionTranslator(); } + @NotNull + public ClassDeclarationTranslator classDeclarationTranslator() { + return staticContext.getClassDeclarationTranslator(); + } + @NotNull public JsFunction getFunctionObject(@NotNull CallableDescriptor descriptor) { return staticContext.getFunctionWithScope(descriptor); @@ -249,6 +256,7 @@ public class TranslationContext { dynamicContext.jsBlock().getStatements().add(statement); } + @Nullable public JsExpression getAliasForDescriptor(@NotNull DeclarationDescriptor descriptor) { if (usageTracker != null) { usageTracker.triggerUsed(descriptor); 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 58b0149d219..9e6951bbe82 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,9 +17,9 @@ 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.TObjectObjectProcedure; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; @@ -34,7 +34,10 @@ import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.general.AbstractTranslator; import org.jetbrains.k2js.translate.initializer.InitializerUtils; -import java.util.*; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; import static com.google.dart.compiler.backend.js.ast.JsVars.JsVar; import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getClassDescriptorForType; @@ -50,11 +53,27 @@ public final class ClassDeclarationTranslator extends AbstractTranslator { private final THashMap openClassDescriptorToItem = new THashMap(); private final LinkedList openList = new LinkedList(); - private final List> finalList = new ArrayList>(); - @NotNull private final ClassDescriptorToLabel classDescriptorToLabel = new ClassDescriptorToLabel(); + private final THashMap openClassDescriptorToQualifiedLabel = new THashMap(); + + private final ClassAliasingMap classDescriptorToQualifiedLabel = new ClassAliasingMap() { + @NotNull + @Override + public JsNameRef get(ClassDescriptor descriptor, ClassDescriptor referencedDescriptor) { + JsNameRef ref = openClassDescriptorToQualifiedLabel.get(descriptor); + if (ref != null) { + return ref; + } + + // will be resolved later + ref = new JsNameRef(""); + openClassDescriptorToQualifiedLabel.put(descriptor, ref); + return ref; + } + }; + @NotNull private final JsFunction dummyFunction; @@ -71,8 +90,8 @@ public final class ClassDeclarationTranslator extends AbstractTranslator { } private final class ClassDescriptorToLabel implements ClassAliasingMap { - @Override @Nullable + @Override public JsNameRef get(ClassDescriptor descriptor, ClassDescriptor referencedDescriptor) { OpenClassInfo item = openClassDescriptorToItem.get(descriptor); // class declared in library @@ -88,13 +107,11 @@ public final class ClassDeclarationTranslator extends AbstractTranslator { private final ClassDescriptor descriptor; private final JetClass declaration; private final JsNameRef label; - private final JsNameRef qualifiedLabel; - private OpenClassInfo(JetClass declaration, ClassDescriptor descriptor, JsNameRef label, JsNameRef qualifiedLabel) { + private OpenClassInfo(JetClass declaration, ClassDescriptor descriptor, JsNameRef label) { this.descriptor = descriptor; this.declaration = declaration; this.label = label; - this.qualifiedLabel = qualifiedLabel; } } @@ -108,7 +125,7 @@ public final class ClassDeclarationTranslator extends AbstractTranslator { List propertyInitializers = new SmartList(); generateOpenClassDeclarations(vars, propertyInitializers); - generateFinalClassDeclarations(); + fixUnresolvedClassReferences(); if (vars.isEmpty()) { if (!propertyInitializers.isEmpty()) { @@ -154,59 +171,51 @@ public final class ClassDeclarationTranslator extends AbstractTranslator { OpenClassInfo item = it.next(); JsExpression translatedDeclaration = new ClassTranslator(item.declaration, item.descriptor, classDescriptorToLabel, context()).translate(); - generate(item, propertyInitializers, translatedDeclaration, vars); + vars.add(new JsVar(item.label.getName(), translatedDeclaration)); + propertyInitializers.add(new JsPropertyInitializer(item.label, item.label)); } } - private void generateFinalClassDeclarations() { - ClassAliasingMap aliasingMap = new ClassAliasingMap() { + private void fixUnresolvedClassReferences() { + openClassDescriptorToQualifiedLabel.forEachEntry(new TObjectObjectProcedure() { @Override - public JsNameRef get(ClassDescriptor descriptor, ClassDescriptor referencedDescriptor) { - OpenClassInfo item = openClassDescriptorToItem.get(descriptor); - return item == null ? null : item.qualifiedLabel; + public boolean execute(ClassDescriptor descriptor, JsNameRef ref) { + if (ref.getName() == null) { + // from library + ref.resolve(context().getNameForDescriptor(descriptor)); + ref.setQualifier(context().getQualifierForDescriptor(descriptor)); + } + return true; } - }; - - for (Pair item : finalList) { - new ClassTranslator(item.first, aliasingMap, context()).translate(item.second); - } - } - - private static void generate(@NotNull OpenClassInfo item, - @NotNull List propertyInitializers, - @NotNull JsExpression definition, - @NotNull List vars) { - JsExpression value; - if (item.label.getName() == null) { - value = definition; - } - else { - assert item.label.getName() != null; - vars.add(new JsVar(item.label.getName(), definition)); - value = item.label; - } - - propertyInitializers.add(new JsPropertyInitializer(item.label, value)); + }); } @NotNull - public JsPropertyInitializer translate(@NotNull JetClassOrObject declaration) { + public JsPropertyInitializer translate(@NotNull JetClassOrObject declaration, TranslationContext context) { ClassDescriptor descriptor = getClassDescriptor(context().bindingContext(), declaration); JsExpression value; if (descriptor.getModality() == Modality.FINAL) { - JsInvocation invocation = context().namer().classCreateInvocation(descriptor); - finalList.add(new Pair(declaration, invocation)); - value = invocation; + value = new ClassTranslator(declaration, classDescriptorToQualifiedLabel, context).translate(); } else { String label = localLabelGenerator.generate(); - JsNameRef labelRef = dummyFunction.getScope().declareName(label).makeRef(); - OpenClassInfo item = new OpenClassInfo((JetClass) declaration, descriptor, labelRef, - new JsNameRef(labelRef.getIdent(), declarationsObjectRef)); + JsName name = dummyFunction.getScope().declareName(label); + JsNameRef qualifiedLabel = openClassDescriptorToQualifiedLabel.get(descriptor); + if (qualifiedLabel == null) { + qualifiedLabel = new JsNameRef(name); + openClassDescriptorToQualifiedLabel.put(descriptor, qualifiedLabel); + } + else { + qualifiedLabel.resolve(name); + } + qualifiedLabel.setQualifier(declarationsObjectRef); + + OpenClassInfo item = new OpenClassInfo((JetClass) declaration, descriptor, name.makeRef()); + openList.add(item); openClassDescriptorToItem.put(descriptor, item); - value = item.qualifiedLabel; + value = qualifiedLabel; } return InitializerUtils.createPropertyInitializer(descriptor, value, context()); 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 d31de4c1994..29616211a76 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 @@ -129,17 +129,6 @@ public class DeclarationBodyVisitor extends TranslatorVisitor { return null; } - @Override - public Void visitObjectDeclarationName(@NotNull JetObjectDeclarationName expression, - @NotNull TranslationContext context) { - if (!context.isEcma5()) { - PropertyTranslator - .translateAccessors(getPropertyDescriptorForObjectDeclaration(context.bindingContext(), expression), result, context); - } - - return null; - } - @Override public Void visitAnonymousInitializer(@NotNull JetClassInitializer expression, @NotNull TranslationContext context) { // parsed it in initializer visitor => no additional actions are needed 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 81ec34d97ce..ede69fc2074 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 @@ -53,7 +53,6 @@ public final class NamespaceDeclarationTranslator extends AbstractTranslator { Map> descriptorToDefineInvocation = new THashMap>(); JsObjectLiteral rootNamespaceDefinition = null; - ClassDeclarationTranslator classDeclarationTranslator = new ClassDeclarationTranslator(context()); for (JetFile file : files) { NamespaceDescriptor descriptor = context().bindingContext().get(BindingContext.FILE_TO_NAMESPACE, file); assert descriptor != null; @@ -62,7 +61,7 @@ public final class NamespaceDeclarationTranslator extends AbstractTranslator { if (rootNamespaceDefinition == null) { rootNamespaceDefinition = getRootPackage(descriptorToDefineInvocation, descriptor); } - translator = new NamespaceTranslator(descriptor, classDeclarationTranslator, descriptorToDefineInvocation, context()); + translator = new NamespaceTranslator(descriptor, descriptorToDefineInvocation, context()); descriptorToTranslator.put(descriptor, translator); } @@ -83,12 +82,12 @@ public final class NamespaceDeclarationTranslator extends AbstractTranslator { result.add(vars); } - classDeclarationTranslator.generateDeclarations(); + context().classDeclarationTranslator().generateDeclarations(); for (NamespaceTranslator translator : descriptorToTranslator.values()) { translator.add(descriptorToDefineInvocation, result); } - vars.addIfHasInitializer(classDeclarationTranslator.getDeclaration()); + vars.addIfHasInitializer(context().classDeclarationTranslator().getDeclaration()); vars.addIfHasInitializer(getDeclaration(rootNamespaceDefinition)); return result; } 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 d807eab3e08..2cd3435141a 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 @@ -49,21 +49,19 @@ import static org.jetbrains.k2js.translate.utils.BindingUtils.getPropertyDescrip final class NamespaceTranslator extends AbstractTranslator { @NotNull private final NamespaceDescriptor descriptor; - @NotNull - private final ClassDeclarationTranslator classDeclarationTranslator; private final FileDeclarationVisitor visitor; private final NotNullLazyValue, LabelGenerator, JsExpression>> definitionPlace; - NamespaceTranslator(@NotNull final NamespaceDescriptor descriptor, - @NotNull ClassDeclarationTranslator classDeclarationTranslator, + NamespaceTranslator( + @NotNull final NamespaceDescriptor descriptor, @NotNull final Map> descriptorToDefineInvocation, - @NotNull TranslationContext context) { + @NotNull TranslationContext context + ) { super(context.newDeclaration(descriptor)); this.descriptor = descriptor; - this.classDeclarationTranslator = classDeclarationTranslator; visitor = new FileDeclarationVisitor(); @@ -186,9 +184,8 @@ final class NamespaceTranslator extends AbstractTranslator { } @Override - public Void visitClass(@NotNull JetClass expression, @NotNull TranslationContext context) { - JsPropertyInitializer value = classDeclarationTranslator.translate(expression); - result.add(value); + public Void visitClass(@NotNull JetClass declaration, @NotNull TranslationContext context) { + result.add(context.classDeclarationTranslator().translate(declaration, context)); return null; } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/LiteralFunctionTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/expression/LiteralFunctionTranslator.java index b89ae0cef48..ec59593814b 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/expression/LiteralFunctionTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/expression/LiteralFunctionTranslator.java @@ -36,6 +36,7 @@ import org.jetbrains.k2js.translate.context.Namer; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.context.UsageTracker; import org.jetbrains.k2js.translate.declaration.ClassTranslator; +import org.jetbrains.k2js.translate.general.AbstractTranslator; import org.jetbrains.k2js.translate.initializer.InitializerUtils; import java.util.List; @@ -43,16 +44,13 @@ import java.util.List; import static org.jetbrains.k2js.translate.utils.FunctionBodyTranslator.translateFunctionBody; import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getExpectedReceiverDescriptor; -public class LiteralFunctionTranslator { - private TranslationContext rootContext; - +public class LiteralFunctionTranslator extends AbstractTranslator { private final Stack, LabelGenerator, JsExpression>>> definitionPlaces = new Stack, LabelGenerator, JsExpression>>>(); private NotNullLazyValue, LabelGenerator, JsExpression>> definitionPlace; - public void setRootContext(@NotNull TranslationContext rootContext) { - assert this.rootContext == null; - this.rootContext = rootContext; + public LiteralFunctionTranslator(@NotNull TranslationContext context) { + super(context); } public static Trinity, LabelGenerator, JsExpression> createPlace(@NotNull List list, @@ -120,7 +118,7 @@ public class LiteralFunctionTranslator { UsageTracker usageTracker = funContext.usageTracker(); assert usageTracker != null; if (usageTracker.isUsed()) { - return new JsInvocation(rootContext.namer().kotlin("assignOwner"), fun, JsLiteral.THIS); + return new JsInvocation(context().namer().kotlin("assignOwner"), fun, JsLiteral.THIS); } else { fun.setName(null); @@ -138,7 +136,7 @@ public class LiteralFunctionTranslator { private JsNameRef createReference(JsFunction fun) { Trinity, LabelGenerator, JsExpression> place = definitionPlace.getValue(); JsNameRef nameRef = new JsNameRef(place.second.generate(), place.third); - place.first.add(new JsPropertyInitializer(nameRef, InitializerUtils.toDataDescriptor(fun, rootContext))); + place.first.add(new JsPropertyInitializer(nameRef, InitializerUtils.toDataDescriptor(fun, context()))); return nameRef; } @@ -153,18 +151,20 @@ public class LiteralFunctionTranslator { } private JsFunction createFunction() { - return new JsFunction(rootContext.scope(), new JsBlock()); + return new JsFunction(context().scope(), new JsBlock()); } - public JsExpression translate(@NotNull ClassDescriptor outerClass, + public JsExpression translate( + @NotNull ClassDescriptor outerClass, @NotNull JetClassOrObject declaration, @NotNull ClassDescriptor descriptor, - @NotNull ClassTranslator classTranslator) { + @NotNull ClassTranslator classTranslator + ) { JsFunction fun = createFunction(); JsNameRef outerClassRef = fun.getScope().declareName(Namer.OUTER_CLASS_NAME).makeRef(); UsageTracker usageTracker = new UsageTracker(descriptor, null, outerClass); - TranslationContext funContext = rootContext.newFunctionBody(fun, rootContext.aliasingContext().inner(outerClass, outerClassRef), - usageTracker); + TranslationContext funContext = context().newFunctionBody(fun, context().aliasingContext().inner(outerClass, outerClassRef), + usageTracker); fun.getBody().getStatements().add(new JsReturn(classTranslator.translate(funContext))); JetClassBody body = declaration.getBody(); 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 fe765a707f3..6850a914e21 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 @@ -67,11 +67,6 @@ public final class Translation { return FunctionTranslator.newInstance(function, context); } - @NotNull - private static List translateFiles(@NotNull Collection files, @NotNull TranslationContext context) { - return NamespaceDeclarationTranslator.translateFiles(files, context); - } - @NotNull public static PatternTranslator patternTranslator(@NotNull TranslationContext context) { return PatternTranslator.newInstance(context); @@ -134,7 +129,6 @@ public final class Translation { private static JsProgram doGenerateAst(@NotNull BindingContext bindingContext, @NotNull Collection files, @NotNull MainCallParameters mainCallParameters, @NotNull Config config) throws MainFunctionNotFoundException { - //TODO: move some of the code somewhere StaticContext staticContext = StaticContext.generateStaticContext(bindingContext, config.getTarget()); JsProgram program = staticContext.getProgram(); JsBlock block = program.getGlobalBlock(); @@ -145,8 +139,8 @@ public final class Translation { statements.add(program.getStringLiteral("use strict").makeStmt()); TranslationContext context = TranslationContext.rootContext(staticContext, rootFunction); - staticContext.getLiteralFunctionTranslator().setRootContext(context); - statements.addAll(translateFiles(files, context)); + staticContext.initTranslators(context); + statements.addAll(NamespaceDeclarationTranslator.translateFiles(files, context)); defineModule(context, statements, config.getModuleId()); if (mainCallParameters.shouldBeGenerated()) { diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java index fc55ef7b428..b705cc6f8ae 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java @@ -58,7 +58,7 @@ public final class BindingUtils { @NotNull public static ClassDescriptor getClassDescriptor(@NotNull BindingContext context, @NotNull JetClassOrObject declaration) { - return getDescriptorForExpression(context, declaration, ClassDescriptor.class); + return BindingContextUtils.getNotNull(context, BindingContext.CLASS, declaration); } @NotNull @@ -232,12 +232,6 @@ public final class BindingUtils { return BindingContextUtils.getNotNull(context, BindingContext.LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, rangeExpression); } - @NotNull - public static PropertyDescriptor getPropertyDescriptorForObjectDeclaration(@NotNull BindingContext context, - @NotNull JetObjectDeclarationName name) { - return BindingContextUtils.getNotNull(context, BindingContext.OBJECT_DECLARATION, name); - } - @NotNull public static JetType getTypeForExpression(@NotNull BindingContext context, @NotNull JetExpression expression) {