js enumerable for ecma5
This commit is contained in:
@@ -3,4 +3,6 @@ package js;
|
|||||||
native
|
native
|
||||||
annotation class native(name : String = "") {}
|
annotation class native(name : String = "") {}
|
||||||
native
|
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;
|
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.config.EcmaVersion;
|
||||||
import org.jetbrains.k2js.test.SingleFileTranslationTest;
|
import org.jetbrains.k2js.test.SingleFileTranslationTest;
|
||||||
|
import org.jetbrains.k2js.test.utils.JsTestUtils;
|
||||||
|
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Pavel Talanov
|
* @author Pavel Talanov
|
||||||
@@ -79,4 +83,18 @@ public final class PropertyAccessTest extends SingleFileTranslationTest {
|
|||||||
public void testInitInstanceProperties() throws Exception {
|
public void testInitInstanceProperties() throws Exception {
|
||||||
fooBoxTest(EnumSet.of(EcmaVersion.v5));
|
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.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,6 +35,11 @@ public final class JsTestUtils {
|
|||||||
private JsTestUtils() {
|
private JsTestUtils() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static EnumSet<EcmaVersion> successOnEcmaV5() {
|
||||||
|
return EnumSet.of(EcmaVersion.v5);
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static String convertFileNameToDotJsFile(@NotNull String filename, @NotNull EcmaVersion ecmaVersion) {
|
public static String convertFileNameToDotJsFile(@NotNull String filename, @NotNull EcmaVersion ecmaVersion) {
|
||||||
String postFix = "_" + ecmaVersion.toString() + ".js";
|
String postFix = "_" + ecmaVersion.toString() + ".js";
|
||||||
|
|||||||
@@ -122,6 +122,9 @@ public final class Namer {
|
|||||||
@NotNull
|
@NotNull
|
||||||
private final JsPropertyInitializer writablePropertyDescriptorField;
|
private final JsPropertyInitializer writablePropertyDescriptorField;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private final JsPropertyInitializer enumerablePropertyDescriptorField;
|
||||||
|
|
||||||
private Namer(@NotNull JsScope rootScope) {
|
private Namer(@NotNull JsScope rootScope) {
|
||||||
kotlinName = rootScope.declareName(KOTLIN_OBJECT_NAME);
|
kotlinName = rootScope.declareName(KOTLIN_OBJECT_NAME);
|
||||||
kotlinScope = new JsScope(rootScope, "Kotlin standard object");
|
kotlinScope = new JsScope(rootScope, "Kotlin standard object");
|
||||||
@@ -132,7 +135,9 @@ public final class Namer {
|
|||||||
|
|
||||||
isTypeName = kotlinScope.declareName("isType");
|
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
|
@NotNull
|
||||||
@@ -190,6 +195,11 @@ public final class Namer {
|
|||||||
return writablePropertyDescriptorField;
|
return writablePropertyDescriptorField;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public JsPropertyInitializer enumerablePropertyDescriptorField() {
|
||||||
|
return enumerablePropertyDescriptorField;
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
/*package*/ JsScope getKotlinScope() {
|
/*package*/ JsScope getKotlinScope() {
|
||||||
return kotlinScope;
|
return kotlinScope;
|
||||||
|
|||||||
+2
-3
@@ -71,10 +71,9 @@ public final class DeclarationBodyVisitor extends TranslatorVisitor<List<JsPrope
|
|||||||
@NotNull TranslationContext context) {
|
@NotNull TranslationContext context) {
|
||||||
JsPropertyInitializer methodAsPropertyInitializer = Translation.functionTranslator(expression, context).translateAsMethod();
|
JsPropertyInitializer methodAsPropertyInitializer = Translation.functionTranslator(expression, context).translateAsMethod();
|
||||||
if (context.isEcma5()) {
|
if (context.isEcma5()) {
|
||||||
final FunctionDescriptor descriptor = getFunctionDescriptor(context.bindingContext(), expression);
|
FunctionDescriptor descriptor = getFunctionDescriptor(context.bindingContext(), expression);
|
||||||
boolean overridable = descriptor.getModality().isOverridable();
|
|
||||||
JsExpression methodBodyExpression = methodAsPropertyInitializer.getValueExpr();
|
JsExpression methodBodyExpression = methodAsPropertyInitializer.getValueExpr();
|
||||||
methodAsPropertyInitializer.setValueExpr(JsAstUtils.createPropertyDataDescriptor(overridable, methodBodyExpression, context));
|
methodAsPropertyInitializer.setValueExpr(JsAstUtils.createPropertyDataDescriptor(descriptor, methodBodyExpression, context));
|
||||||
}
|
}
|
||||||
return Collections.singletonList(methodAsPropertyInitializer);
|
return Collections.singletonList(methodAsPropertyInitializer);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package org.jetbrains.k2js.translate.utils;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
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.DeclarationDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||||
@@ -31,6 +32,8 @@ import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getContaining
|
|||||||
*/
|
*/
|
||||||
public final class AnnotationsUtils {
|
public final class AnnotationsUtils {
|
||||||
|
|
||||||
|
private static final String ENUMERABLE = "js.enumerable";
|
||||||
|
|
||||||
private AnnotationsUtils() {
|
private AnnotationsUtils() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,10 +72,14 @@ public final class AnnotationsUtils {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static AnnotationDescriptor getAnnotationByName(@NotNull DeclarationDescriptor descriptor,
|
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()) {
|
for (AnnotationDescriptor annotationDescriptor : descriptor.getAnnotations()) {
|
||||||
String annotationClassFQName = getAnnotationClassFQName(annotationDescriptor);
|
if (getAnnotationClassFQName(annotationDescriptor).equals(fqn)) {
|
||||||
if (annotationClassFQName.equals(annotation.getFQName())) {
|
|
||||||
return annotationDescriptor;
|
return annotationDescriptor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -91,6 +98,16 @@ public final class AnnotationsUtils {
|
|||||||
return hasAnnotationOrInsideAnnotatedClass(descriptor, PredefinedAnnotation.NATIVE);
|
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) {
|
public static boolean isLibraryObject(@NotNull DeclarationDescriptor descriptor) {
|
||||||
return hasAnnotationOrInsideAnnotatedClass(descriptor, PredefinedAnnotation.LIBRARY);
|
return hasAnnotationOrInsideAnnotatedClass(descriptor, PredefinedAnnotation.LIBRARY);
|
||||||
}
|
}
|
||||||
@@ -105,14 +122,15 @@ public final class AnnotationsUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasAnnotationOrInsideAnnotatedClass(@NotNull DeclarationDescriptor descriptor,
|
public static boolean hasAnnotationOrInsideAnnotatedClass(@NotNull DeclarationDescriptor descriptor,
|
||||||
@NotNull PredefinedAnnotation annotation) {
|
@NotNull PredefinedAnnotation annotation) {
|
||||||
if (getAnnotationByName(descriptor, annotation) != null) {
|
return hasAnnotationOrInsideAnnotatedClass(descriptor, annotation.getFQName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hasAnnotationOrInsideAnnotatedClass(@NotNull DeclarationDescriptor descriptor, @NotNull String fqn) {
|
||||||
|
if (getAnnotationByName(descriptor, fqn) != null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
ClassDescriptor containingClass = getContainingClass(descriptor);
|
ClassDescriptor containingClass = getContainingClass(descriptor);
|
||||||
if (containingClass == null) {
|
return containingClass != null && getAnnotationByName(containingClass, fqn) != null;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return (getAnnotationByName(containingClass, annotation) != null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ import com.google.dart.compiler.backend.js.ast.*;
|
|||||||
import com.google.dart.compiler.util.AstUtil;
|
import com.google.dart.compiler.util.AstUtil;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
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.jet.lang.descriptors.PropertyDescriptor;
|
||||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||||
|
|
||||||
@@ -289,11 +291,19 @@ public final class JsAstUtils {
|
|||||||
@NotNull TranslationContext context) {
|
@NotNull TranslationContext context) {
|
||||||
return AstUtil.newInvocation(DEFINE_PROPERTY, new JsThisRef(),
|
return AstUtil.newInvocation(DEFINE_PROPERTY, new JsThisRef(),
|
||||||
context.program().getStringLiteral(context.getNameForDescriptor(descriptor).getIdent()),
|
context.program().getStringLiteral(context.getNameForDescriptor(descriptor).getIdent()),
|
||||||
createPropertyDataDescriptor(descriptor.isVar(), value, context));
|
createPropertyDataDescriptor(descriptor.isVar(), descriptor, value, context));
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@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 JsExpression value,
|
||||||
@NotNull TranslationContext context) {
|
@NotNull TranslationContext context) {
|
||||||
JsObjectLiteral jsPropertyDescriptor = new JsObjectLiteral();
|
JsObjectLiteral jsPropertyDescriptor = new JsObjectLiteral();
|
||||||
@@ -302,6 +312,9 @@ public final class JsAstUtils {
|
|||||||
if (writable) {
|
if (writable) {
|
||||||
meta.add(context.namer().writablePropertyDescriptorField());
|
meta.add(context.namer().writablePropertyDescriptorField());
|
||||||
}
|
}
|
||||||
|
if (AnnotationsUtils.isEnumerable(descriptor)) {
|
||||||
|
meta.add(context.namer().enumerablePropertyDescriptorField());
|
||||||
|
}
|
||||||
return jsPropertyDescriptor;
|
return jsPropertyDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
* @author Pavel Talanov
|
* @author Pavel Talanov
|
||||||
*/
|
*/
|
||||||
public enum PredefinedAnnotation {
|
public enum PredefinedAnnotation {
|
||||||
|
|
||||||
|
|
||||||
LIBRARY("js.library"),
|
LIBRARY("js.library"),
|
||||||
NATIVE("js.native");
|
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