Refactoring: refactor Aliaser into aliasing context. A very rough draft but test pass.

This commit is contained in:
Pavel V. Talanov
2012-03-21 22:26:15 +04:00
parent 91f488fdf8
commit fe53d20a88
11 changed files with 249 additions and 232 deletions
@@ -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<DeclarationDescriptor, JsName> aliasesForDescriptors = new HashMap<DeclarationDescriptor, JsName>();
@NotNull
private final Map<DeclarationDescriptor, Stack<JsName>> aliasesForThis
= new HashMap<DeclarationDescriptor, Stack<JsName>>();
private Aliaser() {
}
@NotNull
public JsNameRef getAliasForThis(@NotNull DeclarationDescriptor descriptor) {
Stack<JsName> 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<JsName> aliasStack = aliasesForThis.get(descriptor.getOriginal());
if (aliasStack == null) {
aliasStack = new Stack<JsName>();
aliasesForThis.put(descriptor, aliasStack);
}
aliasStack.push(alias);
}
public void removeAliasForThis(@NotNull DeclarationDescriptor descriptor) {
Stack<JsName> aliasStack = aliasesForThis.get(descriptor.getOriginal());
assert !aliasStack.empty();
aliasStack.pop();
if (aliasStack.empty()) {
aliasesForThis.put(descriptor, null);
}
}
public boolean hasAliasForThis(@NotNull DeclarationDescriptor descriptor) {
Stack<JsName> 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());
}
}
@@ -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<DeclarationDescriptor, JsName> aliasesForDescriptors = Maps.newHashMap();
@NotNull
private final Map<DeclarationDescriptor, JsName> 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);
}
}
@@ -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<NamingScope, JsFunction> 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;
@@ -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);
@@ -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<ClassDescriptor> descriptors;
@NotNull
private final Map<JsName, JsName> localToGlobalClassName;
private final BiMap<JsName, JsName> 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<JsName, JsName>();
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<JetClass> 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;
}
@@ -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<JsName, JsName> 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.<JsName, JsName>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.<JsName, JsName>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<JsName, JsName> aliasingMap;
private ClassTranslator(@NotNull JetClassOrObject classDeclaration,
@NotNull Map<JsName, JsName> 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<JsExpression> superclassReferences,
@NotNull List<ClassDescriptor> 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<JsPropertyInitializer> propertyList = new ArrayList<JsPropertyInitializer>();
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<JsPropertyInitializer> translatePropertiesAsConstructorParameters() {
private List<JsPropertyInitializer> translatePropertiesAsConstructorParameters(@NotNull TranslationContext classDeclarationContext) {
List<JsPropertyInitializer> result = new ArrayList<JsPropertyInitializer>();
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());
}
}
@@ -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<JsParameter> translateParameters() {
List<JsParameter> jsParameters = new ArrayList<JsParameter>();
@@ -220,11 +245,8 @@ public final class FunctionTranslator extends AbstractTranslator {
private void mayBeAddThisParameterForExtensionFunction(@NotNull List<JsParameter> 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));
}
}
@@ -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();
@@ -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<JsName, JsName> 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();
}
}
@@ -84,11 +84,11 @@ public final class InitializerVisitor extends TranslatorVisitor<List<JsStatement
public List<JsStatement> 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.<JsStatement>singletonList(assignment);
}
@@ -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,