js enumerable for ecma5
This commit is contained in:
@@ -3,4 +3,6 @@ package js;
|
||||
native
|
||||
annotation class native(name : String = "") {}
|
||||
native
|
||||
annotation class library(name : String = "") {}
|
||||
annotation class library(name : String = "") {}
|
||||
native
|
||||
annotation class enumerable() {}
|
||||
@@ -16,10 +16,14 @@
|
||||
|
||||
package org.jetbrains.k2js.test.semantics;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.k2js.config.EcmaVersion;
|
||||
import org.jetbrains.k2js.test.SingleFileTranslationTest;
|
||||
import org.jetbrains.k2js.test.utils.JsTestUtils;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
@@ -79,4 +83,18 @@ public final class PropertyAccessTest extends SingleFileTranslationTest {
|
||||
public void testInitInstanceProperties() throws Exception {
|
||||
fooBoxTest(EnumSet.of(EcmaVersion.v5));
|
||||
}
|
||||
|
||||
public void testEnumerable() throws Exception {
|
||||
fooBoxTest(JsTestUtils.successOnEcmaV5());
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected List<String> additionalJSFiles(@NotNull EcmaVersion ecmaVersion) {
|
||||
List<String> result = Lists.newArrayList(super.additionalJSFiles(ecmaVersion));
|
||||
if (getName().equals("testEnumerable")) {
|
||||
result.add(pathToTestFiles() + "enumerate.js");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -34,6 +35,11 @@ public final class JsTestUtils {
|
||||
private JsTestUtils() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static EnumSet<EcmaVersion> successOnEcmaV5() {
|
||||
return EnumSet.of(EcmaVersion.v5);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String convertFileNameToDotJsFile(@NotNull String filename, @NotNull EcmaVersion ecmaVersion) {
|
||||
String postFix = "_" + ecmaVersion.toString() + ".js";
|
||||
|
||||
@@ -122,6 +122,9 @@ public final class Namer {
|
||||
@NotNull
|
||||
private final JsPropertyInitializer writablePropertyDescriptorField;
|
||||
|
||||
@NotNull
|
||||
private final JsPropertyInitializer enumerablePropertyDescriptorField;
|
||||
|
||||
private Namer(@NotNull JsScope rootScope) {
|
||||
kotlinName = rootScope.declareName(KOTLIN_OBJECT_NAME);
|
||||
kotlinScope = new JsScope(rootScope, "Kotlin standard object");
|
||||
@@ -132,7 +135,9 @@ public final class Namer {
|
||||
|
||||
isTypeName = kotlinScope.declareName("isType");
|
||||
|
||||
writablePropertyDescriptorField = new JsPropertyInitializer(new JsNameRef("writable"), rootScope.getProgram().getTrueLiteral());
|
||||
JsProgram program = rootScope.getProgram();
|
||||
writablePropertyDescriptorField = new JsPropertyInitializer(program.getStringLiteral("writable"), program.getTrueLiteral());
|
||||
enumerablePropertyDescriptorField = new JsPropertyInitializer(program.getStringLiteral("enumerable"), program.getTrueLiteral());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -190,6 +195,11 @@ public final class Namer {
|
||||
return writablePropertyDescriptorField;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsPropertyInitializer enumerablePropertyDescriptorField() {
|
||||
return enumerablePropertyDescriptorField;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
/*package*/ JsScope getKotlinScope() {
|
||||
return kotlinScope;
|
||||
|
||||
+2
-3
@@ -71,10 +71,9 @@ public final class DeclarationBodyVisitor extends TranslatorVisitor<List<JsPrope
|
||||
@NotNull TranslationContext context) {
|
||||
JsPropertyInitializer methodAsPropertyInitializer = Translation.functionTranslator(expression, context).translateAsMethod();
|
||||
if (context.isEcma5()) {
|
||||
final FunctionDescriptor descriptor = getFunctionDescriptor(context.bindingContext(), expression);
|
||||
boolean overridable = descriptor.getModality().isOverridable();
|
||||
FunctionDescriptor descriptor = getFunctionDescriptor(context.bindingContext(), expression);
|
||||
JsExpression methodBodyExpression = methodAsPropertyInitializer.getValueExpr();
|
||||
methodAsPropertyInitializer.setValueExpr(JsAstUtils.createPropertyDataDescriptor(overridable, methodBodyExpression, context));
|
||||
methodAsPropertyInitializer.setValueExpr(JsAstUtils.createPropertyDataDescriptor(descriptor, methodBodyExpression, context));
|
||||
}
|
||||
return Collections.singletonList(methodAsPropertyInitializer);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jetbrains.k2js.translate.utils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassKind;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
@@ -31,6 +32,8 @@ import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getContaining
|
||||
*/
|
||||
public final class AnnotationsUtils {
|
||||
|
||||
private static final String ENUMERABLE = "js.enumerable";
|
||||
|
||||
private AnnotationsUtils() {
|
||||
}
|
||||
|
||||
@@ -69,10 +72,14 @@ public final class AnnotationsUtils {
|
||||
|
||||
@Nullable
|
||||
private static AnnotationDescriptor getAnnotationByName(@NotNull DeclarationDescriptor descriptor,
|
||||
@NotNull PredefinedAnnotation annotation) {
|
||||
@NotNull PredefinedAnnotation annotation) {
|
||||
return getAnnotationByName(descriptor, annotation.getFQName());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static AnnotationDescriptor getAnnotationByName(@NotNull DeclarationDescriptor descriptor, @NotNull String fqn) {
|
||||
for (AnnotationDescriptor annotationDescriptor : descriptor.getAnnotations()) {
|
||||
String annotationClassFQName = getAnnotationClassFQName(annotationDescriptor);
|
||||
if (annotationClassFQName.equals(annotation.getFQName())) {
|
||||
if (getAnnotationClassFQName(annotationDescriptor).equals(fqn)) {
|
||||
return annotationDescriptor;
|
||||
}
|
||||
}
|
||||
@@ -91,6 +98,16 @@ public final class AnnotationsUtils {
|
||||
return hasAnnotationOrInsideAnnotatedClass(descriptor, PredefinedAnnotation.NATIVE);
|
||||
}
|
||||
|
||||
public static boolean isEnumerable(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (getAnnotationByName(descriptor, ENUMERABLE) != null) {
|
||||
return true;
|
||||
}
|
||||
ClassDescriptor containingClass = getContainingClass(descriptor);
|
||||
return containingClass != null &&
|
||||
(getAnnotationByName(containingClass, ENUMERABLE) != null ||
|
||||
(containingClass.getKind().equals(ClassKind.OBJECT) && containingClass.getName().isSpecial()));
|
||||
}
|
||||
|
||||
public static boolean isLibraryObject(@NotNull DeclarationDescriptor descriptor) {
|
||||
return hasAnnotationOrInsideAnnotatedClass(descriptor, PredefinedAnnotation.LIBRARY);
|
||||
}
|
||||
@@ -105,14 +122,15 @@ public final class AnnotationsUtils {
|
||||
}
|
||||
|
||||
public static boolean hasAnnotationOrInsideAnnotatedClass(@NotNull DeclarationDescriptor descriptor,
|
||||
@NotNull PredefinedAnnotation annotation) {
|
||||
if (getAnnotationByName(descriptor, annotation) != null) {
|
||||
@NotNull PredefinedAnnotation annotation) {
|
||||
return hasAnnotationOrInsideAnnotatedClass(descriptor, annotation.getFQName());
|
||||
}
|
||||
|
||||
private static boolean hasAnnotationOrInsideAnnotatedClass(@NotNull DeclarationDescriptor descriptor, @NotNull String fqn) {
|
||||
if (getAnnotationByName(descriptor, fqn) != null) {
|
||||
return true;
|
||||
}
|
||||
ClassDescriptor containingClass = getContainingClass(descriptor);
|
||||
if (containingClass == null) {
|
||||
return false;
|
||||
}
|
||||
return (getAnnotationByName(containingClass, annotation) != null);
|
||||
return containingClass != null && getAnnotationByName(containingClass, fqn) != null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ 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.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
|
||||
@@ -289,11 +291,19 @@ public final class JsAstUtils {
|
||||
@NotNull TranslationContext context) {
|
||||
return AstUtil.newInvocation(DEFINE_PROPERTY, new JsThisRef(),
|
||||
context.program().getStringLiteral(context.getNameForDescriptor(descriptor).getIdent()),
|
||||
createPropertyDataDescriptor(descriptor.isVar(), value, context));
|
||||
createPropertyDataDescriptor(descriptor.isVar(), descriptor, value, context));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsObjectLiteral createPropertyDataDescriptor(boolean writable,
|
||||
public static JsObjectLiteral createPropertyDataDescriptor(@NotNull FunctionDescriptor descriptor,
|
||||
@NotNull JsExpression value,
|
||||
@NotNull TranslationContext context) {
|
||||
return createPropertyDataDescriptor(descriptor.getModality().isOverridable(), descriptor, value, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static JsObjectLiteral createPropertyDataDescriptor(boolean writable,
|
||||
@NotNull DeclarationDescriptor descriptor,
|
||||
@NotNull JsExpression value,
|
||||
@NotNull TranslationContext context) {
|
||||
JsObjectLiteral jsPropertyDescriptor = new JsObjectLiteral();
|
||||
@@ -302,6 +312,9 @@ public final class JsAstUtils {
|
||||
if (writable) {
|
||||
meta.add(context.namer().writablePropertyDescriptorField());
|
||||
}
|
||||
if (AnnotationsUtils.isEnumerable(descriptor)) {
|
||||
meta.add(context.namer().enumerablePropertyDescriptorField());
|
||||
}
|
||||
return jsPropertyDescriptor;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,8 +22,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public enum PredefinedAnnotation {
|
||||
|
||||
|
||||
LIBRARY("js.library"),
|
||||
NATIVE("js.native");
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package foo
|
||||
|
||||
import js.enumerable
|
||||
import js.native
|
||||
|
||||
native
|
||||
fun <T> _enumerate(o:T):T = noImpl
|
||||
|
||||
native
|
||||
fun _findFirst<T>(o:Any):T = noImpl
|
||||
|
||||
enumerable
|
||||
class Test() {
|
||||
val a:Int = 100
|
||||
val b:String = "s"
|
||||
}
|
||||
|
||||
class P() {
|
||||
enumerable
|
||||
val a:Int = 100
|
||||
val b:String = "s"
|
||||
}
|
||||
|
||||
fun box():Boolean {
|
||||
val test = _enumerate(Test())
|
||||
val p = _enumerate(P())
|
||||
return (100 == test.a && "s" == test.b) && p.a == 100 && _findFirst<Int>(object {val test = 100}) == 100;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
function _enumerate(o) {
|
||||
var r = {};
|
||||
for (var p in o) {
|
||||
r[p] = o[p];
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
function _findFirst(o) {
|
||||
for (var p in o) {
|
||||
return o[p];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user