From fe53d20a884b1c02fee800bec22c67dc3239ab56 Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Wed, 21 Mar 2012 22:26:15 +0400 Subject: [PATCH] Refactoring: refactor Aliaser into aliasing context. A very rough draft but test pass. --- .../k2js/translate/context/Aliaser.java | 100 ---------------- .../translate/context/AliasingContext.java | 92 +++++++++++++++ .../k2js/translate/context/StaticContext.java | 17 +-- .../translate/context/TranslationContext.java | 30 +++-- .../ClassDeclarationTranslator.java | 21 +--- .../declaration/ClassTranslator.java | 67 ++++++++--- .../expression/FunctionTranslator.java | 108 +++++++++++------- .../translate/general/AbstractTranslator.java | 6 - .../k2js/translate/general/Translation.java | 6 +- .../initializer/InitializerVisitor.java | 4 +- .../translate/utils/TranslationUtils.java | 30 ++--- 11 files changed, 249 insertions(+), 232 deletions(-) delete mode 100644 js/js.translator/src/org/jetbrains/k2js/translate/context/Aliaser.java create mode 100644 js/js.translator/src/org/jetbrains/k2js/translate/context/AliasingContext.java diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/context/Aliaser.java b/js/js.translator/src/org/jetbrains/k2js/translate/context/Aliaser.java deleted file mode 100644 index 6022a1c91cd..00000000000 --- a/js/js.translator/src/org/jetbrains/k2js/translate/context/Aliaser.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2010-2012 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.JsName; -import com.google.dart.compiler.backend.js.ast.JsNameRef; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; - -import java.util.HashMap; -import java.util.Map; -import java.util.Stack; - -public class Aliaser { - - public static Aliaser newInstance() { - return new Aliaser(); - } - - @NotNull - private final Map aliasesForDescriptors = new HashMap(); - @NotNull - private final Map> aliasesForThis - = new HashMap>(); - - private Aliaser() { - } - - @NotNull - public JsNameRef getAliasForThis(@NotNull DeclarationDescriptor descriptor) { - Stack aliasStack = aliasesForThis.get(descriptor.getOriginal()); - assert !aliasStack.empty(); - JsName aliasName = aliasStack.peek(); - assert aliasName != null : "This " + descriptor.getOriginal() + " doesn't have an alias."; - return aliasName.makeRef(); - } - - public void setAliasForThis(@NotNull DeclarationDescriptor descriptor, @NotNull JsName alias) { - Stack aliasStack = aliasesForThis.get(descriptor.getOriginal()); - if (aliasStack == null) { - aliasStack = new Stack(); - aliasesForThis.put(descriptor, aliasStack); - } - aliasStack.push(alias); - } - - public void removeAliasForThis(@NotNull DeclarationDescriptor descriptor) { - Stack aliasStack = aliasesForThis.get(descriptor.getOriginal()); - assert !aliasStack.empty(); - aliasStack.pop(); - if (aliasStack.empty()) { - aliasesForThis.put(descriptor, null); - } - } - - public boolean hasAliasForThis(@NotNull DeclarationDescriptor descriptor) { - Stack aliasStack = aliasesForThis.get(descriptor.getOriginal()); - if (aliasStack == null) { - return false; - } - return (!aliasStack.empty()); - } - - @NotNull - public JsName getAliasForDeclaration(@NotNull DeclarationDescriptor declaration) { - JsName alias = aliasesForDescriptors.get(declaration.getOriginal()); - assert alias != null : "Use has alias for declaration to check."; - return alias; - } - - public void setAliasForDescriptor(@NotNull DeclarationDescriptor declaration, @NotNull JsName alias) { - assert (!hasAliasForDeclaration(declaration.getOriginal())) : "This declaration already has an alias!"; - aliasesForDescriptors.put(declaration.getOriginal(), alias); - } - - public void removeAliasForDescriptor(@NotNull DeclarationDescriptor declaration) { - assert (hasAliasForDeclaration(declaration.getOriginal())) : "This declaration does not has an alias!"; - aliasesForDescriptors.remove(declaration.getOriginal()); - } - - public boolean hasAliasForDeclaration(@NotNull DeclarationDescriptor declaration) { - return aliasesForDescriptors.containsKey(declaration.getOriginal()); - } - - -} \ No newline at end of file diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/context/AliasingContext.java b/js/js.translator/src/org/jetbrains/k2js/translate/context/AliasingContext.java new file mode 100644 index 00000000000..3786cef2f46 --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/context/AliasingContext.java @@ -0,0 +1,92 @@ +/* + * Copyright 2010-2012 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.common.collect.Maps; +import com.google.dart.compiler.backend.js.ast.JsName; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; + +import java.util.Map; + +/** + * @author Pavel Talanov + */ +public class AliasingContext { + + private static AliasingContext ROOT = new AliasingContext(null) { + @Override + public JsName getAliasForThis(@NotNull DeclarationDescriptor descriptor) { + return null; + } + + @Override + public JsName getAliasForDescriptor(@NotNull DeclarationDescriptor descriptor) { + return null; + } + }; + + public static AliasingContext getCleanContext() { + return new AliasingContext(ROOT); + } + + @NotNull + private final Map aliasesForDescriptors = Maps.newHashMap(); + @NotNull + private final Map aliasesForThis = Maps.newHashMap(); + + @Nullable + private final AliasingContext parent; + + private AliasingContext(@Nullable AliasingContext parent) { + this.parent = parent; + } + + @NotNull + public AliasingContext withThisAliased(@NotNull DeclarationDescriptor correspondingDescriptor, @NotNull JsName alias) { + AliasingContext newContext = new AliasingContext(this); + assert !newContext.aliasesForThis.containsKey(correspondingDescriptor); + newContext.aliasesForThis.put(correspondingDescriptor, alias); + return newContext; + } + + @NotNull + private AliasingContext getParent() { + assert parent != null; + return parent; + } + + + @Nullable + public JsName getAliasForThis(@NotNull DeclarationDescriptor descriptor) { + JsName alias = aliasesForThis.get(descriptor.getOriginal()); + if (alias != null) { + return alias; + } + return getParent().getAliasForThis(descriptor); + } + + @Nullable + public JsName getAliasForDescriptor(@NotNull DeclarationDescriptor descriptor) { + JsName alias = aliasesForDescriptors.get(descriptor.getOriginal()); + if (alias != null) { + return alias; + } + return getParent().getAliasForDescriptor(descriptor); + } +} 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 3f78b937f7f..bc1e01473f0 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 @@ -48,13 +48,11 @@ public final class StaticContext { JsProgram program = new JsProgram("main"); JsRootScope jsRootScope = program.getRootScope(); Namer namer = Namer.newInstance(jsRootScope); - Aliaser aliaser = Aliaser.newInstance(); NamingScope scope = NamingScope.rootScope(jsRootScope); Intrinsics intrinsics = Intrinsics.standardLibraryIntrinsics(library); StandardClasses standardClasses = StandardClasses.bindImplementations(namer.getKotlinScope()); - return new StaticContext(program, bindingContext, aliaser, - namer, intrinsics, standardClasses, scope); + return new StaticContext(program, bindingContext, namer, intrinsics, standardClasses, scope); } @NotNull @@ -62,10 +60,6 @@ public final class StaticContext { @NotNull private final BindingContext bindingContext; - - @NotNull - private final Aliaser aliaser; - @NotNull private final Namer namer; @@ -90,14 +84,12 @@ public final class StaticContext { private final Map scopeToFunction = Maps.newHashMap(); - //qTODO: too many parameters in constructor + //TODO: too many parameters in constructor private StaticContext(@NotNull JsProgram program, @NotNull BindingContext bindingContext, - @NotNull Aliaser aliaser, @NotNull Namer namer, @NotNull Intrinsics intrinsics, @NotNull StandardClasses standardClasses, @NotNull NamingScope rootScope) { this.program = program; this.bindingContext = bindingContext; - this.aliaser = aliaser; this.namer = namer; this.intrinsics = intrinsics; this.rootScope = rootScope; @@ -114,11 +106,6 @@ public final class StaticContext { return bindingContext; } - @NotNull - public Aliaser getAliaser() { - return aliaser; - } - @NotNull public Intrinsics getIntrinsics() { return intrinsics; 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 e463e7a5020..68ed2bd3c65 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 @@ -38,28 +38,35 @@ public final class TranslationContext { private final DynamicContext dynamicContext; @NotNull private final StaticContext staticContext; + @NotNull + private final AliasingContext aliasingContext; @NotNull public static TranslationContext rootContext(@NotNull StaticContext staticContext) { JsProgram program = staticContext.getProgram(); JsBlock globalBlock = program.getGlobalBlock(); + DynamicContext rootDynamicContext = DynamicContext.rootContext(staticContext.getRootScope(), globalBlock); + AliasingContext rootAliasingContext = AliasingContext.getCleanContext(); return new TranslationContext(staticContext, - DynamicContext.rootContext(staticContext.getRootScope(), globalBlock)); + rootDynamicContext, rootAliasingContext); } - private TranslationContext(@NotNull StaticContext staticContext, @NotNull DynamicContext dynamicContext) { + private TranslationContext(@NotNull StaticContext staticContext, + @NotNull DynamicContext dynamicContext, + @NotNull AliasingContext context) { this.dynamicContext = dynamicContext; this.staticContext = staticContext; + aliasingContext = context; } @NotNull public TranslationContext contextWithScope(@NotNull NamingScope newScope, @NotNull JsBlock block) { - return new TranslationContext(staticContext, DynamicContext.newContext(newScope, block)); + return new TranslationContext(staticContext, DynamicContext.newContext(newScope, block), aliasingContext); } @NotNull public TranslationContext innerBlock(@NotNull JsBlock block) { - return new TranslationContext(staticContext, dynamicContext.innerBlock(block)); + return new TranslationContext(staticContext, dynamicContext.innerBlock(block), aliasingContext); } @NotNull @@ -73,6 +80,11 @@ public final class TranslationContext { return contextWithScope(dynamicContext.getScope().innerScope(scope), block); } + @NotNull + public TranslationContext innerContextWithThisAliased(@NotNull DeclarationDescriptor correspondingDescriptor, @NotNull JsName alias) { + return new TranslationContext(staticContext, dynamicContext, aliasingContext.withThisAliased(correspondingDescriptor, alias)); + } + @NotNull public JsBlock getBlockForDescriptor(@NotNull DeclarationDescriptor descriptor) { if (descriptor instanceof CallableDescriptor) { @@ -119,11 +131,6 @@ public final class TranslationContext { return dynamicContext.declareTemporary(initExpression); } - @NotNull - public Aliaser aliaser() { - return staticContext.getAliaser(); - } - @NotNull public Namer namer() { return staticContext.getNamer(); @@ -144,6 +151,11 @@ public final class TranslationContext { return dynamicContext.jsScope(); } + @NotNull + public AliasingContext aliasingContext() { + return aliasingContext; + } + @NotNull public JsFunction getFunctionObject(@NotNull CallableDescriptor descriptor) { return staticContext.getFunctionWithScope(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 9d100fb7f29..b68205b26b5 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 @@ -16,6 +16,8 @@ package org.jetbrains.k2js.translate.declaration; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; import com.google.common.collect.Lists; import com.google.dart.compiler.backend.js.ast.*; import com.google.dart.compiler.util.AstUtil; @@ -32,9 +34,7 @@ import org.jetbrains.k2js.translate.utils.BindingUtils; import org.jetbrains.k2js.translate.utils.ClassSortingUtils; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getAllClassesDefinedInNamespace; import static org.jetbrains.k2js.translate.utils.JsAstUtils.*; @@ -49,7 +49,7 @@ public final class ClassDeclarationTranslator extends AbstractTranslator { @NotNull private final List descriptors; @NotNull - private final Map localToGlobalClassName; + private final BiMap localToGlobalClassName; @NotNull private final JsFunction dummyFunction; @Nullable @@ -61,7 +61,7 @@ public final class ClassDeclarationTranslator extends AbstractTranslator { @NotNull TranslationContext context) { super(context); this.descriptors = descriptors; - this.localToGlobalClassName = new HashMap(); + this.localToGlobalClassName = HashBiMap.create(); this.dummyFunction = new JsFunction(context.jsScope()); } @@ -69,7 +69,7 @@ public final class ClassDeclarationTranslator extends AbstractTranslator { declarationsObject = context().jsScope().declareName(Namer.nameForClassesVariable()); assert declarationsObject != null; declarationsStatement = - newVar(declarationsObject, generateDummyFunctionInvocation()); + newVar(declarationsObject, generateDummyFunctionInvocation()); } @NotNull @@ -112,16 +112,9 @@ public final class ClassDeclarationTranslator extends AbstractTranslator { for (JetClass jetClass : getClassDeclarations()) { classDeclarations.add(generateDeclaration(jetClass)); } - removeAliases(); return classDeclarations; } - private void removeAliases() { - for (JetClass jetClass : getClassDeclarations()) { - ClassDescriptor descriptor = BindingUtils.getClassDescriptor(bindingContext(), jetClass); - aliaser().removeAliasForDescriptor(descriptor); - } - } @NotNull private List getClassDeclarations() { @@ -136,7 +129,7 @@ public final class ClassDeclarationTranslator extends AbstractTranslator { private JsStatement generateDeclaration(@NotNull JetClass declaration) { JsName localClassName = generateLocalAlias(declaration); JsInvocation classDeclarationExpression = - Translation.translateClassDeclaration(declaration, context()); + Translation.translateClassDeclaration(declaration, localToGlobalClassName.inverse(), context()); return newVar(localClassName, classDeclarationExpression); } @@ -145,8 +138,6 @@ public final class ClassDeclarationTranslator extends AbstractTranslator { JsName globalClassName = context().getNameForElement(declaration); JsName localAlias = dummyFunction.getScope().declareTemporary(); localToGlobalClassName.put(localAlias, globalClassName); - ClassDescriptor descriptor = BindingUtils.getClassDescriptor(bindingContext(), declaration); - aliaser().setAliasForDescriptor(descriptor, localAlias); return localAlias; } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassTranslator.java index 581400b2c46..1f13b9636eb 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassTranslator.java @@ -33,7 +33,9 @@ import org.jetbrains.k2js.translate.general.Translation; import org.jetbrains.k2js.translate.utils.JsAstUtils; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Map; import static com.google.dart.compiler.util.AstUtil.newSequence; import static org.jetbrains.k2js.translate.utils.BindingUtils.getClassDescriptor; @@ -53,21 +55,31 @@ public final class ClassTranslator extends AbstractTranslator { @NotNull public static JsPropertyInitializer translateAsProperty(@NotNull JetClassOrObject classDeclaration, @NotNull TranslationContext context) { - JsInvocation classCreationExpression = generateClassCreationExpression(classDeclaration, context); + JsInvocation classCreationExpression = + generateClassCreationExpression(classDeclaration, context); JsName className = context.getNameForElement(classDeclaration); return new JsPropertyInitializer(className.makeRef(), classCreationExpression); } @NotNull public static JsInvocation generateClassCreationExpression(@NotNull JetClassOrObject classDeclaration, + @NotNull Map aliasingMap, @NotNull TranslationContext context) { - return (new ClassTranslator(classDeclaration, context)).translateClassOrObjectCreation(); + return (new ClassTranslator(classDeclaration, aliasingMap, context)).translateClassOrObjectCreation(); + } + + @NotNull + public static JsInvocation generateClassCreationExpression(@NotNull JetClassOrObject classDeclaration, + + @NotNull TranslationContext context) { + return (new ClassTranslator(classDeclaration, Collections.emptyMap(), context)).translateClassOrObjectCreation(); } @NotNull public static JsExpression generateObjectLiteralExpression(@NotNull JetObjectLiteralExpression objectLiteralExpression, @NotNull TranslationContext context) { - return (new ClassTranslator(objectLiteralExpression.getObjectDeclaration(), context)).translateObjectLiteralExpression(); + return (new ClassTranslator(objectLiteralExpression.getObjectDeclaration(), Collections.emptyMap(), context)) + .translateObjectLiteralExpression(); } @NotNull @@ -76,11 +88,20 @@ public final class ClassTranslator extends AbstractTranslator { @NotNull private final JetClassOrObject classDeclaration; + @Nullable + private TemporaryVariable aliasForContainingClassThis = null; + @NotNull private final ClassDescriptor descriptor; - private ClassTranslator(@NotNull JetClassOrObject classDeclaration, @NotNull TranslationContext context) { + @NotNull + private final Map aliasingMap; + + private ClassTranslator(@NotNull JetClassOrObject classDeclaration, + @NotNull Map aliasingMap, + @NotNull TranslationContext context) { super(context.newDeclaration(classDeclaration)); + this.aliasingMap = aliasingMap; this.descriptor = getClassDescriptor(context.bindingContext(), classDeclaration); this.classDeclaration = classDeclaration; } @@ -96,11 +117,8 @@ public final class ClassTranslator extends AbstractTranslator { @NotNull private JsExpression translateAsObjectCreationExpressionWithEnclosingThisSaved(@NotNull ClassDescriptor containingClass) { - TemporaryVariable thisAlias = context().declareTemporary(getThisObject(context(), containingClass)); - aliaser().setAliasForThis(containingClass, thisAlias.name()); - JsBinaryOperation result = newSequence(thisAlias.assignmentExpression(), translateClassOrObjectCreation()); - aliaser().removeAliasForThis(containingClass); - return result; + aliasForContainingClassThis = context().declareTemporary(getThisObject(context(), containingClass)); + return newSequence(aliasForContainingClassThis.assignmentExpression(), translateClassOrObjectCreation()); } @NotNull @@ -155,7 +173,7 @@ public final class ClassTranslator extends AbstractTranslator { private void addTraits(@NotNull List superclassReferences, @NotNull List superclassDescriptors) { for (ClassDescriptor superClassDescriptor : - superclassDescriptors) { + superclassDescriptors) { assert (superClassDescriptor.getKind() == ClassKind.TRAIT) : "Only traits are expected here"; superclassReferences.add(getClassReference(superClassDescriptor)); } @@ -173,8 +191,10 @@ public final class ClassTranslator extends AbstractTranslator { @NotNull private JsExpression getClassReference(@NotNull ClassDescriptor superClassDescriptor) { //NOTE: aliasing here is needed for the declaration generation step - if (aliaser().hasAliasForDeclaration(superClassDescriptor)) { - return aliaser().getAliasForDeclaration(superClassDescriptor).makeRef(); + JsName name = context().getNameForDescriptor(superClassDescriptor); + JsName alias = aliasingMap.get(name); + if (alias != null) { + return alias.makeRef(); } return getQualifiedReference(context(), superClassDescriptor); } @@ -188,25 +208,36 @@ public final class ClassTranslator extends AbstractTranslator { @NotNull private JsObjectLiteral translateClassDeclarations() { + TranslationContext classDeclarationContext = getClassDeclarationContext(); List propertyList = new ArrayList(); if (!isTrait()) { - propertyList.add(Translation.generateClassInitializerMethod(classDeclaration, context())); + propertyList.add(Translation.generateClassInitializerMethod(classDeclaration, classDeclarationContext)); } - propertyList.addAll(translatePropertiesAsConstructorParameters()); - propertyList.addAll(declarationBodyVisitor.traverseClass(classDeclaration, context())); + propertyList.addAll(translatePropertiesAsConstructorParameters(classDeclarationContext)); + propertyList.addAll(declarationBodyVisitor.traverseClass(classDeclaration, classDeclarationContext)); return JsAstUtils.newObjectLiteral(propertyList); } @NotNull - private List translatePropertiesAsConstructorParameters() { + private List translatePropertiesAsConstructorParameters(@NotNull TranslationContext classDeclarationContext) { List result = new ArrayList(); for (JetParameter parameter : getPrimaryConstructorParameters(classDeclaration)) { PropertyDescriptor descriptor = - getPropertyDescriptorForConstructorParameter(bindingContext(), parameter); + getPropertyDescriptorForConstructorParameter(bindingContext(), parameter); if (descriptor != null) { - result.addAll(PropertyTranslator.translateAccessors(descriptor, context())); + result.addAll(PropertyTranslator.translateAccessors(descriptor, 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()); + } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/FunctionTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/expression/FunctionTranslator.java index 1b0402c4d12..c9c38aaf58e 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/expression/FunctionTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/expression/FunctionTranslator.java @@ -20,6 +20,7 @@ package org.jetbrains.k2js.translate.expression; import com.google.dart.compiler.backend.js.ast.*; import com.google.dart.compiler.util.AstUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.JetDeclarationWithBody; import org.jetbrains.jet.lang.psi.JetElement; @@ -34,6 +35,7 @@ import org.jetbrains.k2js.translate.general.AbstractTranslator; import org.jetbrains.k2js.translate.general.Translation; import org.jetbrains.k2js.translate.reference.ReferenceTranslator; import org.jetbrains.k2js.translate.utils.DescriptorUtils; +import org.jetbrains.k2js.translate.utils.TranslationUtils; import org.jetbrains.k2js.translate.utils.closure.ClosureContext; import org.jetbrains.k2js.translate.utils.closure.ClosureUtils; import org.jetbrains.k2js.translate.utils.mutator.Mutator; @@ -45,7 +47,6 @@ import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescrip import static org.jetbrains.k2js.translate.utils.DescriptorUtils.*; import static org.jetbrains.k2js.translate.utils.JsAstUtils.convertToBlock; import static org.jetbrains.k2js.translate.utils.JsAstUtils.setParameters; -import static org.jetbrains.k2js.translate.utils.TranslationUtils.newAliasForThis; import static org.jetbrains.k2js.translate.utils.mutator.LastExpressionMutator.mutateLastExpression; @@ -62,13 +63,15 @@ public final class FunctionTranslator extends AbstractTranslator { return new FunctionTranslator(function, context); } + @Nullable + private TemporaryVariable aliasForContaingClassThis = null; @NotNull private final JetDeclarationWithBody functionDeclaration; + @Nullable + private JsName extensionFunctionReceiverName = null; @NotNull private final JsFunction functionObject; @NotNull - private final TranslationContext functionBodyContext; - @NotNull private final FunctionDescriptor descriptor; // function body needs to be explicitly created here to include it in the context @NotNull @@ -81,14 +84,49 @@ public final class FunctionTranslator extends AbstractTranslator { this.functionDeclaration = functionDeclaration; this.functionObject = context().getFunctionObject(descriptor); this.functionBody = functionObject.getBody(); - this.functionBodyContext = functionBodyContext().innerBlock(functionBody); + } + + @NotNull + private TranslationContext getFunctionBodyContext() { + if (isLiteral()) { + return getFunctionBodyContextForLiteral(); + } + if (isExtensionFunction()) { + return getFunctionBodyContextForExtensionFunction(); + } + return getContextWithFunctionBodyBlock(); + } + + @NotNull + private TranslationContext getFunctionBodyContextForLiteral() { + ClassDescriptor containingClass = getContainingClass(descriptor); + if (containingClass == null) { + return getContextWithFunctionBodyBlock(); + } + JsExpression thisQualifier = TranslationUtils.getThisObject(context(), containingClass); + aliasForContaingClassThis = context().declareTemporary(thisQualifier); + return getContextWithFunctionBodyBlock().innerContextWithThisAliased(containingClass, aliasForContaingClassThis.name()); + } + + @NotNull + private TranslationContext getFunctionBodyContextForExtensionFunction() { + TranslationContext contextWithFunctionBodyBlock = getContextWithFunctionBodyBlock(); + extensionFunctionReceiverName = contextWithFunctionBodyBlock.jsScope().declareName(Namer.getReceiverParameterName()); + DeclarationDescriptor expectedReceiverDescriptor = getExpectedReceiverDescriptor(descriptor); + assert expectedReceiverDescriptor != null; + return contextWithFunctionBodyBlock.innerContextWithThisAliased(expectedReceiverDescriptor, extensionFunctionReceiverName); + } + + @NotNull + private TranslationContext getContextWithFunctionBodyBlock() { + return context().newDeclaration(functionDeclaration).innerBlock(functionBody); } @NotNull public JsFunction translateAsLocalFunction() { JsName functionName = context().getNameForElement(functionDeclaration); - generateFunctionObject(); + generateFunctionObject(getFunctionBodyContext()); functionObject.setName(functionName); return functionObject; } @@ -96,7 +134,7 @@ public final class FunctionTranslator extends AbstractTranslator { @NotNull public JsPropertyInitializer translateAsMethod() { JsName functionName = context().getNameForElement(functionDeclaration); - generateFunctionObject(); + generateFunctionObject(getFunctionBodyContext()); return new JsPropertyInitializer(functionName.makeRef(), functionObject); } @@ -108,17 +146,26 @@ public final class FunctionTranslator extends AbstractTranslator { @NotNull private JsExpression doTranslateAsLiteral() { assert getExpectedThisDescriptor(descriptor) == null; - ClassDescriptor containingClass = getContainingClass(descriptor); - if (containingClass == null) { - generateFunctionObject(); + generateFunctionObject(getFunctionBodyContext()); + boolean shouldAliasThisObject = shouldAliasThisObject(); + if (!shouldAliasThisObject) { return functionObject; } - return generateFunctionObjectWithAliasedThisReference(containingClass); + assert aliasForContaingClassThis != null; + return AstUtil.newSequence(aliasForContaingClassThis.assignmentExpression(), functionObject); + } + + private boolean shouldAliasThisObject() { + if (!isLiteral()) { + return false; + } + ClassDescriptor containingClass = getContainingClass(descriptor); + return containingClass != null; } @NotNull private JsExpression mayBeWrapInClosureCaptureExpression(@NotNull JsExpression wrappedExpression) { - ClosureContext closureContext = ClosureUtils.captureClosure(context(), (JetElement) functionDeclaration); + ClosureContext closureContext = ClosureUtils.captureClosure(context(), (JetElement)functionDeclaration); if (closureContext.getDescriptors().isEmpty()) { return wrappedExpression; } @@ -138,35 +185,18 @@ public final class FunctionTranslator extends AbstractTranslator { return dummyFunctionInvocation; } - @NotNull - private JsExpression generateFunctionObjectWithAliasedThisReference(@NotNull ClassDescriptor containingClass) { - TemporaryVariable aliasForThis = newAliasForThis(context(), containingClass); - generateFunctionObject(); - aliaser().removeAliasForThis(containingClass); - return AstUtil.newSequence(aliasForThis.assignmentExpression(), functionObject); - } - - private void generateFunctionObject() { + private void generateFunctionObject(@NotNull TranslationContext context) { setParameters(functionObject, translateParameters()); - translateBody(); - restoreContext(); + translateBody(context); } - private void restoreContext() { - if (isExtensionFunction()) { - DeclarationDescriptor expectedReceiverDescriptor = getExpectedReceiverDescriptor(descriptor); - assert expectedReceiverDescriptor != null : "Extension functions should always have receiver descriptors."; - functionBodyContext.aliaser().removeAliasForThis(expectedReceiverDescriptor); - } - } - - private void translateBody() { + private void translateBody(@NotNull TranslationContext context) { JetExpression jetBodyExpression = functionDeclaration.getBodyExpression(); if (jetBodyExpression == null) { assert descriptor.getModality().equals(Modality.ABSTRACT); return; } - JsNode realBody = Translation.translateExpression(jetBodyExpression, functionBodyContext); + JsNode realBody = Translation.translateExpression(jetBodyExpression, context); functionBody.getStatements().add(wrapWithReturnIfNeeded(realBody, mustAddReturnToGeneratedFunctionBody())); } @@ -192,16 +222,11 @@ public final class FunctionTranslator extends AbstractTranslator { if (!(node instanceof JsExpression)) { return node; } - return new JsReturn((JsExpression) node); + return new JsReturn((JsExpression)node); } }); } - @NotNull - private TranslationContext functionBodyContext() { - return context().newDeclaration(functionDeclaration); - } - @NotNull private List translateParameters() { List jsParameters = new ArrayList(); @@ -220,11 +245,8 @@ public final class FunctionTranslator extends AbstractTranslator { private void mayBeAddThisParameterForExtensionFunction(@NotNull List jsParameters) { if (isExtensionFunction()) { - JsName receiver = functionBodyContext.jsScope().declareName(Namer.getReceiverParameterName()); - DeclarationDescriptor expectedReceiverDescriptor = getExpectedReceiverDescriptor(descriptor); - assert expectedReceiverDescriptor != null; - aliaser().setAliasForThis(expectedReceiverDescriptor, receiver); - jsParameters.add(new JsParameter(receiver)); + assert extensionFunctionReceiverName != null; + jsParameters.add(new JsParameter(extensionFunctionReceiverName)); } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/general/AbstractTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/general/AbstractTranslator.java index 3edcb3bca9d..c470ef085ec 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/general/AbstractTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/general/AbstractTranslator.java @@ -19,7 +19,6 @@ package org.jetbrains.k2js.translate.general; import com.google.dart.compiler.backend.js.ast.JsProgram; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.k2js.translate.context.Aliaser; import org.jetbrains.k2js.translate.context.TranslationContext; /** @@ -44,11 +43,6 @@ public abstract class AbstractTranslator { return context; } - @NotNull - protected Aliaser aliaser() { - return context.aliaser(); - } - @NotNull protected BindingContext bindingContext() { return context.bindingContext(); 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 b9164a722cc..53fc606ec59 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 @@ -36,6 +36,7 @@ import org.jetbrains.k2js.translate.initializer.ClassInitializerTranslator; import org.jetbrains.k2js.translate.initializer.NamespaceInitializerTranslator; import java.util.List; +import java.util.Map; import static org.jetbrains.k2js.translate.utils.JsAstUtils.convertToExpression; import static org.jetbrains.k2js.translate.utils.JsAstUtils.convertToStatement; @@ -64,8 +65,9 @@ public final class Translation { @NotNull public static JsInvocation translateClassDeclaration(@NotNull JetClass classDeclaration, + @NotNull Map aliasingMap, @NotNull TranslationContext context) { - return ClassTranslator.generateClassCreationExpression(classDeclaration, context); + return ClassTranslator.generateClassCreationExpression(classDeclaration, aliasingMap, context); } @NotNull @@ -124,6 +126,4 @@ public final class Translation { namer.exec(context.program()); return context.program(); } - - } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/initializer/InitializerVisitor.java b/js/js.translator/src/org/jetbrains/k2js/translate/initializer/InitializerVisitor.java index 47b128dd366..ab05b3209c7 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/initializer/InitializerVisitor.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/initializer/InitializerVisitor.java @@ -84,11 +84,11 @@ public final class InitializerVisitor extends TranslatorVisitor visitObjectDeclarationName(@NotNull JetObjectDeclarationName objectName, @NotNull TranslationContext context) { PropertyDescriptor propertyDescriptorForObjectDeclaration - = getPropertyDescriptorForObjectDeclaration(context.bindingContext(), objectName); + = getPropertyDescriptorForObjectDeclaration(context.bindingContext(), objectName); JetObjectDeclaration objectDeclaration = getObjectDeclarationForName(objectName); JsInvocation objectValue = ClassTranslator.generateClassCreationExpression(objectDeclaration, context); JsExprStmt assignment = assignmentToBackingField(context, propertyDescriptorForObjectDeclaration, objectValue) - .makeStmt(); + .makeStmt(); return Collections.singletonList(assignment); } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java index dce66c642e1..50dad2a11c1 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java @@ -21,7 +21,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; -import org.jetbrains.k2js.translate.context.TemporaryVariable; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.general.Translation; import org.jetbrains.k2js.translate.intrinsic.Intrinsic; @@ -117,23 +116,21 @@ public final class TranslationUtils { @NotNull public static JsExpression getThisObject(@NotNull TranslationContext context, @NotNull DeclarationDescriptor correspondingDeclaration) { - JsExpression thisRef = null; if (correspondingDeclaration instanceof ClassDescriptor) { - if (context.aliaser().hasAliasForThis(correspondingDeclaration)) { - thisRef = context.aliaser().getAliasForThis(correspondingDeclaration); + JsName alias = context.aliasingContext().getAliasForThis(correspondingDeclaration); + if (alias != null) { + return alias.makeRef(); } } if (correspondingDeclaration instanceof CallableDescriptor) { DeclarationDescriptor receiverDescriptor = - getExpectedReceiverDescriptor((CallableDescriptor) correspondingDeclaration); + getExpectedReceiverDescriptor((CallableDescriptor)correspondingDeclaration); assert receiverDescriptor != null; - if (context.aliaser().hasAliasForThis(receiverDescriptor)) { - thisRef = context.aliaser().getAliasForThis(receiverDescriptor); + JsName alias = context.aliasingContext().getAliasForThis(receiverDescriptor); + if (alias != null) { + return alias.makeRef(); } } - if (thisRef != null) { - return thisRef; - } return new JsThisRef(); } @@ -171,7 +168,7 @@ public final class TranslationUtils { public static boolean isIntrinsicOperation(@NotNull TranslationContext context, @NotNull JetOperationExpression expression) { FunctionDescriptor operationDescriptor = - BindingUtils.getFunctionDescriptorForOperationExpression(context.bindingContext(), expression); + BindingUtils.getFunctionDescriptorForOperationExpression(context.bindingContext(), expression); if (operationDescriptor == null) return true; if (context.intrinsics().isIntrinsic(operationDescriptor)) return true; @@ -183,7 +180,7 @@ public final class TranslationUtils { public static JsNameRef getMethodReferenceForOverloadedOperation(@NotNull TranslationContext context, @NotNull JetOperationExpression expression) { FunctionDescriptor overloadedOperationDescriptor = getFunctionDescriptorForOperationExpression - (context.bindingContext(), expression); + (context.bindingContext(), expression); assert overloadedOperationDescriptor != null; JsNameRef overloadedOperationReference = context.getNameForDescriptor(overloadedOperationDescriptor).makeRef(); assert overloadedOperationReference != null; @@ -195,15 +192,6 @@ public final class TranslationUtils { return context.program().getNumberLiteral(0); } - @NotNull - public static TemporaryVariable newAliasForThis(@NotNull TranslationContext context, - @NotNull DeclarationDescriptor descriptor) { - JsExpression thisQualifier = getThisObject(context, descriptor); - TemporaryVariable aliasForThis = context.declareTemporary(thisQualifier); - context.aliaser().setAliasForThis(descriptor, aliasForThis.name()); - return aliasForThis; - } - @NotNull public static JsExpression applyIntrinsicToBinaryExpression(@NotNull TranslationContext context, @NotNull Intrinsic intrinsic,