Reworked ExtractionVisitor into Declaration visitor.

This commit is contained in:
Pavel Talanov
2011-11-29 17:29:32 +04:00
parent 5ed130b745
commit ba767e7205
6 changed files with 230 additions and 145 deletions
@@ -0,0 +1,46 @@
package org.jetbrains.k2js.declarations;
import com.google.dart.compiler.backend.js.ast.JsName;
import com.google.dart.compiler.backend.js.ast.JsNameRef;
import com.google.dart.compiler.backend.js.ast.JsScope;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public final class DeclarationContext {
@NotNull
public static DeclarationContext rootContext(@NotNull JsScope scope, @Nullable JsNameRef qualifier) {
return new DeclarationContext(scope, qualifier);
}
@NotNull
private final JsScope scope;
@Nullable
private final JsNameRef qualifier;
private DeclarationContext(@NotNull JsScope scope, @Nullable JsNameRef qualifier) {
this.scope = scope;
this.qualifier = qualifier;
}
@NotNull
public JsScope getScope() {
return scope;
}
@Nullable
public JsNameRef getQualifier() {
return qualifier;
}
@NotNull
public DeclarationContext innerDeclaration(@NotNull JsScope declarationScope, @NotNull JsName declarationName) {
JsNameRef reference = declarationName.makeRef();
if (qualifier != null) {
AstUtil.setQualifier(reference, qualifier);
}
return new DeclarationContext(declarationScope, reference);
}
}
@@ -0,0 +1,139 @@
package org.jetbrains.k2js.declarations;
import com.google.dart.compiler.backend.js.ast.JsName;
import com.google.dart.compiler.backend.js.ast.JsScope;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.k2js.translate.utils.Namer;
/**
* @author Talanov Pavel
*/
public final class DeclarationVisitor extends DeclarationDescriptorVisitor<Void, DeclarationContext> {
@NotNull
private final Declarations declarations;
/*package*/ DeclarationVisitor(@NotNull Declarations declarations) {
this.declarations = declarations;
}
@Override
public Void visitClassDescriptor(@NotNull ClassDescriptor descriptor, @NotNull DeclarationContext context) {
DeclarationContext classContext = declareClass(descriptor, context);
declareClassConstructor(descriptor, context);
declareClassMembers(descriptor, classContext);
return null;
}
@NotNull
private DeclarationContext declareClass(@NotNull ClassDescriptor descriptor,
@NotNull DeclarationContext context) {
JsScope classScope = declareScope(descriptor, context, "class " + descriptor.getName());
JsName className = declareName(descriptor, context);
return context.innerDeclaration(classScope, className);
}
private JsScope declareScope(@NotNull DeclarationDescriptor descriptor, @NotNull DeclarationContext context,
@NotNull String scopeName) {
JsScope classScope = new JsScope(context.getScope(), scopeName);
declarations.putScope(descriptor, classScope);
return classScope;
}
@NotNull
private JsName declareName(@NotNull DeclarationDescriptor descriptor, @NotNull DeclarationContext context,
@NotNull String name) {
JsName jsName = context.getScope().declareName(name);
declarations.putName(descriptor, jsName);
declarations.putQualifier(descriptor, context.getQualifier());
return jsName;
}
@NotNull
private JsName declareName(@NotNull DeclarationDescriptor descriptor,
@NotNull DeclarationContext context) {
return declareName(descriptor, context, descriptor.getName());
}
private void declareClassMembers(@NotNull ClassDescriptor descriptor, @NotNull DeclarationContext context) {
for (DeclarationDescriptor memberDescriptor :
descriptor.getDefaultType().getMemberScope().getAllDescriptors()) {
memberDescriptor.accept(this, context);
}
}
private void declareClassConstructor(@NotNull ClassDescriptor descriptor, @NotNull DeclarationContext context) {
for (ConstructorDescriptor constructorDescriptor : descriptor.getConstructors()) {
constructorDescriptor.accept(this, context);
}
}
@Override
public Void visitConstructorDescriptor(@NotNull ConstructorDescriptor descriptor,
@NotNull DeclarationContext context) {
JsName alreadyDeclaredClassName = declarations.getName(descriptor.getContainingDeclaration());
declarations.putName(descriptor, alreadyDeclaredClassName);
return null;
}
@Override
public Void visitFunctionDescriptor(@NotNull FunctionDescriptor descriptor, @NotNull DeclarationContext context) {
declareName(descriptor, context);
declareScope(descriptor, context, "function " + descriptor.getName());
return null;
}
@Override
public Void visitPropertyDescriptor(@NotNull PropertyDescriptor descriptor, @NotNull DeclarationContext context) {
String propertyName = descriptor.getName();
String backingFieldName = Namer.getKotlinBackingFieldName(propertyName);
declareName(descriptor, context, backingFieldName);
extractAccessor(descriptor.getGetter(), true, propertyName, context);
if (descriptor.isVar()) {
extractAccessor(descriptor.getSetter(), false, propertyName, context);
}
return null;
}
public void extractAccessor(@Nullable PropertyAccessorDescriptor descriptor, boolean isGetter,
@NotNull String propertyName, @NotNull DeclarationContext context) {
assert descriptor != null : "Accessor descriptor should not be null";
String accessorName = Namer.getNameForAccessor(propertyName, isGetter);
declareName(descriptor, context, accessorName);
declareScope(descriptor, context, (isGetter ? "getter " : "setter ") + propertyName);
}
@Override
public Void visitNamespaceDescriptor(@NotNull NamespaceDescriptor descriptor, @NotNull DeclarationContext context) {
DeclarationContext namespaceContext = extractNamespaceDeclaration(descriptor, context);
visitMemberDeclarations(descriptor, namespaceContext);
return null;
}
@NotNull
private DeclarationContext extractNamespaceDeclaration(@NotNull NamespaceDescriptor descriptor,
@NotNull DeclarationContext context) {
JsName namespaceName = declareName(descriptor, context, nameForNamespace(descriptor));
JsScope namespaceScope = declareScope(descriptor, context, "namespace " + namespaceName.getIdent());
return context.innerDeclaration(namespaceScope, namespaceName);
}
@NotNull
private String nameForNamespace(@NotNull NamespaceDescriptor descriptor) {
String name = descriptor.getName();
if (name.equals("")) {
return "Anonymous";
}
return name;
}
private void visitMemberDeclarations(@NotNull NamespaceDescriptor descriptor, @NotNull DeclarationContext context) {
for (DeclarationDescriptor memberDescriptor :
descriptor.getMemberScope().getAllDescriptors()) {
memberDescriptor.accept(this, context);
}
}
}
@@ -1,9 +1,12 @@
package org.jetbrains.k2js.declarations;
import com.google.dart.compiler.backend.js.ast.JsName;
import com.google.dart.compiler.backend.js.ast.JsNameRef;
import com.google.dart.compiler.backend.js.ast.JsScope;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.types.JetStandardLibrary;
import java.util.HashMap;
import java.util.Map;
@@ -12,46 +15,69 @@ import java.util.Map;
* @author Talanov Pavel
*/
public final class Declarations {
private final Map<DeclarationDescriptor, JsScope> descriptorToScopeMap
= new HashMap<DeclarationDescriptor, JsScope>();
private final Map<DeclarationDescriptor, JsName> descriptorToNameMap
= new HashMap<DeclarationDescriptor, JsName>();
private Declarations() {
@NotNull
private final Map<DeclarationDescriptor, JsScope> descriptorToScopeMap = new HashMap<DeclarationDescriptor, JsScope>();
@NotNull
private final Map<DeclarationDescriptor, JsName> descriptorToNameMap = new HashMap<DeclarationDescriptor, JsName>();
@NotNull
private final Map<DeclarationDescriptor, JsNameRef> descriptorToQualifierMap = new HashMap<DeclarationDescriptor, JsNameRef>();
@NotNull
private final JsScope rootScope;
private Declarations(@NotNull JsScope scope) {
this.rootScope = scope;
}
@NotNull
static public Declarations extractDeclarations(@NotNull DeclarationDescriptor descriptor, JsScope rootScope) {
Declarations declarations = new Declarations();
ExtractionVisitor visitor = new ExtractionVisitor(declarations);
descriptor.accept(visitor, rootScope);
return declarations;
static public Declarations newInstance(@NotNull JsScope rootScope) {
return new Declarations(rootScope);
}
public void extractDeclarations(@NotNull DeclarationDescriptor descriptor) {
DeclarationVisitor visitor = new DeclarationVisitor(this);
descriptor.accept(visitor, DeclarationContext.rootContext(rootScope, null));
}
//TODO: provide a mechanism to do intrinsics
public void extractStandardLibrary(@NotNull JetStandardLibrary standardLibrary) {
DeclarationVisitor visitor = new DeclarationVisitor(this);
// for (DeclarationDescriptor descriptor :
// standardLibrary.getLibraryScope().getAllDescriptors()) {
// descriptor.accept(visitor, rootScope);
// }
// standardLibrary.getArray().accept(visitor, rootScope);
}
@NotNull
public JsScope getScope(@NotNull DeclarationDescriptor descriptor) {
JsScope scope = descriptorToScopeMap.get(descriptor);
JsScope scope = descriptorToScopeMap.get(descriptor.getOriginal());
assert scope != null : "Unknown declaration";
return scope;
}
@NotNull
public JsName getName(@NotNull DeclarationDescriptor descriptor) {
JsName name = descriptorToNameMap.get(descriptor);
JsName name = descriptorToNameMap.get(descriptor.getOriginal());
assert name != null : "Unknown declaration";
return name;
}
public boolean isDeclared(@NotNull DeclarationDescriptor descriptor) {
return descriptorToNameMap.containsKey(descriptor);
return descriptorToNameMap.containsKey(descriptor.getOriginal());
}
/*package*/ void putScope(@NotNull DeclarationDescriptor descriptor, @NotNull JsScope scope) {
assert !descriptorToScopeMap.containsKey(descriptor) : "Already contains that key!";
descriptorToScopeMap.put(descriptor, scope);
}
/*package*/ void putName(@NotNull DeclarationDescriptor descriptor, @NotNull JsName name) {
assert !descriptorToNameMap.containsKey(descriptor) : "Already contains that key!";
descriptorToNameMap.put(descriptor, name);
}
/*package*/ void putQualifier(@NotNull DeclarationDescriptor descriptor, @Nullable JsNameRef qualifier) {
assert !descriptorToQualifierMap.containsKey(descriptor) : "Already contains that key!";
descriptorToQualifierMap.put(descriptor, qualifier);
}
}
@@ -1,130 +0,0 @@
package org.jetbrains.k2js.declarations;
import com.google.dart.compiler.backend.js.ast.JsName;
import com.google.dart.compiler.backend.js.ast.JsScope;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.k2js.translate.utils.Namer;
/**
* @author Talanov Pavel
*/
public final class ExtractionVisitor extends DeclarationDescriptorVisitor<Void, JsScope> {
@NotNull
private final Declarations declarations;
/*package*/ ExtractionVisitor(@NotNull Declarations declarations) {
this.declarations = declarations;
}
@Override
public Void visitClassDescriptor(@NotNull ClassDescriptor descriptor, @NotNull JsScope enclosingScope) {
JsScope classScope = extractClassDeclarations(descriptor, enclosingScope);
visitClassMembers(descriptor, classScope);
return null;
}
@NotNull
private JsScope extractClassDeclarations(@NotNull ClassDescriptor descriptor, @NotNull JsScope enclosingScope) {
String className = descriptor.getName();
declarations.putName(descriptor, enclosingScope.declareName(className));
JsScope classScope = new JsScope(enclosingScope, "class " + className);
declarations.putScope(descriptor, classScope);
return classScope;
}
private void visitClassMembers(@NotNull ClassDescriptor descriptor, @NotNull JsScope classScope) {
visitClassConstructor(descriptor, classScope);
for (DeclarationDescriptor memberDescriptor :
descriptor.getDefaultType().getMemberScope().getAllDescriptors()) {
memberDescriptor.accept(this, classScope);
}
}
private void visitClassConstructor(@NotNull ClassDescriptor descriptor, @NotNull JsScope classScope) {
for (ConstructorDescriptor constructorDescriptor : descriptor.getConstructors()) {
constructorDescriptor.accept(this, classScope);
}
}
//TODO: think about the ways to make this less hacky
//For now constructor just references the name of the class. Initialize method scope is defined independently.
@Override
public Void visitConstructorDescriptor(@NotNull ConstructorDescriptor descriptor, @NotNull JsScope enclosingScope) {
String className = descriptor.getContainingDeclaration().getName();
JsName alreadyDeclaredClassName = enclosingScope.findExistingName(className);
declarations.putName(descriptor, alreadyDeclaredClassName);
return null;
}
@Override
public Void visitFunctionDescriptor(@NotNull FunctionDescriptor descriptor, @NotNull JsScope enclosingScope) {
String functionName = descriptor.getName();
declarations.putName(descriptor, enclosingScope.declareName(functionName));
JsScope functionScope = new JsScope(enclosingScope, "function " + functionName);
declarations.putScope(descriptor, functionScope);
return null;
}
@Override
public Void visitPropertyDescriptor(@NotNull PropertyDescriptor descriptor, @NotNull JsScope enclosingScope) {
String propertyName = descriptor.getName();
declarations.putName(descriptor, enclosingScope.declareName(Namer.getKotlinBackingFieldName(propertyName)));
extractAccessor(descriptor.getGetter(), true, propertyName, enclosingScope);
if (descriptor.isVar()) {
extractAccessor(descriptor.getSetter(), false, propertyName, enclosingScope);
}
return null;
}
//Not using visitors here for convenience
public void extractAccessor(@Nullable PropertyAccessorDescriptor descriptor, boolean isGetter, String propertyName,
@NotNull JsScope enclosingScope) {
assert descriptor != null : "Accessor descriptor should not be null";
String accessorName = Namer.getNameForAccessor(propertyName, isGetter);
JsName jsName = enclosingScope.declareName(accessorName);
JsScope accessorScope = new JsScope(enclosingScope, (isGetter ? "getter " : "setter ") + propertyName);
declarations.putScope(descriptor, accessorScope);
declarations.putName(descriptor, jsName);
}
@Override
public Void visitNamespaceDescriptor(@NotNull NamespaceDescriptor descriptor, @NotNull JsScope enclosingScope) {
JsScope namespaceScope = extractNamespaceDeclaration(descriptor, enclosingScope);
visitMemberDeclarations(descriptor, namespaceScope);
return null;
}
@NotNull
private JsScope extractNamespaceDeclaration(@NotNull NamespaceDescriptor descriptor,
@NotNull JsScope enclosingScope) {
JsName name;
String namespaceName = descriptor.getName();
name = getNameForNamespace(enclosingScope, namespaceName);
declarations.putName(descriptor, name);
JsScope namespaceScope = new JsScope(enclosingScope, "namespace " + namespaceName);
declarations.putScope(descriptor, namespaceScope);
return namespaceScope;
}
@NotNull
private JsName getNameForNamespace(@NotNull JsScope enclosingScope, @NotNull String namespaceName) {
JsName name;
if (namespaceName.equals("")) {
name = enclosingScope.declareName("Anonymous");
} else {
name = enclosingScope.declareName(namespaceName);
}
return name;
}
private void visitMemberDeclarations(@NotNull NamespaceDescriptor descriptor, @NotNull JsScope namespaceScope) {
for (DeclarationDescriptor memberDescriptor :
descriptor.getMemberScope().getAllDescriptors()) {
memberDescriptor.accept(this, namespaceScope);
}
}
}
@@ -7,6 +7,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.JetStandardLibrary;
import org.jetbrains.k2js.declarations.Declarations;
import org.jetbrains.k2js.translate.declaration.ClassTranslator;
import org.jetbrains.k2js.translate.declaration.NamespaceTranslator;
@@ -98,7 +99,9 @@ public final class Translation {
//TODO hardcoded
JsProgram result = new JsProgram("main");
NamespaceDescriptor descriptor = BindingUtils.getNamespaceDescriptor(bindingContext, namespace);
Declarations declarations = Declarations.extractDeclarations(descriptor, result.getRootScope());
Declarations declarations = Declarations.newInstance(result.getRootScope());
declarations.extractStandardLibrary(JetStandardLibrary.getJetStandardLibrary(project));
declarations.extractDeclarations(descriptor);
JsBlock block = result.getFragmentBlock(0);
TranslationContext context = TranslationContext.rootContext(result, bindingContext, declarations, project);
block.addStatement(Translation.translateNamespace(namespace, context));
@@ -77,6 +77,7 @@ public class ReferenceTranslator extends AbstractTranslator {
if (referencedDescriptor == null) {
return null;
}
//TODO: think about the places where we should check for original descriptors
if (!context().isDeclared(referencedDescriptor)) {
return null;
}