JS backend: refactoring -- prepare to fix KT-2696

This commit is contained in:
develar
2013-08-14 14:50:06 +04:00
committed by Zalim Bashorov
parent 92eb4a5f1f
commit 4544990188
9 changed files with 101 additions and 98 deletions
@@ -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;
}
@@ -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);
@@ -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<ClassDescriptor, OpenClassInfo> openClassDescriptorToItem = new THashMap<ClassDescriptor, OpenClassInfo>();
private final LinkedList<OpenClassInfo> openList = new LinkedList<OpenClassInfo>();
private final List<Pair<JetClassOrObject, JsInvocation>> finalList = new ArrayList<Pair<JetClassOrObject, JsInvocation>>();
@NotNull
private final ClassDescriptorToLabel classDescriptorToLabel = new ClassDescriptorToLabel();
private final THashMap<ClassDescriptor, JsNameRef> openClassDescriptorToQualifiedLabel = new THashMap<ClassDescriptor, JsNameRef>();
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("<unresolved class>");
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<JsPropertyInitializer> propertyInitializers = new SmartList<JsPropertyInitializer>();
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<ClassDescriptor, JsNameRef>() {
@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<JetClassOrObject, JsInvocation> item : finalList) {
new ClassTranslator(item.first, aliasingMap, context()).translate(item.second);
}
}
private static void generate(@NotNull OpenClassInfo item,
@NotNull List<JsPropertyInitializer> propertyInitializers,
@NotNull JsExpression definition,
@NotNull List<JsVar> 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<JetClassOrObject, JsInvocation>(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());
@@ -129,17 +129,6 @@ public class DeclarationBodyVisitor extends TranslatorVisitor<Void> {
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
@@ -53,7 +53,6 @@ public final class NamespaceDeclarationTranslator extends AbstractTranslator {
Map<NamespaceDescriptor, List<JsExpression>> descriptorToDefineInvocation = new THashMap<NamespaceDescriptor, List<JsExpression>>();
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;
}
@@ -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<Trinity<List<JsPropertyInitializer>, LabelGenerator, JsExpression>> definitionPlace;
NamespaceTranslator(@NotNull final NamespaceDescriptor descriptor,
@NotNull ClassDeclarationTranslator classDeclarationTranslator,
NamespaceTranslator(
@NotNull final NamespaceDescriptor descriptor,
@NotNull final Map<NamespaceDescriptor, List<JsExpression>> 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;
}
@@ -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<NotNullLazyValue<Trinity<List<JsPropertyInitializer>, LabelGenerator, JsExpression>>> definitionPlaces =
new Stack<NotNullLazyValue<Trinity<List<JsPropertyInitializer>, LabelGenerator, JsExpression>>>();
private NotNullLazyValue<Trinity<List<JsPropertyInitializer>, 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<List<JsPropertyInitializer>, LabelGenerator, JsExpression> createPlace(@NotNull List<JsPropertyInitializer> 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<List<JsPropertyInitializer>, 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();
@@ -67,11 +67,6 @@ public final class Translation {
return FunctionTranslator.newInstance(function, context);
}
@NotNull
private static List<JsStatement> translateFiles(@NotNull Collection<JetFile> 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<JetFile> 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()) {
@@ -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) {