From 85a57b3cf9d43ce7b0d538195ee252a812b97089 Mon Sep 17 00:00:00 2001 From: Pavel Talanov Date: Wed, 1 Feb 2012 22:09:50 +0400 Subject: [PATCH] lots of api tweaks in jslib some kotlin_lib functions added support for native properties added simple api for Canvas2D --- jslib/src/core/annotations.kt | 5 +- jslib/src/core/core.kt | 21 ++- jslib/src/core/json.kt | 10 +- jslib/src/jquery/common.kt | 14 +- jslib/src/raphael/raphael.kt | 50 +++++-- .../src/org/jetbrains/k2js/config/Config.java | 3 +- .../translate/context/TranslationContext.java | 3 +- .../AnnotatedDeclarationVisitor.java | 51 +++---- .../context/declaration/AnnotationsUtils.java | 21 ++- .../declaration/NativeDeclarationVisitor.java | 5 +- .../reference/ArrayAccessTranslator.java | 5 +- .../KotlinPropertyAccessTranslator.java | 83 ++++++++++++ .../NativePropertyAccessTranslator.java | 66 +++++++++ .../reference/PropertyAccessTranslator.java | 126 ++++++------------ .../reference/ReferenceAccessTranslator.java | 8 +- translator/testFiles/kotlin_lib.js | 41 ++++-- 16 files changed, 334 insertions(+), 178 deletions(-) create mode 100644 translator/src/org/jetbrains/k2js/translate/reference/KotlinPropertyAccessTranslator.java create mode 100644 translator/src/org/jetbrains/k2js/translate/reference/NativePropertyAccessTranslator.java diff --git a/jslib/src/core/annotations.kt b/jslib/src/core/annotations.kt index 8d7c69cb06d..5509c5f1112 100644 --- a/jslib/src/core/annotations.kt +++ b/jslib/src/core/annotations.kt @@ -1,7 +1,6 @@ package js.annotations; -annotation class NativeClass() {} -annotation class NativeFun(name : String) +annotation class Native(name : String = "") annotation class LibraryClass() {} -annotation class LibraryFun(name : String) {} \ No newline at end of file +annotation class LibraryFun(name : String = "") {} \ No newline at end of file diff --git a/jslib/src/core/core.kt b/jslib/src/core/core.kt index 0b75d5eb4b7..f158655ecb1 100644 --- a/jslib/src/core/core.kt +++ b/jslib/src/core/core.kt @@ -2,16 +2,25 @@ package js; import js.annotations.LibraryFun import js.annotations.LibraryClass +import js.annotations.Native LibraryFun("println") -fun println() +fun println() {} LibraryFun("println") -fun println(s : Any?) +fun println(s : Any?) {} LibraryFun("print") -fun print(s : Any?) +fun print(s : Any?) {} LibraryFun("parseInt") -fun parseInt(s : String) : Int +fun parseInt(s : String) : Int = 0 LibraryClass -open class Exception() +open class Exception() {} LibraryClass -class NumberFormatException() : Exception() +class NumberFormatException() : Exception() {} + +Native +fun setTimeout(callback : ()-> Unit) {} + +Native +fun setInterval(callback : ()-> Unit, ms : Int) {} +Native +fun setInterval(callback : ()-> Unit) {} \ No newline at end of file diff --git a/jslib/src/core/json.kt b/jslib/src/core/json.kt index b427d861516..a76bb32f990 100644 --- a/jslib/src/core/json.kt +++ b/jslib/src/core/json.kt @@ -1,11 +1,17 @@ package js import java.util.*; +import js.annotations.LibraryFun class Json() { - fun set(paramName : String, value : Any?) {} - fun get(paramName : String) : Any? = null + } +LibraryFun("jsonSet") +fun Json.set(paramName : String, value : Any?) : Unit {} +LibraryFun("jsonGet") +fun Json.get(paramName : String) : Any? = null + fun Map.toJson() : Json = Json() +LibraryFun("jsonFromTuples") fun json(vararg pairs : Tuple2) = Json() diff --git a/jslib/src/jquery/common.kt b/jslib/src/jquery/common.kt index 271c4835d6c..646a1a5a22a 100644 --- a/jslib/src/jquery/common.kt +++ b/jslib/src/jquery/common.kt @@ -2,7 +2,7 @@ package jquery; import js.annotations.*; -NativeClass +Native class JQuery() { fun addClass(className : String) : JQuery = this; fun addClass(f : DomElement.(Int, String)->String) = this; @@ -35,15 +35,15 @@ open class DomElement() { //val document = object : DomElement() {} -NativeFun("$") +Native("$") fun jq(selector : String) = JQuery(); -NativeFun("$") +Native("$") fun jq(selector : String, context : DomElement) = JQuery(); -NativeFun("$") +Native("$") fun jq(callback : () -> Unit) = JQuery(); -NativeFun("$") +Native("$") fun jq(obj : JQuery) = JQuery(); -NativeFun("$") +Native("$") fun jq(el : DomElement) = JQuery(); -NativeFun("$") +Native("$") fun jq() = JQuery(); diff --git a/jslib/src/raphael/raphael.kt b/jslib/src/raphael/raphael.kt index 2050097e701..bf48eac01d9 100644 --- a/jslib/src/raphael/raphael.kt +++ b/jslib/src/raphael/raphael.kt @@ -3,32 +3,60 @@ package raphael import js.annotations.*; import js.*; -NativeClass -class Element() { +Native +open class Element() { - fun attr(name : String, value : String) : Element = this + fun attr(name : String, value : Any?) : Element = this fun attr(nameToValue : Json) : Element = this - fun mouseover(handler : () -> Unit) = this + fun click(handler : Element.()-> Unit) = this; + + fun mouseover(handler : Element.() -> Unit) = this + fun mouseout(handler : Element.() -> Unit) = this + fun getTotalLength() : Double = 0.0 + fun getPointAtLength(length : Double) : Point {} + + fun animate(params : Json, ms : Int, callback : ()-> Unit) : Element {} + fun animate(params : Json, ms : Int, s : String) : Element {} + fun animate(params : Json, ms : Int) : Element {} //fun mouse } -NativeClass +Native +class Set() : Element() { + fun push(el : Element) {} +} + +Native class Paper() { fun path(pathString : String) : Element = Element(); fun path() : Element = Element(); - fun ellipse(x : Int, y : Int, rx : Int, ry : Int) : Element = Element(); + fun ellipse(x : Int, y : Int, rx : Int, ry : Int) : Element {} + fun circle(x : Int, y : Int, r : Int) : Element {} + fun set() : Set {} + + val customAttributes : Json = Json(); } -NativeFun("Raphael") +Native("Raphael") fun Raphael(elementId : String, width : Int, height : Int) : Paper = Paper(); -NativeFun("Raphael") +Native("Raphael") fun Raphael(elementId : String, width : Int, height : Int, initFun : Paper.() -> Unit) : Unit {} -NativeClass -val Raphael = object { - fun getColor() : String = "" +Native +fun getColor() : Color {} +Native +fun resetColors() {} + +Native +class Color() {} + +Native +class Point() { + val x = 0 + val y = 0 + val alpha = 0 } diff --git a/translator/src/org/jetbrains/k2js/config/Config.java b/translator/src/org/jetbrains/k2js/config/Config.java index 845b6d0dd4c..8234d17b646 100644 --- a/translator/src/org/jetbrains/k2js/config/Config.java +++ b/translator/src/org/jetbrains/k2js/config/Config.java @@ -30,7 +30,8 @@ public abstract class Config { PATH_TO_JS_LIB_SRC + "\\core\\javalang.kt", PATH_TO_JS_LIB_SRC + "\\core\\core.kt", PATH_TO_JS_LIB_SRC + "\\raphael\\raphael.kt", - PATH_TO_JS_LIB_SRC + "\\core\\json.kt" + PATH_TO_JS_LIB_SRC + "\\core\\json.kt", + PATH_TO_JS_LIB_SRC + "\\html5\\core.kt" ); diff --git a/translator/src/org/jetbrains/k2js/translate/context/TranslationContext.java b/translator/src/org/jetbrains/k2js/translate/context/TranslationContext.java index 881d19e9c87..4181e68b0a2 100644 --- a/translator/src/org/jetbrains/k2js/translate/context/TranslationContext.java +++ b/translator/src/org/jetbrains/k2js/translate/context/TranslationContext.java @@ -193,9 +193,8 @@ public final class TranslationContext { return dynamicContext.jsBlock(); } - //TODO: deletE? @NotNull - private DeclarationFacade declarationFacade() { + public DeclarationFacade declarationFacade() { return staticContext.getDeclarationFacade(); } } diff --git a/translator/src/org/jetbrains/k2js/translate/context/declaration/AnnotatedDeclarationVisitor.java b/translator/src/org/jetbrains/k2js/translate/context/declaration/AnnotatedDeclarationVisitor.java index 51b0e0e93c2..1068092e896 100644 --- a/translator/src/org/jetbrains/k2js/translate/context/declaration/AnnotatedDeclarationVisitor.java +++ b/translator/src/org/jetbrains/k2js/translate/context/declaration/AnnotatedDeclarationVisitor.java @@ -4,7 +4,6 @@ import com.google.dart.compiler.backend.js.ast.JsName; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.k2js.translate.context.NamingScope; @@ -20,14 +19,14 @@ public class AnnotatedDeclarationVisitor extends AbstractDeclarationVisitor { private final String classAnnotationFQName; @NotNull - private final String funAnnotationFQName; + private final String memberAnnotationFQName; /*package*/ AnnotatedDeclarationVisitor(@NotNull Declarations declarations, @NotNull String classAnnotationFQName, - @NotNull String funAnnotationFQName) { + @NotNull String memberAnnotationFQName) { super(declarations); this.classAnnotationFQName = classAnnotationFQName; - this.funAnnotationFQName = funAnnotationFQName; + this.memberAnnotationFQName = memberAnnotationFQName; } @NotNull @@ -61,13 +60,11 @@ public class AnnotatedDeclarationVisitor extends AbstractDeclarationVisitor { if (descriptor instanceof NamespaceDescriptor) { return true; } - if (descriptor instanceof FunctionDescriptor) { - return isAnnotatedFunction((FunctionDescriptor) descriptor); - } if (descriptor instanceof ClassDescriptor) { return isAnnotatedClass((ClassDescriptor) descriptor); } - return false; + + return isAnnotatedMember(descriptor); } @Override @@ -76,38 +73,28 @@ public class AnnotatedDeclarationVisitor extends AbstractDeclarationVisitor { } + //TODO: refactor @NotNull public String getName(@NotNull DeclarationDescriptor descriptor) { - if (descriptor instanceof FunctionDescriptor) { - return getNameForFunction((FunctionDescriptor) descriptor); - } - if (descriptor instanceof ClassDescriptor) { - return getNameForClass((ClassDescriptor) descriptor); - } - throw new AssertionError(); - } - - @NotNull - private String getNameForFunction(@NotNull FunctionDescriptor descriptor) { - if (hasFunctionAnnotation(descriptor)) { - return annotationStringParameter(descriptor, funAnnotationFQName); + if (hasMemberAnnotation(descriptor)) { + String name = annotationStringParameter(descriptor, memberAnnotationFQName); + if (!(name.isEmpty())) { + return name; + } + return descriptor.getName(); } if (declaredInAnnotatedClass(descriptor)) { return descriptor.getName(); } + if (hasClassAnnotation(descriptor)) { + return descriptor.getName(); + } throw new AssertionError("Use isAnnotatedFunction to check"); } - @NotNull - private String getNameForClass(@NotNull ClassDescriptor descriptor) { - if (hasClassAnnotation(descriptor)) { - return descriptor.getName(); - } - throw new AssertionError("Use isAnnotatedClass to check"); - } - public boolean isAnnotatedFunction(@NotNull FunctionDescriptor functionDescriptor) { - return hasFunctionAnnotation(functionDescriptor) || declaredInAnnotatedClass(functionDescriptor); + public boolean isAnnotatedMember(@NotNull DeclarationDescriptor descriptor) { + return hasMemberAnnotation(descriptor) || declaredInAnnotatedClass(descriptor); } public boolean isAnnotatedClass(@NotNull ClassDescriptor classDescriptor) { @@ -121,8 +108,8 @@ public class AnnotatedDeclarationVisitor extends AbstractDeclarationVisitor { } - private boolean hasFunctionAnnotation(@NotNull DeclarationDescriptor descriptor) { - return (getAnnotationByName(descriptor, funAnnotationFQName) != null); + private boolean hasMemberAnnotation(@NotNull DeclarationDescriptor descriptor) { + return (getAnnotationByName(descriptor, memberAnnotationFQName) != null); } private boolean hasClassAnnotation(@NotNull DeclarationDescriptor descriptor) { diff --git a/translator/src/org/jetbrains/k2js/translate/context/declaration/AnnotationsUtils.java b/translator/src/org/jetbrains/k2js/translate/context/declaration/AnnotationsUtils.java index cbf857c667d..1baccb26c49 100644 --- a/translator/src/org/jetbrains/k2js/translate/context/declaration/AnnotationsUtils.java +++ b/translator/src/org/jetbrains/k2js/translate/context/declaration/AnnotationsUtils.java @@ -4,9 +4,9 @@ import com.google.common.collect.Sets; 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.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.resolve.DescriptorUtils; +import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import java.util.Set; @@ -16,16 +16,14 @@ import java.util.Set; public final class AnnotationsUtils { @NotNull - public static final String NATIVE_FUNCTION_ANNOTATION_FQNAME = "js.annotations.NativeFun"; - @NotNull - public static final String NATIVE_CLASS_ANNOTATION_FQNAME = "js.annotations.NativeClass"; + public static final String NATIVE_ANNOTATION_FQNAME = "js.annotations.Native"; @NotNull public static final String LIBRARY_FUNCTION_ANNOTATION_FQNAME = "js.annotations.LibraryFun"; @NotNull public static final String LIBRARY_CLASS_ANNOTATION_FQNAME = "js.annotations.LibraryClass"; @NotNull public static Set INTERNAL_ANNOTATIONS_FQNAMES = Sets.newHashSet( - NATIVE_CLASS_ANNOTATION_FQNAME, NATIVE_FUNCTION_ANNOTATION_FQNAME, + NATIVE_ANNOTATION_FQNAME, LIBRARY_CLASS_ANNOTATION_FQNAME, LIBRARY_FUNCTION_ANNOTATION_FQNAME); private AnnotationsUtils() { @@ -46,12 +44,21 @@ public final class AnnotationsUtils { } @NotNull - public static String annotationStringParameter(@NotNull FunctionDescriptor declarationDescriptor, + public static String annotationStringParameter(@NotNull DeclarationDescriptor declarationDescriptor, @NotNull String annotationFQName) { AnnotationDescriptor annotationDescriptor = getAnnotationByName(declarationDescriptor, annotationFQName); assert annotationDescriptor != null; - Object value = annotationDescriptor.getValueArguments().iterator().next().getValue(); + //TODO: this is a quick fix for unsupported default args problem + if (annotationDescriptor.getValueArguments().isEmpty()) { + return ""; + } + CompileTimeConstant constant = annotationDescriptor.getValueArguments().iterator().next(); + //TODO: this is a quick fix for unsupported default args problem + if (constant == null) { + return ""; + } + Object value = constant.getValue(); assert value instanceof String : "Native function annotation should have one String parameter"; return (String) value; } diff --git a/translator/src/org/jetbrains/k2js/translate/context/declaration/NativeDeclarationVisitor.java b/translator/src/org/jetbrains/k2js/translate/context/declaration/NativeDeclarationVisitor.java index 6e95a67aab7..c33052b91e6 100644 --- a/translator/src/org/jetbrains/k2js/translate/context/declaration/NativeDeclarationVisitor.java +++ b/translator/src/org/jetbrains/k2js/translate/context/declaration/NativeDeclarationVisitor.java @@ -2,8 +2,7 @@ package org.jetbrains.k2js.translate.context.declaration; import org.jetbrains.annotations.NotNull; -import static org.jetbrains.k2js.translate.context.declaration.AnnotationsUtils.NATIVE_CLASS_ANNOTATION_FQNAME; -import static org.jetbrains.k2js.translate.context.declaration.AnnotationsUtils.NATIVE_FUNCTION_ANNOTATION_FQNAME; +import static org.jetbrains.k2js.translate.context.declaration.AnnotationsUtils.NATIVE_ANNOTATION_FQNAME; /** * @author Pavel Talanov @@ -11,6 +10,6 @@ import static org.jetbrains.k2js.translate.context.declaration.AnnotationsUtils. public final class NativeDeclarationVisitor extends AnnotatedDeclarationVisitor { /*package*/ NativeDeclarationVisitor(@NotNull Declarations nativeDeclarations) { - super(nativeDeclarations, NATIVE_CLASS_ANNOTATION_FQNAME, NATIVE_FUNCTION_ANNOTATION_FQNAME); + super(nativeDeclarations, NATIVE_ANNOTATION_FQNAME, NATIVE_ANNOTATION_FQNAME); } } diff --git a/translator/src/org/jetbrains/k2js/translate/reference/ArrayAccessTranslator.java b/translator/src/org/jetbrains/k2js/translate/reference/ArrayAccessTranslator.java index 542286cfbd2..564de6942bb 100644 --- a/translator/src/org/jetbrains/k2js/translate/reference/ArrayAccessTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/reference/ArrayAccessTranslator.java @@ -21,8 +21,9 @@ import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForRe */ public final class ArrayAccessTranslator extends AccessTranslator { - public static ArrayAccessTranslator newInstance(@NotNull JetArrayAccessExpression expression, - @NotNull TranslationContext context) { + /*package*/ + static ArrayAccessTranslator newInstance(@NotNull JetArrayAccessExpression expression, + @NotNull TranslationContext context) { return new ArrayAccessTranslator(expression, context); } diff --git a/translator/src/org/jetbrains/k2js/translate/reference/KotlinPropertyAccessTranslator.java b/translator/src/org/jetbrains/k2js/translate/reference/KotlinPropertyAccessTranslator.java new file mode 100644 index 00000000000..0486f9150cb --- /dev/null +++ b/translator/src/org/jetbrains/k2js/translate/reference/KotlinPropertyAccessTranslator.java @@ -0,0 +1,83 @@ +package org.jetbrains.k2js.translate.reference; + +import com.google.dart.compiler.backend.js.ast.JsExpression; +import com.google.dart.compiler.backend.js.ast.JsNameRef; +import com.google.dart.compiler.util.AstUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; +import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; +import org.jetbrains.k2js.translate.context.TranslationContext; + +import java.util.Arrays; + +import static org.jetbrains.k2js.translate.utils.TranslationUtils.backingFieldReference; + +/** + * @author Pavel Talanov + */ +public final class KotlinPropertyAccessTranslator extends PropertyAccessTranslator { + + @Nullable + private final JsExpression qualifier; + @NotNull + private final PropertyDescriptor propertyDescriptor; + private final boolean isBackingFieldAccess; + @NotNull + ResolvedCall resolvedCall; + + //TODO: too many params in constructor + /*package*/ KotlinPropertyAccessTranslator(@NotNull PropertyDescriptor descriptor, + @Nullable JsExpression qualifier, + boolean isBackingFieldAccess, + @NotNull ResolvedCall resolvedCall, + @NotNull TranslationContext context) { + super(context); + this.qualifier = qualifier; + this.propertyDescriptor = descriptor.getOriginal(); + this.isBackingFieldAccess = isBackingFieldAccess; + this.resolvedCall = resolvedCall; + } + + @Override + @NotNull + public JsExpression translateAsGet() { + if (isBackingFieldAccess) { + return backingFieldGet(); + } else { + return getterCall(); + } + } + + @NotNull + private JsExpression backingFieldGet() { + return backingFieldReference(context(), propertyDescriptor); + } + + @NotNull + private JsExpression getterCall() { + return CallTranslator.translate(qualifier, resolvedCall, propertyDescriptor.getGetter(), context()); + } + + @Override + @NotNull + public JsExpression translateAsSet(@NotNull JsExpression toSetTo) { + if (isBackingFieldAccess) { + return backingFieldAssignment(toSetTo); + } else { + return setterCall(toSetTo); + } + } + + @NotNull + private JsExpression setterCall(@NotNull JsExpression toSetTo) { + return CallTranslator.translate(qualifier, Arrays.asList(toSetTo), + resolvedCall, propertyDescriptor.getSetter(), context()); + } + + @NotNull + private JsExpression backingFieldAssignment(@NotNull JsExpression toSetTo) { + JsNameRef backingFieldReference = backingFieldReference(context(), propertyDescriptor); + return AstUtil.newAssignment(backingFieldReference, toSetTo); + } +} diff --git a/translator/src/org/jetbrains/k2js/translate/reference/NativePropertyAccessTranslator.java b/translator/src/org/jetbrains/k2js/translate/reference/NativePropertyAccessTranslator.java new file mode 100644 index 00000000000..ffdec57d561 --- /dev/null +++ b/translator/src/org/jetbrains/k2js/translate/reference/NativePropertyAccessTranslator.java @@ -0,0 +1,66 @@ +package org.jetbrains.k2js.translate.reference; + +import com.google.dart.compiler.backend.js.ast.JsExpression; +import com.google.dart.compiler.backend.js.ast.JsName; +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.PropertyDescriptor; +import org.jetbrains.k2js.translate.context.TranslationContext; +import org.jetbrains.k2js.translate.utils.TranslationUtils; + +import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getExpectedThisDescriptor; + +/** + * @author Pavel Talanov + */ +public final class NativePropertyAccessTranslator extends PropertyAccessTranslator { + + + @Nullable + private final JsExpression qualifier; + @NotNull + private final PropertyDescriptor propertyDescriptor; + + /*package*/ + NativePropertyAccessTranslator(@NotNull PropertyDescriptor descriptor, + @Nullable JsExpression qualifier, + @NotNull TranslationContext context) { + super(context); + this.qualifier = qualifier; + this.propertyDescriptor = descriptor.getOriginal(); + } + + + @Override + @NotNull + public JsExpression translateAsGet() { + JsName nativePropertyName = context().getNameForDescriptor(propertyDescriptor); + JsExpression realQualifier = getQualifier(); + if (realQualifier != null) { + return AstUtil.qualified(nativePropertyName, realQualifier); + } else { + return nativePropertyName.makeRef(); + } + } + + @Override + @NotNull + public JsExpression translateAsSet(@NotNull JsExpression setTo) { + return AstUtil.assignment(translateAsGet(), setTo); + } + + @Nullable + public JsExpression getQualifier() { + if (qualifier != null) { + return qualifier; + } + assert !propertyDescriptor.getReceiverParameter().exists() : "Cant have native extension properties."; + DeclarationDescriptor expectedThisDescriptor = getExpectedThisDescriptor(propertyDescriptor); + if (expectedThisDescriptor == null) { + return null; + } + return TranslationUtils.getThisObject(context(), expectedThisDescriptor); + } +} diff --git a/translator/src/org/jetbrains/k2js/translate/reference/PropertyAccessTranslator.java b/translator/src/org/jetbrains/k2js/translate/reference/PropertyAccessTranslator.java index cbda54ad3d9..110000761c0 100644 --- a/translator/src/org/jetbrains/k2js/translate/reference/PropertyAccessTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/reference/PropertyAccessTranslator.java @@ -1,8 +1,6 @@ package org.jetbrains.k2js.translate.reference; import com.google.dart.compiler.backend.js.ast.JsExpression; -import com.google.dart.compiler.backend.js.ast.JsNameRef; -import com.google.dart.compiler.util.AstUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; @@ -13,32 +11,57 @@ import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.k2js.translate.context.TranslationContext; -import java.util.Arrays; - import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression; import static org.jetbrains.k2js.translate.utils.BindingUtils.getResolvedCall; import static org.jetbrains.k2js.translate.utils.PsiUtils.getSelectorAsSimpleName; import static org.jetbrains.k2js.translate.utils.PsiUtils.isBackingFieldReference; -import static org.jetbrains.k2js.translate.utils.TranslationUtils.backingFieldReference; /** * @author Pavel Talanov */ -public final class PropertyAccessTranslator extends AccessTranslator { +public abstract class PropertyAccessTranslator extends AccessTranslator { @NotNull - private static PropertyDescriptor getPropertyDescriptor(@NotNull JetSimpleNameExpression expression, - @NotNull TranslationContext context) { + public static PropertyAccessTranslator newInstance(@NotNull PropertyDescriptor descriptor, + @NotNull ResolvedCall resolvedCall, + @NotNull TranslationContext context) { + if (isNativeProperty(descriptor, context)) { + return new NativePropertyAccessTranslator(descriptor, /*qualifier = */ null, context); + } else { + return new KotlinPropertyAccessTranslator(descriptor, /*qualifier = */ null, /*backingFieldAccess = */ false, + resolvedCall, context); + } + } + + @NotNull + public static PropertyAccessTranslator newInstance(@NotNull JetSimpleNameExpression expression, + @Nullable JsExpression qualifier, + @NotNull TranslationContext context) { + PropertyDescriptor propertyDescriptor = getPropertyDescriptor(expression, context); + if (isNativeProperty(propertyDescriptor, context)) { + return new NativePropertyAccessTranslator(propertyDescriptor, qualifier, context); + } + ResolvedCall resolvedCall = getResolvedCall(context.bindingContext(), expression); + boolean backingFieldAccess = isBackingFieldReference(expression); + return new KotlinPropertyAccessTranslator(propertyDescriptor, qualifier, + backingFieldAccess, resolvedCall, context); + } + + @NotNull + /*package*/ static PropertyDescriptor getPropertyDescriptor(@NotNull JetSimpleNameExpression expression, + @NotNull TranslationContext context) { DeclarationDescriptor descriptor = getDescriptorForReferenceExpression(context.bindingContext(), expression); assert descriptor instanceof PropertyDescriptor : "Must be a property descriptor."; return (PropertyDescriptor) descriptor; } + @NotNull - public static JsExpression translateAsPropertyGetterCall(@NotNull PropertyDescriptor descriptor, - @NotNull ResolvedCall resolvedCall, - @NotNull TranslationContext context) { + /*package*/ + static JsExpression translateAsPropertyGetterCall(@NotNull PropertyDescriptor descriptor, + @NotNull ResolvedCall resolvedCall, + @NotNull TranslationContext context) { return (newInstance(descriptor, resolvedCall, context)) .translateAsGet(); } @@ -51,23 +74,6 @@ public final class PropertyAccessTranslator extends AccessTranslator { .translateAsGet(); } - @NotNull - private static PropertyAccessTranslator newInstance(@NotNull PropertyDescriptor descriptor, - @NotNull ResolvedCall resolvedCall, - @NotNull TranslationContext context) { - return new PropertyAccessTranslator(descriptor, null, false, resolvedCall, context); - } - - @NotNull - public static PropertyAccessTranslator newInstance(@NotNull JetSimpleNameExpression expression, - @Nullable JsExpression qualifier, - @NotNull TranslationContext context) { - PropertyDescriptor propertyDescriptor = getPropertyDescriptor(expression, context); - ResolvedCall resolvedCall = getResolvedCall(context.bindingContext(), expression); - boolean backingFieldAccess = isBackingFieldReference(expression); - return new PropertyAccessTranslator(propertyDescriptor, qualifier, - backingFieldAccess, resolvedCall, context); - } public static boolean canBePropertyGetterCall(@NotNull JetQualifiedExpression expression, @NotNull TranslationContext context) { @@ -101,65 +107,13 @@ public final class PropertyAccessTranslator extends AccessTranslator { return canBePropertyGetterCall(expression, context); } - @Nullable - private final JsExpression qualifier; - @NotNull - private final PropertyDescriptor propertyDescriptor; - private final boolean isBackingFieldAccess; - @NotNull - ResolvedCall resolvedCall; + private static boolean isNativeProperty(@NotNull PropertyDescriptor propertyDescriptor, + @NotNull TranslationContext context) { + return context.declarationFacade().getNativeDeclarations().hasDeclaredName(propertyDescriptor); + } - private PropertyAccessTranslator(@NotNull PropertyDescriptor descriptor, - @Nullable JsExpression qualifier, - boolean isBackingFieldAccess, - @NotNull ResolvedCall resolvedCall, - @NotNull TranslationContext context) { + protected PropertyAccessTranslator(@NotNull TranslationContext context) { super(context); - this.qualifier = qualifier; - this.propertyDescriptor = descriptor.getOriginal(); - this.isBackingFieldAccess = isBackingFieldAccess; - this.resolvedCall = resolvedCall; } - @Override - @NotNull - public JsExpression translateAsGet() { - if (isBackingFieldAccess) { - return backingFieldGet(); - } else { - return getterCall(); - } - } - - @NotNull - private JsExpression backingFieldGet() { - return backingFieldReference(context(), propertyDescriptor); - } - - @NotNull - private JsExpression getterCall() { - return CallTranslator.translate(qualifier, resolvedCall, propertyDescriptor.getGetter(), context()); - } - - @Override - @NotNull - public JsExpression translateAsSet(@NotNull JsExpression toSetTo) { - if (isBackingFieldAccess) { - return backingFieldAssignment(toSetTo); - } else { - return setterCall(toSetTo); - } - } - - @NotNull - private JsExpression setterCall(@NotNull JsExpression toSetTo) { - return CallTranslator.translate(qualifier, Arrays.asList(toSetTo), - resolvedCall, propertyDescriptor.getSetter(), context()); - } - - @NotNull - private JsExpression backingFieldAssignment(@NotNull JsExpression toSetTo) { - JsNameRef backingFieldReference = backingFieldReference(context(), propertyDescriptor); - return AstUtil.newAssignment(backingFieldReference, toSetTo); - } -} +} \ No newline at end of file diff --git a/translator/src/org/jetbrains/k2js/translate/reference/ReferenceAccessTranslator.java b/translator/src/org/jetbrains/k2js/translate/reference/ReferenceAccessTranslator.java index f2d7ed488ca..f5adc75859d 100644 --- a/translator/src/org/jetbrains/k2js/translate/reference/ReferenceAccessTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/reference/ReferenceAccessTranslator.java @@ -13,13 +13,11 @@ import org.jetbrains.k2js.translate.context.TranslationContext; public final class ReferenceAccessTranslator extends AccessTranslator { @NotNull - public static ReferenceAccessTranslator newInstance(@NotNull JetSimpleNameExpression expression, - @NotNull TranslationContext context) { + /*package*/ static ReferenceAccessTranslator newInstance(@NotNull JetSimpleNameExpression expression, + @NotNull TranslationContext context) { return new ReferenceAccessTranslator(expression, context); } - //TODO: condider evaluating only once - @NotNull private final JetSimpleNameExpression expression; @@ -32,12 +30,14 @@ public final class ReferenceAccessTranslator extends AccessTranslator { @Override @NotNull public JsExpression translateAsGet() { + //TODO: consider evaluating only once return ReferenceTranslator.translateSimpleName(expression, context()); } @Override @NotNull public JsExpression translateAsSet(@NotNull JsExpression toSetTo) { + //TODO: consider evaluating only once JsExpression reference = ReferenceTranslator.translateSimpleName(expression, context()); assert reference instanceof JsNameRef; return AstUtil.newAssignment((JsNameRef) reference, toSetTo); diff --git a/translator/testFiles/kotlin_lib.js b/translator/testFiles/kotlin_lib.js index 469c9b5fc45..fab347c438f 100644 --- a/translator/testFiles/kotlin_lib.js +++ b/translator/testFiles/kotlin_lib.js @@ -122,8 +122,9 @@ ; function create() { var parent = null, properties = $A(arguments); - if (typeof (properties[0]) == "function") + if (typeof (properties[0]) == "function") { parent = properties.shift(); + } function klass() { this.initializing = klass; @@ -160,8 +161,9 @@ for (var i = 0, length = properties.length; i < length; i++) klass.addMethods(properties[i]); - if (!klass.prototype.initialize) + if (!klass.prototype.initialize) { klass.prototype.initialize = emptyFunction; + } klass.prototype.constructor = klass; return klass; @@ -313,9 +315,9 @@ Kotlin.parseInt = - function (str) { - return parseInt(str); - } + function (str) { + return parseInt(str); + } ; Kotlin.System = function () { @@ -325,7 +327,8 @@ if (obj !== undefined) { if (obj == null || typeof obj != "object") { output += obj; - } else { + } + else { output += obj.toString(); } } @@ -507,7 +510,9 @@ next:function () { return this.arr[this.i++]; }, - get_hasNext:function() { return this.hasNext()} + get_hasNext:function () { + return this.hasNext() + } } ); @@ -519,7 +524,7 @@ return obj.toString(); }; - Kotlin.jsonFromTuples = function(pairArr) { + Kotlin.jsonFromTuples = function (pairArr) { var i = pairArr.length; var res = {}; while (i > 0) { @@ -529,6 +534,14 @@ return res; }; + Kotlin.jsonSet = function (obj, attrName, value) { + obj[attrName] = value; + }; + + Kotlin.jsonGet = function (obj, attrName) { + return obj[attrName]; + }; + /** * Copyright 2010 Tim Down. @@ -570,7 +583,8 @@ var itemsAfterDeleted, i, len; if (idx === arr.length - 1) { arr.length = idx; - } else { + } + else { itemsAfterDeleted = arr.slice(idx + 1); arr.length = idx; for (i = 0, len = itemsAfterDeleted.length; i < len; ++i) { @@ -589,7 +603,8 @@ return (typeof hashCode == "string") ? hashCode : hashObject(hashCode); } else if (typeof obj.toString == FUNCTION) { return obj.toString(); - } else { + } + else { try { return String(obj); } catch (ex) { @@ -759,11 +774,13 @@ // This bucket entry is the current mapping of key to value, so replace old value and we're done. oldValue = bucketEntry[1]; bucketEntry[1] = value; - } else { + } + else { // The bucket does not contain an entry for this key, so add one bucket.addEntry(key, value); } - } else { + } + else { // No bucket exists for the key, so create one and put our key/value mapping in bucket = new Bucket(hash, key, value, equalityFunction); buckets[buckets.length] = bucket;