js enumerable for ecma5

This commit is contained in:
develar
2012-06-21 14:08:28 +04:00
parent 3e491ba7f1
commit 39fe690ec8
10 changed files with 123 additions and 18 deletions
+3 -1
View File
@@ -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;
@@ -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];
}
}