JS: update support of enum's values() and valueOf()

This commit is contained in:
Alexander Udalov
2014-09-05 18:55:23 +04:00
parent c5345a83c9
commit d52eff0825
10 changed files with 111 additions and 94 deletions
@@ -19,13 +19,10 @@ package org.jetbrains.k2js.translate.context;
import com.google.dart.compiler.backend.js.ast.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassKind;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.plugin.JetLanguage;
import static org.jetbrains.jet.lang.descriptors.ClassKind.TRAIT;
/**
* Encapuslates different types of constants and naming conventions.
*/
@@ -40,9 +37,9 @@ public final class Namer {
private static final String APPLY_FUNCTION = "apply";
private static final String CLASS_OBJECT_NAME = "createClass";
private static final String ENUM_CLASS_OBJECT_NAME = "createEnumClass";
private static final String TRAIT_OBJECT_NAME = "createTrait";
private static final String OBJECT_OBJECT_NAME = "createObject";
private static final String ENUM_ENTRIES_NAME = "createEnumEntries";
private static final String CALLABLE_REF_FOR_MEMBER_FUNCTION_NAME = "getCallableRefForMemberFunction";
private static final String CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME = "getCallableRefForExtensionFunction";
private static final String CALLABLE_REF_FOR_CONSTRUCTOR_NAME = "getCallableRefForConstructor";
@@ -178,6 +175,8 @@ public final class Namer {
@NotNull
private final JsName className;
@NotNull
private final JsName enumClassName;
@NotNull
private final JsName traitName;
@NotNull
private final JsExpression definePackage;
@@ -186,8 +185,6 @@ public final class Namer {
@NotNull
private final JsName objectName;
@NotNull
private final JsName enumEntriesName;
@NotNull
private final JsName callableRefForMemberFunctionName;
@NotNull
private final JsName callableRefForExtensionFunctionName;
@@ -221,7 +218,7 @@ public final class Namer {
callSetProperty = kotlin("callSetter");
className = kotlinScope.declareName(CLASS_OBJECT_NAME);
enumEntriesName = kotlinScope.declareName(ENUM_ENTRIES_NAME);
enumClassName = kotlinScope.declareName(ENUM_CLASS_OBJECT_NAME);
objectName = kotlinScope.declareName(OBJECT_OBJECT_NAME);
callableRefForMemberFunctionName = kotlinScope.declareName(CALLABLE_REF_FOR_MEMBER_FUNCTION_NAME);
callableRefForExtensionFunctionName = kotlinScope.declareName(CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME);
@@ -241,8 +238,8 @@ public final class Namer {
}
@NotNull
public JsExpression enumEntriesCreationMethodReference() {
return kotlin(enumEntriesName);
public JsExpression enumClassCreationMethodReference() {
return kotlin(enumClassName);
}
@NotNull
@@ -321,7 +318,7 @@ public final class Namer {
}
@NotNull
/*package*/ JsScope getKotlinScope() {
/*package*/ JsScope getKotlinScope() {
return kotlinScope;
}
@@ -332,21 +329,24 @@ public final class Namer {
@NotNull
public JsExpression classCreateInvocation(@NotNull ClassDescriptor descriptor) {
ClassKind kind = descriptor.getKind();
if (kind == TRAIT) {
return traitCreationMethodReference();
switch (descriptor.getKind()) {
case TRAIT:
return traitCreationMethodReference();
case ENUM_CLASS:
return enumClassCreationMethodReference();
case ENUM_ENTRY:
case OBJECT:
case CLASS_OBJECT:
return objectCreationMethodReference();
case ANNOTATION_CLASS:
throw new IllegalStateException("Can't create annotation class instance: " + descriptor);
case CLASS:
return DescriptorUtils.isAnonymousObject(descriptor)
? objectCreationMethodReference()
: classCreationMethodReference();
default:
throw new UnsupportedOperationException("Unsupported class kind: " + descriptor);
}
if (kind.isSingleton() || DescriptorUtils.isAnonymousObject(descriptor)) {
return objectCreationMethodReference();
}
return classCreationMethodReference();
}
@NotNull
public JsInvocation enumEntriesObjectCreateInvocation() {
return new JsInvocation(enumEntriesCreationMethodReference());
}
@NotNull
@@ -37,7 +37,6 @@ import org.jetbrains.k2js.translate.utils.JsAstUtils;
import java.util.Map;
import static org.jetbrains.jet.lang.descriptors.ClassKind.CLASS_OBJECT;
import static org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils.descriptorToDeclaration;
import static org.jetbrains.k2js.translate.utils.AnnotationsUtils.*;
import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.*;
@@ -502,12 +501,26 @@ public final class StaticContext {
return null;
}
};
Rule<JsNameRef> staticMembersHaveContainerQualifier = new Rule<JsNameRef>() {
@Override
public JsNameRef apply(@NotNull DeclarationDescriptor descriptor) {
if (descriptor instanceof CallableDescriptor && !isNativeObject(descriptor)) {
CallableDescriptor callableDescriptor = (CallableDescriptor) descriptor;
if (DescriptorUtils.isStaticDeclaration(callableDescriptor)) {
return getQualifiedReference(callableDescriptor.getContainingDeclaration());
}
}
return null;
}
};
addRule(libraryObjectsHaveKotlinQualifier);
addRule(constructorOrClassObjectHasTheSameQualifierAsTheClass);
addRule(standardObjectsHaveKotlinQualifier);
addRule(packageLevelDeclarationsHaveEnclosingPackagesNamesAsQualifier);
addRule(nativeObjectsHaveNativePartOfFullQualifier);
addRule(staticMembersHaveContainerQualifier);
}
}
@@ -42,11 +42,9 @@ import java.util.*;
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*;
import static org.jetbrains.jet.lang.types.TypeUtils.topologicallySortSuperclassesAndRecordAllInstances;
import static org.jetbrains.k2js.translate.initializer.InitializerUtils.createClassObjectInitializer;
import static org.jetbrains.k2js.translate.reference.ReferenceTranslator.translateAsFQReference;
import static org.jetbrains.k2js.translate.utils.BindingUtils.getClassDescriptor;
import static org.jetbrains.k2js.translate.utils.BindingUtils.getPropertyDescriptorForConstructorParameter;
import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getContainingClass;
import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.*;
import static org.jetbrains.k2js.translate.utils.PsiUtils.getPrimaryConstructorParameters;
import static org.jetbrains.k2js.translate.utils.TranslationUtils.simpleReturnFunction;
@@ -135,12 +133,17 @@ public final class ClassTranslator extends AbstractTranslator {
DeclarationBodyVisitor bodyVisitor = new DeclarationBodyVisitor(properties, staticProperties);
bodyVisitor.traverseContainer(classDeclaration, declarationContext);
delegationTranslator.generateDelegated(properties);
mayBeAddEnumEntry(bodyVisitor.getEnumEntryList(), staticProperties, declarationContext);
if (KotlinBuiltIns.getInstance().isData(descriptor)) {
new JsDataClassGenerator(classDeclaration, declarationContext, properties).generate();
}
if (isEnumClass(descriptor)) {
JsObjectLiteral enumEntries = new JsObjectLiteral(bodyVisitor.getEnumEntryList(), true);
JsFunction function = simpleReturnFunction(declarationContext.getScopeForDescriptor(descriptor), enumEntries);
invocationArguments.add(function);
}
boolean hasStaticProperties = !staticProperties.isEmpty();
if (!properties.isEmpty() || hasStaticProperties) {
if (properties.isEmpty()) {
@@ -158,6 +161,7 @@ public final class ClassTranslator extends AbstractTranslator {
invocationArguments.add(new JsDocComment(JsAstUtils.LENDS_JS_DOC_TAG, qualifiedReference));
invocationArguments.add(new JsObjectLiteral(staticProperties, true));
}
return invocationArguments;
}
@@ -181,21 +185,6 @@ public final class ClassTranslator extends AbstractTranslator {
return declarationContext;
}
private void mayBeAddEnumEntry(@NotNull List<JsPropertyInitializer> enumEntryList,
@NotNull List<JsPropertyInitializer> staticProperties,
@NotNull TranslationContext declarationContext
) {
if (descriptor.getKind() == ClassKind.ENUM_CLASS) {
JsInvocation invocation = context().namer().enumEntriesObjectCreateInvocation();
invocation.getArguments().add(new JsObjectLiteral(enumEntryList, true));
JsFunction fun = simpleReturnFunction(declarationContext.getScopeForDescriptor(descriptor), invocation);
staticProperties.add(createClassObjectInitializer(fun, declarationContext));
} else {
assert enumEntryList.isEmpty(): "Only enum class may have enum entry. Class kind is: " + descriptor.getKind();
}
}
private JsExpression getSuperclassReferences(@NotNull TranslationContext declarationContext) {
List<JsExpression> superClassReferences = getSupertypesNameReferences();
if (superClassReferences.isEmpty()) {
@@ -22,10 +22,10 @@ import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.backend.common.CodegenUtil;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.OverrideResolver;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
@@ -41,7 +41,8 @@ import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getFqName;
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isAnonymousObject;
import static org.jetbrains.k2js.translate.context.Namer.getKotlinBackingFieldName;
import static org.jetbrains.k2js.translate.utils.BindingUtils.getCallableDescriptorForOperationExpression;
import static org.jetbrains.k2js.translate.utils.JsAstUtils.*;
import static org.jetbrains.k2js.translate.utils.JsAstUtils.assignment;
import static org.jetbrains.k2js.translate.utils.JsAstUtils.createDataDescriptor;
public final class TranslationUtils {
public static final Comparator<FunctionDescriptor> OVERLOADED_FUNCTION_COMPARATOR = new OverloadedFunctionComparator();
@@ -177,11 +178,16 @@ public final class TranslationUtils {
else if (containingDeclaration instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
// Use stable mangling when it inside a overridable declaration for avoid clashing names when inheritance.
// Use stable mangling when it's inside an overridable declaration to avoid clashing names on inheritance.
if (classDescriptor.getModality().isOverridable()) {
return true;
}
// valueOf() is created in the library with a mangled name for every enum class
if (CodegenUtil.isEnumValueOfMethod(descriptor)) {
return true;
}
// Don't use stable mangling when it inside a non-public API declaration.
if (!classDescriptor.getVisibility().isPublicAPI()) {
return false;
+1 -27
View File
@@ -231,34 +231,8 @@
toString: function () {
return this.name();
}
});
(function () {
function valueOf(name) {
return this[name];
}
function getValues() {
return this.values$;
}
Kotlin.createEnumEntries = function (enumEntryList) {
var i = 0;
var values = [];
for (var entryName in enumEntryList) {
if (enumEntryList.hasOwnProperty(entryName)) {
var entryObject = enumEntryList[entryName];
values[i] = entryObject;
entryObject.ordinal$ = i;
entryObject.name$ = entryName;
i++;
}
}
enumEntryList.values$ = values;
enumEntryList.valueOf_61zpoe$ = valueOf;
enumEntryList.values = getValues;
return enumEntryList;
};
})();
);
Kotlin.PropertyMetadata = Kotlin.createClassNow(null,
function (name) {
@@ -222,6 +222,41 @@ var Kotlin = {};
return $o;
};
/**
* @param {(function():Array.<*>)|null} basesFun
* @param {?=} constructor
* @param {function():Object} enumEntries
* @param {Object=} properties
* @returns {*}
*/
Kotlin.createEnumClass = function (basesFun, constructor, enumEntries, properties) {
return Kotlin.createClass(
basesFun, constructor, properties, {
object_initializer$: function () {
var enumEntryList = enumEntries()
var i = 0;
var values = [];
for (var entryName in enumEntryList) {
if (enumEntryList.hasOwnProperty(entryName)) {
var entryObject = enumEntryList[entryName];
values[i] = entryObject;
entryObject.ordinal$ = i;
entryObject.name$ = entryName;
i++;
}
}
enumEntryList.values$ = values;
return enumEntryList;
},
values: function() {
return this.object.values$;
},
valueOf_61zpoe$: function(name) {
return this.object[name];
}
})
};
/**
* @param {(function():Array.<*>)|null} basesFun
* @param {Object=} properties