JS backend: refactoring LiteralFunctionTranslator -- make possible to store translation state and create an instance for each translation instead of one instance for all translations.

Introduced DefinitionPlace class and make creating a new definition place more safety.
This commit is contained in:
Zalim Bashorov
2013-12-12 15:45:31 +04:00
parent 1c3c2b2f77
commit 948827aa06
14 changed files with 134 additions and 164 deletions
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.k2js.translate.context
import com.google.dart.compiler.backend.js.ast.JsExpression
import com.google.dart.compiler.backend.js.ast.JsPropertyInitializer
import com.google.dart.compiler.backend.js.ast.JsNameRef
class DefinitionPlace(
val properties: MutableList<JsPropertyInitializer>,
private val fqName: JsExpression
) {
fun define(name: String, expression : JsExpression): JsNameRef {
properties.add(JsPropertyInitializer(JsNameRef(name), expression))
return JsNameRef(name, fqName)
}
}
@@ -31,7 +31,6 @@ 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.expression.LiteralFunctionTranslator;
import org.jetbrains.k2js.translate.intrinsic.Intrinsics;
import org.jetbrains.k2js.translate.utils.AnnotationsUtils;
import org.jetbrains.k2js.translate.utils.JsAstUtils;
@@ -93,9 +92,6 @@ public final class StaticContext {
@NotNull
private final EcmaVersion ecmaVersion;
@NotNull
private LiteralFunctionTranslator literalFunctionTranslator;
//TODO: too many parameters in constructor
private StaticContext(@NotNull JsProgram program, @NotNull BindingContext bindingContext,
@NotNull Namer namer, @NotNull Intrinsics intrinsics,
@@ -109,15 +105,6 @@ public final class StaticContext {
this.ecmaVersion = ecmaVersion;
}
public void initTranslators(TranslationContext programContext) {
literalFunctionTranslator = new LiteralFunctionTranslator(programContext);
}
@NotNull
public LiteralFunctionTranslator getLiteralFunctionTranslator() {
return literalFunctionTranslator;
}
public boolean isEcma5() {
return ecmaVersion == EcmaVersion.v5;
}
@@ -25,7 +25,6 @@ import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.k2js.translate.expression.LiteralFunctionTranslator;
import org.jetbrains.k2js.translate.intrinsic.Intrinsics;
import java.util.HashMap;
@@ -46,31 +45,42 @@ public class TranslationContext {
private final AliasingContext aliasingContext;
@Nullable
private final UsageTracker usageTracker;
@Nullable
private final TranslationContext parent;
@Nullable
private final DefinitionPlace definitionPlace;
@NotNull
public static TranslationContext rootContext(@NotNull StaticContext staticContext, JsFunction rootFunction) {
DynamicContext rootDynamicContext =
DynamicContext.rootContext(rootFunction.getScope(), rootFunction.getBody());
AliasingContext rootAliasingContext = AliasingContext.getCleanContext();
return new TranslationContext(staticContext, rootDynamicContext, rootAliasingContext, null);
return new TranslationContext(null, staticContext, rootDynamicContext, rootAliasingContext, null, null);
}
private final HashMap<JsExpression, TemporaryConstVariable> expressionToTempConstVariableCache = new HashMap<JsExpression, TemporaryConstVariable>();
private TranslationContext(
@Nullable TranslationContext parent,
@NotNull StaticContext staticContext,
@NotNull DynamicContext dynamicContext,
@NotNull AliasingContext aliasingContext,
@Nullable UsageTracker usageTracker
@Nullable UsageTracker usageTracker,
@Nullable DefinitionPlace definitionPlace
) {
this.parent = parent;
this.dynamicContext = dynamicContext;
this.staticContext = staticContext;
this.aliasingContext = aliasingContext;
this.usageTracker = usageTracker;
this.definitionPlace = definitionPlace;
}
private TranslationContext(@NotNull TranslationContext parent, @NotNull AliasingContext aliasingContext) {
this(parent.staticContext, parent.dynamicContext, aliasingContext, parent.usageTracker);
private TranslationContext(
@NotNull TranslationContext parent,
@NotNull AliasingContext aliasingContext
) {
this(parent, parent.staticContext, parent.dynamicContext, aliasingContext, parent.usageTracker, null);
}
private TranslationContext(
@@ -79,8 +89,8 @@ public class TranslationContext {
@NotNull AliasingContext aliasingContext,
@Nullable UsageTracker usageTracker
) {
this(parent.staticContext, DynamicContext.newContext(fun.getScope(), fun.getBody()), aliasingContext,
usageTracker == null ? parent.usageTracker : usageTracker);
this(parent, parent.staticContext, DynamicContext.newContext(fun.getScope(), fun.getBody()), aliasingContext,
usageTracker == null ? parent.usageTracker : usageTracker, null);
}
@Nullable
@@ -97,14 +107,6 @@ public class TranslationContext {
return new TranslationContext(this, fun, aliasingContext, null);
}
@NotNull
private TranslationContext contextWithScope(@NotNull JsScope newScope,
@NotNull JsBlock block,
@NotNull AliasingContext aliasingContext,
@Nullable UsageTracker usageTracker) {
return new TranslationContext(staticContext, DynamicContext.newContext(newScope, block), aliasingContext, usageTracker);
}
@NotNull
public TranslationContext newFunctionBody(
@NotNull JsFunction fun,
@@ -117,12 +119,13 @@ public class TranslationContext {
@NotNull
public TranslationContext innerBlock(@NotNull JsBlock block) {
return new TranslationContext(staticContext, dynamicContext.innerBlock(block), aliasingContext, usageTracker);
return new TranslationContext(this, staticContext, dynamicContext.innerBlock(block), aliasingContext, usageTracker, null);
}
@NotNull
public TranslationContext newDeclaration(@NotNull DeclarationDescriptor descriptor) {
return contextWithScope(getScopeForDescriptor(descriptor), getBlockForDescriptor(descriptor), aliasingContext, usageTracker);
public TranslationContext newDeclaration(@NotNull DeclarationDescriptor descriptor, @Nullable DefinitionPlace place) {
DynamicContext dynamicContext = DynamicContext.newContext(getScopeForDescriptor(descriptor), getBlockForDescriptor(descriptor));
return new TranslationContext(this, staticContext, dynamicContext, aliasingContext, usageTracker, place);
}
@NotNull
@@ -247,11 +250,6 @@ public class TranslationContext {
return aliasingContext;
}
@NotNull
public LiteralFunctionTranslator literalFunctionTranslator() {
return staticContext.getLiteralFunctionTranslator();
}
@NotNull
public JsFunction getFunctionObject(@NotNull CallableDescriptor descriptor) {
return staticContext.getFunctionWithScope(descriptor);
@@ -287,4 +285,12 @@ public class TranslationContext {
JsExpression alias = aliasingContext.getAliasForDescriptor(effectiveDescriptor);
return alias == null ? JsLiteral.THIS : alias;
}
@NotNull
public DefinitionPlace getDefinitionPlace() {
if (definitionPlace != null) return definitionPlace;
if (parent != null) return parent.getDefinitionPlace();
throw new AssertionError("Can not find definition place from rootContext(definitionPlace and parent is null)");
}
}
@@ -17,8 +17,6 @@
package org.jetbrains.k2js.translate.declaration;
import com.google.dart.compiler.backend.js.ast.*;
import com.intellij.openapi.util.NotNullLazyValue;
import com.intellij.openapi.util.Trinity;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
@@ -29,8 +27,9 @@ import org.jetbrains.jet.lang.psi.JetObjectDeclaration;
import org.jetbrains.jet.lang.psi.JetParameter;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeConstructor;
import org.jetbrains.k2js.translate.LabelGenerator;
import org.jetbrains.k2js.translate.context.DefinitionPlace;
import org.jetbrains.k2js.translate.context.TranslationContext;
import org.jetbrains.k2js.translate.expression.LiteralFunctionTranslator;
import org.jetbrains.k2js.translate.general.AbstractTranslator;
import org.jetbrains.k2js.translate.initializer.ClassInitializerTranslator;
import org.jetbrains.k2js.translate.utils.JsAstUtils;
@@ -39,7 +38,6 @@ import java.util.*;
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*;
import static org.jetbrains.jet.lang.types.TypeUtils.topologicallySortSuperclassesAndRecordAllInstances;
import static org.jetbrains.k2js.translate.expression.LiteralFunctionTranslator.createPlace;
import static org.jetbrains.k2js.translate.initializer.InitializerUtils.createClassObjectInitializer;
import static org.jetbrains.k2js.translate.utils.BindingUtils.getClassDescriptor;
import static org.jetbrains.k2js.translate.utils.BindingUtils.getPropertyDescriptorForConstructorParameter;
@@ -110,7 +108,7 @@ public final class ClassTranslator extends AbstractTranslator {
if (containingClass == null) {
return translate(context());
}
return context().literalFunctionTranslator().translate(containingClass, context(), classDeclaration, descriptor, this);
return new LiteralFunctionTranslator(context()).translate(containingClass, context(), classDeclaration, descriptor, this);
}
@NotNull
@@ -130,34 +128,26 @@ public final class ClassTranslator extends AbstractTranslator {
private List<JsExpression> getClassCreateInvocationArguments(@NotNull TranslationContext declarationContext) {
List<JsExpression> invocationArguments = new ArrayList<JsExpression>();
final List<JsPropertyInitializer> properties = new SmartList<JsPropertyInitializer>();
final List<JsPropertyInitializer> staticProperties = new SmartList<JsPropertyInitializer>();
List<JsPropertyInitializer> properties = new SmartList<JsPropertyInitializer>();
List<JsPropertyInitializer> staticProperties = new SmartList<JsPropertyInitializer>();
boolean isTopLevelDeclaration = context() == declarationContext;
final JsNameRef qualifiedReference;
JsNameRef qualifiedReference;
if (!isTopLevelDeclaration) {
qualifiedReference = null;
}
else if (descriptor.getKind().isSingleton() || isAnonymousObject(descriptor)) {
qualifiedReference = null;
declarationContext.literalFunctionTranslator().setDefinitionPlace(
new NotNullLazyValue<Trinity<List<JsPropertyInitializer>, LabelGenerator, JsExpression>>() {
@Override
@NotNull
public Trinity<List<JsPropertyInitializer>, LabelGenerator, JsExpression> compute() {
return createPlace(properties, context().getThisObject(descriptor));
}
});
}
else {
qualifiedReference = declarationContext.getQualifiedReference(descriptor);
declarationContext.literalFunctionTranslator().setDefinitionPlace(
new NotNullLazyValue<Trinity<List<JsPropertyInitializer>, LabelGenerator, JsExpression>>() {
@Override
@NotNull
public Trinity<List<JsPropertyInitializer>, LabelGenerator, JsExpression> compute() {
return createPlace(staticProperties, qualifiedReference);
}
});
DefinitionPlace definitionPlace;
if (descriptor.getKind().isSingleton() || isAnonymousObject(descriptor)) {
qualifiedReference = null;
definitionPlace = new DefinitionPlace(properties, context().getThisObject(descriptor));
}
else {
qualifiedReference = declarationContext.getQualifiedReference(descriptor);
definitionPlace = new DefinitionPlace(staticProperties, qualifiedReference);
}
declarationContext = declarationContext.newDeclaration(descriptor, definitionPlace);
}
invocationArguments.add(getSuperclassReferences(declarationContext));
@@ -171,10 +161,6 @@ public final class ClassTranslator extends AbstractTranslator {
bodyVisitor.traverseContainer(classDeclaration, declarationContext);
mayBeAddEnumEntry(bodyVisitor.getEnumEntryList(), staticProperties, declarationContext);
if (isTopLevelDeclaration) {
declarationContext.literalFunctionTranslator().setDefinitionPlace(null);
}
boolean hasStaticProperties = !staticProperties.isEmpty();
if (!properties.isEmpty() || hasStaticProperties) {
if (properties.isEmpty()) {
@@ -48,10 +48,6 @@ public class DeclarationBodyVisitor extends TranslatorVisitor<Void> {
protected final List<JsPropertyInitializer> staticResult;
protected final List<JsPropertyInitializer> enumEntryList = new SmartList<JsPropertyInitializer>();
public DeclarationBodyVisitor() {
this(new SmartList<JsPropertyInitializer>(), new SmartList<JsPropertyInitializer>());
}
public DeclarationBodyVisitor(@NotNull List<JsPropertyInitializer> result, @NotNull List<JsPropertyInitializer> staticResult) {
this.result = result;
this.staticResult = staticResult;
@@ -30,7 +30,7 @@ public class DefineInvocation {
/* package */
@NotNull
static DefineInvocation createDefineInvocation(
static DefineInvocation create(
@NotNull FqName packageFqName,
@Nullable JsExpression initializer,
@NotNull JsObjectLiteral members,
@@ -15,14 +15,11 @@
*/
package org.jetbrains.k2js.translate.declaration
import com.google.dart.compiler.backend.js.ast.JsExpression
import com.google.dart.compiler.backend.js.ast.JsNameRef
import com.google.dart.compiler.backend.js.ast.JsPropertyInitializer
import org.jetbrains.k2js.translate.initializer.InitializerVisitor
import org.jetbrains.k2js.translate.utils.JsAstUtils
import org.jetbrains.k2js.translate.context.TranslationContext
import org.jetbrains.jet.lang.psi.JetClassInitializer
import com.google.dart.compiler.backend.js.ast.JsStatement
import org.jetbrains.k2js.translate.general.Translation
import org.jetbrains.jet.lang.psi.JetProperty
import org.jetbrains.k2js.translate.initializer.InitializerUtils
@@ -32,8 +29,13 @@ import com.google.dart.compiler.backend.js.ast.JsFunction
import org.jetbrains.k2js.translate.utils.BindingUtils.*
import org.jetbrains.k2js.translate.initializer.InitializerUtils.*
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor
import com.intellij.util.SmartList
class FileDeclarationVisitor(
val context: TranslationContext,
initializers: List<JsPropertyInitializer> = SmartList()
) : DeclarationBodyVisitor(initializers, SmartList()) {
class FileDeclarationVisitor(val context: TranslationContext) : DeclarationBodyVisitor() {
private val initializer = JsAstUtils.createFunctionWithEmptyBody(context.scope())
private val initializerContext = context.contextWithScope(initializer)
private val initializerStatements = initializer.getBody()!!.getStatements()!!
@@ -22,6 +22,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.PackageFragmentDescriptor;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.k2js.translate.context.Namer;
import org.jetbrains.k2js.translate.context.TranslationContext;
@@ -30,7 +31,6 @@ import org.jetbrains.k2js.translate.general.AbstractTranslator;
import java.util.*;
import static com.google.dart.compiler.backend.js.ast.JsVars.JsVar;
import static org.jetbrains.k2js.translate.declaration.DefineInvocation.createDefineInvocation;
public final class PackageDeclarationTranslator extends AbstractTranslator {
private final Iterable<JetFile> files;
@@ -53,12 +53,13 @@ public final class PackageDeclarationTranslator extends AbstractTranslator {
Map<FqName, DefineInvocation> packageFqNameToDefineInvocation = new THashMap<FqName, DefineInvocation>();
for (JetFile file : files) {
PackageFragmentDescriptor packageFragment = context().bindingContext().get(BindingContext.FILE_TO_PACKAGE_FRAGMENT, file);
PackageFragmentDescriptor packageFragment =
BindingContextUtils.getNotNull(context().bindingContext(), BindingContext.FILE_TO_PACKAGE_FRAGMENT, file);
PackageTranslator translator = packageFragmentToTranslator.get(packageFragment);
if (translator == null) {
createRootPackageDefineInvocationIfNeeded(packageFqNameToDefineInvocation);
translator = new PackageTranslator(packageFragment, packageFqNameToDefineInvocation, context());
translator = PackageTranslator.create(packageFragment, context());
packageFragmentToTranslator.put(packageFragment, translator);
}
@@ -78,7 +79,7 @@ public final class PackageDeclarationTranslator extends AbstractTranslator {
private void createRootPackageDefineInvocationIfNeeded(@NotNull Map<FqName, DefineInvocation> packageFqNameToDefineInvocation) {
if (!packageFqNameToDefineInvocation.containsKey(FqName.ROOT)) {
packageFqNameToDefineInvocation.put(
FqName.ROOT, createDefineInvocation(FqName.ROOT, null, new JsObjectLiteral(true), context()));
FqName.ROOT, DefineInvocation.create(FqName.ROOT, null, new JsObjectLiteral(true), context()));
}
}
@@ -17,15 +17,14 @@
package org.jetbrains.k2js.translate.declaration;
import com.google.dart.compiler.backend.js.ast.*;
import com.intellij.openapi.util.NotNullLazyValue;
import com.intellij.openapi.util.Trinity;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.PackageFragmentDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.psi.JetDeclaration;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.k2js.translate.LabelGenerator;
import org.jetbrains.k2js.translate.context.DefinitionPlace;
import org.jetbrains.k2js.translate.context.TranslationContext;
import org.jetbrains.k2js.translate.general.AbstractTranslator;
import org.jetbrains.k2js.translate.utils.AnnotationsUtils;
@@ -34,61 +33,50 @@ import org.jetbrains.k2js.translate.utils.BindingUtils;
import java.util.List;
import java.util.Map;
import static org.jetbrains.k2js.translate.declaration.DefineInvocation.createDefineInvocation;
import static org.jetbrains.k2js.translate.expression.LiteralFunctionTranslator.createPlace;
final class PackageTranslator extends AbstractTranslator {
static PackageTranslator create(
@NotNull PackageFragmentDescriptor descriptor,
@NotNull TranslationContext context
) {
SmartList<JsPropertyInitializer> properties = new SmartList<JsPropertyInitializer>();
DefinitionPlace definitionPlace = new DefinitionPlace(properties, context.getQualifiedReference(descriptor));
TranslationContext newContext = context.newDeclaration(descriptor, definitionPlace);
FileDeclarationVisitor visitor = new FileDeclarationVisitor(newContext, definitionPlace.getProperties());
return new PackageTranslator(descriptor, newContext, visitor);
}
@NotNull
private final PackageFragmentDescriptor descriptor;
private final FileDeclarationVisitor visitor;
private final NotNullLazyValue<Trinity<List<JsPropertyInitializer>, LabelGenerator, JsExpression>> definitionPlace;
PackageTranslator(
@NotNull final PackageFragmentDescriptor descriptor,
@NotNull final Map<FqName, DefineInvocation> packageFqNameToDefineInvocation,
@NotNull TranslationContext context
private PackageTranslator(
@NotNull PackageFragmentDescriptor descriptor,
@NotNull TranslationContext context,
@NotNull FileDeclarationVisitor visitor
) {
super(context.newDeclaration(descriptor));
super(context);
this.descriptor = descriptor;
visitor = new FileDeclarationVisitor(context());
definitionPlace = new NotNullLazyValue<Trinity<List<JsPropertyInitializer>, LabelGenerator, JsExpression>>() {
@Override
@NotNull
public Trinity<List<JsPropertyInitializer>, LabelGenerator, JsExpression> compute() {
DefineInvocation defineInvocation = packageFqNameToDefineInvocation.get(descriptor.getFqName());
if (defineInvocation == null) {
defineInvocation = createDefinitionPlace(null, packageFqNameToDefineInvocation);
}
return createPlace(defineInvocation.getMembers(), context().getQualifiedReference(descriptor.getFqName()));
}
};
this.visitor = visitor;
}
public void translate(JetFile file) {
context().literalFunctionTranslator().setDefinitionPlace(definitionPlace);
for (JetDeclaration declaration : file.getDeclarations()) {
if (!AnnotationsUtils.isPredefinedObject(BindingUtils.getDescriptorForElement(bindingContext(), declaration))) {
declaration.accept(visitor, context());
}
}
context().literalFunctionTranslator().setDefinitionPlace(null);
}
private DefineInvocation createDefinitionPlace(
private void createDefinitionPlace(
@Nullable JsExpression initializer,
Map<FqName, DefineInvocation> packageFqNameToDefineInvocation
) {
FqName fqName = descriptor.getFqName();
DefineInvocation place = createDefineInvocation(fqName, initializer, new JsObjectLiteral(visitor.getResult(), true), context());
DefineInvocation place = DefineInvocation.create(fqName, initializer, new JsObjectLiteral(visitor.getResult(), true), context());
packageFqNameToDefineInvocation.put(fqName, place);
addToParent(fqName.parent(), getEntry(fqName, place), packageFqNameToDefineInvocation);
return place;
}
public void add(@NotNull Map<FqName, DefineInvocation> packageFqNameToDefineInvocation) {
@@ -137,7 +125,7 @@ final class PackageTranslator extends AbstractTranslator {
Map<FqName, DefineInvocation> packageFqNameToDefineInvocation) {
while (!addEntryIfParentExists(parentFqName, entry, packageFqNameToDefineInvocation)) {
JsObjectLiteral members = new JsObjectLiteral(new SmartList<JsPropertyInitializer>(entry), true);
DefineInvocation defineInvocation = createDefineInvocation(parentFqName, null, members, context());
DefineInvocation defineInvocation = DefineInvocation.create(parentFqName, null, members, context());
entry = getEntry(parentFqName, defineInvocation);
packageFqNameToDefineInvocation.put(parentFqName, defineInvocation);
@@ -187,7 +187,7 @@ public final class PropertyTranslator extends AbstractTranslator {
@NotNull
private JsFunction generateDefaultSetterFunction(@NotNull PropertySetterDescriptor setterDescriptor) {
JsFunction fun = new JsFunction(context().getScopeForDescriptor(setterDescriptor.getContainingDeclaration()));
JsParameter defaultParameter = new JsParameter(propertyAccessContext(setterDescriptor).scope().declareTemporary());
JsParameter defaultParameter = new JsParameter(fun.getScope().declareTemporary());
fun.getParameters().add(defaultParameter);
JsExpression setExpression;
@@ -208,11 +208,6 @@ public final class PropertyTranslator extends AbstractTranslator {
return TranslationUtils.translateFunctionAsEcma5PropertyDescriptor(function, accessorDescriptor, context());
}
@NotNull
private TranslationContext propertyAccessContext(@NotNull PropertySetterDescriptor propertySetterDescriptor) {
return context().newDeclaration(propertySetterDescriptor);
}
@NotNull
private JsPropertyInitializer translateCustomAccessor(@NotNull JetPropertyAccessor expression) {
FunctionTranslator translator = Translation.functionTranslator(expression, context());
@@ -403,13 +403,13 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
@Override
@NotNull
public JsNode visitFunctionLiteralExpression(@NotNull JetFunctionLiteralExpression expression, @NotNull TranslationContext context) {
return context.literalFunctionTranslator().translate(expression.getFunctionLiteral(), context);
return new LiteralFunctionTranslator(context).translate(expression.getFunctionLiteral(), context);
}
@Override
@NotNull
public JsNode visitNamedFunction(@NotNull JetNamedFunction expression, @NotNull TranslationContext context) {
JsExpression alias = context.literalFunctionTranslator().translate(expression, context);
JsExpression alias = new LiteralFunctionTranslator(context).translate(expression, context);
FunctionDescriptor descriptor = getFunctionDescriptor(context.bindingContext(), expression);
JsName name = context.scope().declareFreshName(descriptor.getName().asString());
context.aliasingContext().registerAlias(descriptor, name.makeRef());
@@ -17,9 +17,6 @@
package org.jetbrains.k2js.translate.expression;
import com.google.dart.compiler.backend.js.ast.*;
import com.intellij.openapi.util.NotNullLazyValue;
import com.intellij.openapi.util.Trinity;
import com.intellij.util.containers.Stack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
@@ -31,42 +28,24 @@ import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.psi.JetDeclarationWithBody;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.k2js.translate.LabelGenerator;
import org.jetbrains.k2js.translate.context.AliasingContext;
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.context.*;
import org.jetbrains.k2js.translate.declaration.ClassTranslator;
import org.jetbrains.k2js.translate.general.AbstractTranslator;
import java.util.List;
import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptor;
import static org.jetbrains.k2js.translate.utils.FunctionBodyTranslator.translateFunctionBody;
import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getExpectedReceiverDescriptor;
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;
private static final LabelGenerator FUNCTION_NAME_GENERATOR = new LabelGenerator('f');
@NotNull
private final DefinitionPlace definitionPlace;
// TODO: Maybe we need make it private and add static method `translate`
public LiteralFunctionTranslator(@NotNull TranslationContext context) {
super(context);
}
public static Trinity<List<JsPropertyInitializer>, LabelGenerator, JsExpression> createPlace(@NotNull List<JsPropertyInitializer> list,
@NotNull JsExpression reference) {
return Trinity.create(list, new LabelGenerator('f'), reference);
}
public void setDefinitionPlace(@Nullable NotNullLazyValue<Trinity<List<JsPropertyInitializer>, LabelGenerator, JsExpression>> place) {
if (place == null) {
definitionPlaces.pop();
definitionPlace = definitionPlaces.isEmpty() ? null : definitionPlaces.peek();
}
else {
definitionPlaces.push(place);
definitionPlace = place;
}
this.definitionPlace = context.getDefinitionPlace();
}
@NotNull
@@ -128,16 +107,13 @@ public class LiteralFunctionTranslator extends AbstractTranslator {
InnerFunctionTranslator translator = new InnerFunctionTranslator(descriptor, funContext, fun);
JsExpression result = translator.translate(createReference(fun), outerContext);
JsExpression result = translator.translate(defineFunction(fun), outerContext);
addRegularParameters(descriptor, fun, funContext, receiverName);
return result;
}
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, fun));
return nameRef;
private JsNameRef defineFunction(JsFunction fun) {
return definitionPlace.define(FUNCTION_NAME_GENERATOR.generate(), fun);
}
private static void addRegularParameters(
@@ -172,6 +148,6 @@ public class LiteralFunctionTranslator extends AbstractTranslator {
fun.getBody().getStatements().add(new JsReturn(classTranslator.translate(funContext)));
JetClassBody body = declaration.getBody();
assert body != null;
return new InnerObjectTranslator(funContext, fun).translate(createReference(fun), usageTracker.isUsed() ? outerClassRef : null);
return new InnerObjectTranslator(funContext, fun).translate(defineFunction(fun), usageTracker.isUsed() ? outerClassRef : null);
}
}
@@ -134,7 +134,6 @@ public final class Translation {
statements.add(program.getStringLiteral("use strict").makeStmt());
TranslationContext context = TranslationContext.rootContext(staticContext, rootFunction);
staticContext.initTranslators(context);
statements.addAll(PackageDeclarationTranslator.translateFiles(files, context));
defineModule(context, statements, config.getModuleId());
@@ -52,10 +52,13 @@ public final class ClassInitializerTranslator extends AbstractTranslator {
@NotNull
private final List<JsStatement> initializerStatements = new SmartList<JsStatement>();
public ClassInitializerTranslator(@NotNull JetClassOrObject classDeclaration, @NotNull TranslationContext context) {
public ClassInitializerTranslator(
@NotNull JetClassOrObject classDeclaration,
@NotNull TranslationContext context
) {
// Note: it's important we use scope for class descriptor because anonymous function used in property initializers
// belong to the properties themselves
super(context.newDeclaration(getConstructor(context.bindingContext(), classDeclaration)));
super(context.newDeclaration(getConstructor(context.bindingContext(), classDeclaration), null));
this.classDeclaration = classDeclaration;
}