Refactoring: refactor Aliaser into aliasing context. A very rough draft but test pass.
This commit is contained in:
@@ -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);
|
||||
|
||||
+6
-15
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+49
-18
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
+65
-43
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user