refactor generators to inner classes

This commit is contained in:
Pavel Talanov
2012-02-03 16:38:26 +04:00
parent f285d55d09
commit 3b9a20ba89
4 changed files with 259 additions and 268 deletions
@@ -21,7 +21,7 @@ public abstract class Config {
@NotNull
private static final String PATH_TO_JS_LIB_SRC = getPathToJsLibSrc();
//TODO: provide some generic way to access
//TODO: provide some generic way to get the files of the project
@NotNull
private static final List<String> LIB_FILE_NAMES = Arrays.asList(
PATH_TO_JS_LIB_SRC + "\\core\\annotations.kt",
@@ -3,7 +3,6 @@ package org.jetbrains.k2js.translate.context;
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;
/**
* @author Pavel Talanov
@@ -12,29 +11,25 @@ public final class NamingScope {
@NotNull
public static NamingScope rootScope(@NotNull JsScope rootScope) {
return new NamingScope(rootScope, null);
return new NamingScope(rootScope);
}
@NotNull
private final JsScope scope;
@Nullable
private final NamingScope parent;
private NamingScope(@NotNull JsScope correspondingScope, @Nullable NamingScope parent) {
private NamingScope(@NotNull JsScope correspondingScope) {
this.scope = correspondingScope;
this.parent = parent;
}
@NotNull
public NamingScope innerScope(@NotNull String scopeName) {
JsScope innerJsScope = new JsScope(jsScope(), scopeName);
return new NamingScope(innerJsScope, this);
return new NamingScope(innerJsScope);
}
@NotNull
public NamingScope innerScope(@NotNull JsScope correspondingScope) {
return new NamingScope(correspondingScope, this);
return new NamingScope(correspondingScope);
}
@NotNull
@@ -56,11 +56,11 @@ public class StaticContext {
private final NamingScope rootScope;
@NotNull
private final Generator<JsName> names = nameGenerator();
private final Generator<JsName> names = new NameGenerator();
@NotNull
private final Generator<NamingScope> scopes = scopeGenerator();
private final Generator<NamingScope> scopes = new ScopeGenerator();
@NotNull
private final Generator<JsNameRef> qualifiers = qualifierGenerator();
private final Generator<JsNameRef> qualifiers = new QualifierGenerator();
//TODO: too many parameters in constructor
@@ -112,260 +112,6 @@ public class StaticContext {
return standardClasses;
}
@NotNull
private Generator<JsName> nameGenerator() {
Rule<JsName> aliasOverridesNames = new Rule<JsName>() {
@Override
@Nullable
public JsName apply(@NotNull DeclarationDescriptor data) {
if (aliaser.hasAliasForDeclaration(data)) {
return aliaser.getAliasForDeclaration(data);
}
return null;
}
};
Rule<JsName> namesForStandardClasses = new Rule<JsName>() {
@Override
@Nullable
public JsName apply(@NotNull DeclarationDescriptor data) {
if (!standardClasses.isStandardObject(data)) {
return null;
}
return standardClasses.getStandardObjectName(data);
}
};
Rule<JsName> namespacesShouldBeDefinedInRootScope = new Rule<JsName>() {
@Override
@Nullable
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
if (!(descriptor instanceof NamespaceDescriptor)) {
return null;
}
String nameForNamespace = getNameForNamespace((NamespaceDescriptor) descriptor);
return getRootScope().declareUnobfuscatableName(nameForNamespace);
}
};
Rule<JsName> memberDeclarationsInsideParentsScope = new Rule<JsName>() {
@Override
@Nullable
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
NamingScope namingScope = getEnclosingScope(descriptor);
return namingScope.declareObfuscatableName(descriptor.getName());
}
};
Rule<JsName> constructorHasTheSameNameAsTheClass = new Rule<JsName>() {
@Override
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
if (!(descriptor instanceof ConstructorDescriptor)) {
return null;
}
ClassDescriptor containingClass = getContainingClass(descriptor);
assert containingClass != null : "Can't have constructor without a class";
return getNameForDescriptor(containingClass);
}
};
Rule<JsName> accessorsHasNamesWithSpecialPrefixes = new Rule<JsName>() {
@Override
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
if (!(descriptor instanceof PropertyAccessorDescriptor)) {
return null;
}
boolean isGetter = descriptor instanceof PropertyGetterDescriptor;
String propertyName = ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty().getName();
String accessorName = Namer.getNameForAccessor(propertyName, isGetter);
NamingScope enclosingScope = getEnclosingScope(descriptor);
return enclosingScope.declareObfuscatableName(accessorName);
}
};
Rule<JsName> namesAnnotatedAsLibraryHasUnobfuscatableNames = new Rule<JsName>() {
@Override
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
//TODO: refactor
String name = null;
AnnotationDescriptor annotation = getAnnotationByName(descriptor, LIBRARY_ANNOTATION_FQNAME);
if (annotation != null) {
name = AnnotationsUtils.getAnnotationStringParameter(descriptor, LIBRARY_ANNOTATION_FQNAME);
name = (!name.isEmpty()) ? name : descriptor.getName();
} else {
ClassDescriptor containingClass = getContainingClass(descriptor);
if (containingClass == null) return null;
if (getAnnotationByName(containingClass, LIBRARY_ANNOTATION_FQNAME) != null) {
name = descriptor.getName();
}
}
if (name != null) {
return getEnclosingScope(descriptor).declareUnobfuscatableName(name);
}
return null;
}
};
Rule<JsName> propertiesCorrespondToSpeciallyTreatedBackingFieldNames = new Rule<JsName>() {
@Override
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
if (!(descriptor instanceof PropertyDescriptor)) {
return null;
}
NamingScope enclosingScope = getEnclosingScope(descriptor);
return enclosingScope.declareObfuscatableName(Namer.getKotlinBackingFieldName(descriptor.getName()));
}
};
//TODO: hack!
Rule<JsName> toStringHack = new Rule<JsName>() {
@Override
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
if (!(descriptor instanceof FunctionDescriptor)) {
return null;
}
if (!descriptor.getName().equals("toString")) {
return null;
}
if (((FunctionDescriptor) descriptor).getValueParameters().isEmpty()) {
return getEnclosingScope(descriptor).declareUnobfuscatableName("toString");
}
return null;
}
};
Rule<JsName> namesForNativeObjectsAreUnobfuscatable = new Rule<JsName>() {
@Override
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
String name = null;
AnnotationDescriptor annotation = getAnnotationByName(descriptor, NATIVE_ANNOTATION_FQNAME);
if (annotation != null) {
name = AnnotationsUtils.getAnnotationStringParameter(descriptor, NATIVE_ANNOTATION_FQNAME);
name = (!name.isEmpty()) ? name : descriptor.getName();
} else {
ClassDescriptor containingClass = getContainingClass(descriptor);
if (containingClass == null) return null;
if (getAnnotationByName(containingClass, NATIVE_ANNOTATION_FQNAME) != null) {
name = descriptor.getName();
}
}
if (name != null) {
return getEnclosingScope(descriptor).declareUnobfuscatableName(name);
}
return null;
}
};
Generator<JsName> nameGenerator = new Generator<JsName>();
nameGenerator.addRule(namesForStandardClasses);
nameGenerator.addRule(aliasOverridesNames);
nameGenerator.addRule(constructorHasTheSameNameAsTheClass);
nameGenerator.addRule(namesAnnotatedAsLibraryHasUnobfuscatableNames);
nameGenerator.addRule(namesForNativeObjectsAreUnobfuscatable);
nameGenerator.addRule(toStringHack);
nameGenerator.addRule(propertiesCorrespondToSpeciallyTreatedBackingFieldNames);
nameGenerator.addRule(namespacesShouldBeDefinedInRootScope);
nameGenerator.addRule(accessorsHasNamesWithSpecialPrefixes);
nameGenerator.addRule(memberDeclarationsInsideParentsScope);
return nameGenerator;
}
private NamingScope getEnclosingScope(@NotNull DeclarationDescriptor descriptor) {
DeclarationDescriptor containingDeclaration = getContainingDeclaration(descriptor);
return getScopeForDescriptor(containingDeclaration.getOriginal());
}
@NotNull
private Generator<NamingScope> scopeGenerator() {
Generator<NamingScope> scopeGenerator = new Generator<NamingScope>();
Rule<NamingScope> generateNewScopesForNamespaceDescriptors = new Rule<NamingScope>() {
@Override
public NamingScope apply(@NotNull DeclarationDescriptor descriptor) {
if (!(descriptor instanceof NamespaceDescriptor)) {
return null;
}
return getRootScope().innerScope("Namespace " + descriptor.getName());
}
};
Rule<NamingScope> generateInnerScopesForMembers = new Rule<NamingScope>() {
@Override
public NamingScope apply(@NotNull DeclarationDescriptor descriptor) {
NamingScope enclosingScope = getEnclosingScope(descriptor);
return enclosingScope.innerScope("scope for member " + descriptor.getName());
}
};
scopeGenerator.addRule(generateNewScopesForNamespaceDescriptors);
scopeGenerator.addRule(generateInnerScopesForMembers);
return scopeGenerator;
}
@NotNull
private Generator<JsNameRef> qualifierGenerator() {
Rule<JsNameRef> namespacesHaveNoQualifiers = new Rule<JsNameRef>() {
@Override
public JsNameRef apply(@NotNull DeclarationDescriptor descriptor) {
if (!standardClasses.isStandardObject(descriptor)) {
return null;
}
return namer.kotlinObject();
}
};
Rule<JsNameRef> namespaceLevelDeclarationsHaveEnclosingNamespacesNamesAsQualifier = new Rule<JsNameRef>() {
@Override
public JsNameRef apply(@NotNull DeclarationDescriptor descriptor) {
DeclarationDescriptor containingDeclaration = getContainingDeclaration(descriptor);
if (!(containingDeclaration instanceof NamespaceDescriptor)) {
return null;
}
JsName containingDeclarationName = getNameForDescriptor(containingDeclaration);
return containingDeclarationName.makeRef();
}
};
Rule<JsNameRef> constructorHaveTheSameQualifierAsTheClass = new Rule<JsNameRef>() {
@Override
public JsNameRef apply(@NotNull DeclarationDescriptor descriptor) {
if (!(descriptor instanceof ConstructorDescriptor)) {
return null;
}
ClassDescriptor containingClass = getContainingClass(descriptor);
assert containingClass != null : "Can't have constructor without a class";
return getQualifierForDescriptor(containingClass);
}
};
Rule<JsNameRef> libraryObjectsHaveKotlinQualifier = new Rule<JsNameRef>() {
//TODO: refactor by removing one annotation
@Override
public JsNameRef apply(@NotNull DeclarationDescriptor descriptor) {
if (getAnnotationByName(descriptor, AnnotationsUtils.LIBRARY_ANNOTATION_FQNAME) != null) {
return namer.kotlinObject();
}
if (getAnnotationByName(descriptor, AnnotationsUtils.LIBRARY_ANNOTATION_FQNAME) != null) {
return namer.kotlinObject();
}
return null;
}
};
Rule<JsNameRef> membersOfAnnotatedClassesHaveKotlinQualifier = new Rule<JsNameRef>() {
@Override
public JsNameRef apply(@NotNull DeclarationDescriptor descriptor) {
ClassDescriptor containingClass = getContainingClass(descriptor);
if (containingClass == null) {
return null;
}
if (getAnnotationByName(descriptor, LIBRARY_ANNOTATION_FQNAME) != null) {
return namer.kotlinObject();
}
return null;
}
};
Generator<JsNameRef> qualifierGenerator = new Generator<JsNameRef>();
qualifierGenerator.addRule(libraryObjectsHaveKotlinQualifier);
qualifierGenerator.addRule(membersOfAnnotatedClassesHaveKotlinQualifier);
qualifierGenerator.addRule(constructorHaveTheSameQualifierAsTheClass);
qualifierGenerator.addRule(namespacesHaveNoQualifiers);
qualifierGenerator.addRule(namespaceLevelDeclarationsHaveEnclosingNamespacesNamesAsQualifier);
return qualifierGenerator;
}
@NotNull
public NamingScope getScopeForDescriptor(@NotNull DeclarationDescriptor descriptor) {
NamingScope namingScope = scopes.get(descriptor);
@@ -390,4 +136,254 @@ public class StaticContext {
return name;
}
private class NameGenerator extends Generator<JsName> {
public NameGenerator() {
Rule<JsName> aliasOverridesNames = new Rule<JsName>() {
@Override
@Nullable
public JsName apply(@NotNull DeclarationDescriptor data) {
if (aliaser.hasAliasForDeclaration(data)) {
return aliaser.getAliasForDeclaration(data);
}
return null;
}
};
Rule<JsName> namesForStandardClasses = new Rule<JsName>() {
@Override
@Nullable
public JsName apply(@NotNull DeclarationDescriptor data) {
if (!standardClasses.isStandardObject(data)) {
return null;
}
return standardClasses.getStandardObjectName(data);
}
};
Rule<JsName> namespacesShouldBeDefinedInRootScope = new Rule<JsName>() {
@Override
@Nullable
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
if (!(descriptor instanceof NamespaceDescriptor)) {
return null;
}
String nameForNamespace = getNameForNamespace((NamespaceDescriptor) descriptor);
return getRootScope().declareUnobfuscatableName(nameForNamespace);
}
};
Rule<JsName> memberDeclarationsInsideParentsScope = new Rule<JsName>() {
@Override
@Nullable
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
NamingScope namingScope = getEnclosingScope(descriptor);
return namingScope.declareObfuscatableName(descriptor.getName());
}
};
Rule<JsName> constructorHasTheSameNameAsTheClass = new Rule<JsName>() {
@Override
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
if (!(descriptor instanceof ConstructorDescriptor)) {
return null;
}
ClassDescriptor containingClass = getContainingClass(descriptor);
assert containingClass != null : "Can't have constructor without a class";
return getNameForDescriptor(containingClass);
}
};
Rule<JsName> accessorsHasNamesWithSpecialPrefixes = new Rule<JsName>() {
@Override
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
if (!(descriptor instanceof PropertyAccessorDescriptor)) {
return null;
}
boolean isGetter = descriptor instanceof PropertyGetterDescriptor;
String propertyName = ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty().getName();
String accessorName = Namer.getNameForAccessor(propertyName, isGetter);
NamingScope enclosingScope = getEnclosingScope(descriptor);
return enclosingScope.declareObfuscatableName(accessorName);
}
};
Rule<JsName> namesAnnotatedAsLibraryHasUnobfuscatableNames = new Rule<JsName>() {
@Override
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
//TODO: refactor
String name = null;
AnnotationDescriptor annotation = getAnnotationByName(descriptor, LIBRARY_ANNOTATION_FQNAME);
if (annotation != null) {
name = AnnotationsUtils.getAnnotationStringParameter(descriptor, LIBRARY_ANNOTATION_FQNAME);
name = (!name.isEmpty()) ? name : descriptor.getName();
} else {
ClassDescriptor containingClass = getContainingClass(descriptor);
if (containingClass == null) return null;
if (getAnnotationByName(containingClass, LIBRARY_ANNOTATION_FQNAME) != null) {
name = descriptor.getName();
}
}
if (name != null) {
return getEnclosingScope(descriptor).declareUnobfuscatableName(name);
}
return null;
}
};
Rule<JsName> propertiesCorrespondToSpeciallyTreatedBackingFieldNames = new Rule<JsName>() {
@Override
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
if (!(descriptor instanceof PropertyDescriptor)) {
return null;
}
NamingScope enclosingScope = getEnclosingScope(descriptor);
return enclosingScope.declareObfuscatableName(Namer.getKotlinBackingFieldName(descriptor.getName()));
}
};
//TODO: hack!
Rule<JsName> toStringHack = new Rule<JsName>() {
@Override
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
if (!(descriptor instanceof FunctionDescriptor)) {
return null;
}
if (!descriptor.getName().equals("toString")) {
return null;
}
if (((FunctionDescriptor) descriptor).getValueParameters().isEmpty()) {
return getEnclosingScope(descriptor).declareUnobfuscatableName("toString");
}
return null;
}
};
Rule<JsName> namesForNativeObjectsAreUnobfuscatable = new Rule<JsName>() {
@Override
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
String name = null;
AnnotationDescriptor annotation = getAnnotationByName(descriptor, NATIVE_ANNOTATION_FQNAME);
if (annotation != null) {
name = AnnotationsUtils.getAnnotationStringParameter(descriptor, NATIVE_ANNOTATION_FQNAME);
name = (!name.isEmpty()) ? name : descriptor.getName();
} else {
ClassDescriptor containingClass = getContainingClass(descriptor);
if (containingClass == null) return null;
if (getAnnotationByName(containingClass, NATIVE_ANNOTATION_FQNAME) != null) {
name = descriptor.getName();
}
}
if (name != null) {
return getEnclosingScope(descriptor).declareUnobfuscatableName(name);
}
return null;
}
};
addRule(namesForStandardClasses);
addRule(aliasOverridesNames);
addRule(constructorHasTheSameNameAsTheClass);
addRule(namesAnnotatedAsLibraryHasUnobfuscatableNames);
addRule(namesForNativeObjectsAreUnobfuscatable);
addRule(toStringHack);
addRule(propertiesCorrespondToSpeciallyTreatedBackingFieldNames);
addRule(namespacesShouldBeDefinedInRootScope);
addRule(accessorsHasNamesWithSpecialPrefixes);
addRule(memberDeclarationsInsideParentsScope);
}
}
private NamingScope getEnclosingScope(@NotNull DeclarationDescriptor descriptor) {
DeclarationDescriptor containingDeclaration = getContainingDeclaration(descriptor);
return getScopeForDescriptor(containingDeclaration.getOriginal());
}
private class ScopeGenerator extends Generator<NamingScope> {
public ScopeGenerator() {
Rule<NamingScope> generateNewScopesForNamespaceDescriptors = new Rule<NamingScope>() {
@Override
public NamingScope apply(@NotNull DeclarationDescriptor descriptor) {
if (!(descriptor instanceof NamespaceDescriptor)) {
return null;
}
return getRootScope().innerScope("Namespace " + descriptor.getName());
}
};
Rule<NamingScope> generateInnerScopesForMembers = new Rule<NamingScope>() {
@Override
public NamingScope apply(@NotNull DeclarationDescriptor descriptor) {
NamingScope enclosingScope = getEnclosingScope(descriptor);
return enclosingScope.innerScope("scope for member " + descriptor.getName());
}
};
addRule(generateNewScopesForNamespaceDescriptors);
addRule(generateInnerScopesForMembers);
}
}
private class QualifierGenerator extends Generator<JsNameRef> {
public QualifierGenerator() {
Rule<JsNameRef> namespacesHaveNoQualifiers = new Rule<JsNameRef>() {
@Override
public JsNameRef apply(@NotNull DeclarationDescriptor descriptor) {
if (!standardClasses.isStandardObject(descriptor)) {
return null;
}
return namer.kotlinObject();
}
};
Rule<JsNameRef> namespaceLevelDeclarationsHaveEnclosingNamespacesNamesAsQualifier = new Rule<JsNameRef>() {
@Override
public JsNameRef apply(@NotNull DeclarationDescriptor descriptor) {
DeclarationDescriptor containingDeclaration = getContainingDeclaration(descriptor);
if (!(containingDeclaration instanceof NamespaceDescriptor)) {
return null;
}
JsName containingDeclarationName = getNameForDescriptor(containingDeclaration);
return containingDeclarationName.makeRef();
}
};
Rule<JsNameRef> constructorHaveTheSameQualifierAsTheClass = new Rule<JsNameRef>() {
@Override
public JsNameRef apply(@NotNull DeclarationDescriptor descriptor) {
if (!(descriptor instanceof ConstructorDescriptor)) {
return null;
}
ClassDescriptor containingClass = getContainingClass(descriptor);
assert containingClass != null : "Can't have constructor without a class";
return getQualifierForDescriptor(containingClass);
}
};
Rule<JsNameRef> libraryObjectsHaveKotlinQualifier = new Rule<JsNameRef>() {
//TODO: refactor by removing one annotation
@Override
public JsNameRef apply(@NotNull DeclarationDescriptor descriptor) {
if (getAnnotationByName(descriptor, AnnotationsUtils.LIBRARY_ANNOTATION_FQNAME) != null) {
return namer.kotlinObject();
}
if (getAnnotationByName(descriptor, AnnotationsUtils.LIBRARY_ANNOTATION_FQNAME) != null) {
return namer.kotlinObject();
}
return null;
}
};
Rule<JsNameRef> membersOfAnnotatedClassesHaveKotlinQualifier = new Rule<JsNameRef>() {
@Override
public JsNameRef apply(@NotNull DeclarationDescriptor descriptor) {
ClassDescriptor containingClass = getContainingClass(descriptor);
if (containingClass == null) {
return null;
}
if (getAnnotationByName(descriptor, LIBRARY_ANNOTATION_FQNAME) != null) {
return namer.kotlinObject();
}
return null;
}
};
addRule(libraryObjectsHaveKotlinQualifier);
addRule(membersOfAnnotatedClassesHaveKotlinQualifier);
addRule(constructorHaveTheSameQualifierAsTheClass);
addRule(namespacesHaveNoQualifiers);
addRule(namespaceLevelDeclarationsHaveEnclosingNamespacesNamesAsQualifier);
}
}
}
@@ -12,7 +12,7 @@ import java.util.Map;
/**
* @author Pavel Talanov
*/
public final class Generator<V> {
public class Generator<V> {
@NotNull