From e13d34e08dbf2a2015284b2851824f00d0b6be4f Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Fri, 14 Oct 2016 15:34:16 +0300 Subject: [PATCH] JS: rewrite stdlib to compile with new flat structure --- build.xml | 16 + .../dart/compiler/backend/js/ast/jsScopes.kt | 6 +- .../kotlin/js/naming/NameSuggestion.kt | 10 +- js/js.libraries/src/builtins/annotations.kt | 27 + js/js.libraries/src/builtins/kotlin.kt | 34 ++ .../primitiveCompanionObjects.kt | 16 +- js/js.libraries/src/core/builtins.kt | 33 ++ js/js.libraries/src/core/exceptions.kt | 39 +- js/js.libraries/src/core/javalang.kt | 63 ++- js/js.libraries/src/core/javautil.kt | 7 +- .../kotlin/js/translate/context/Namer.java | 9 +- .../js/translate/context/StandardClasses.java | 181 ------- .../js/translate/context/StaticContext.java | 90 ++-- .../translate/context/TranslationContext.java | 41 +- .../translate/declaration/ClassTranslator.kt | 121 ++--- .../declaration/DeclarationBodyVisitor.kt | 6 +- .../declaration/DefineInvocation.java | 99 ---- .../declaration/FileDeclarationVisitor.kt | 9 +- .../expression/LiteralFunctionTranslator.kt | 4 +- .../js/translate/general/Translation.java | 4 +- .../js/translate/intrinsic/Intrinsics.java | 7 +- .../functions/FunctionIntrinsics.java | 2 +- .../functions/basic/FqnCallIntrinsic.kt | 49 ++ .../basic/LazyImportedCallIntrinsic.kt | 49 ++ .../functions/factories/LongOperationFIF.kt | 1 - .../PrimitiveBinaryOperationFIF.java | 20 +- .../factories/ProgressionCompanionFIF.kt | 21 +- .../factories/StringOperationFIF.java | 33 -- .../intrinsic/objects/objectsIntrinsics.kt | 22 +- .../kotlin/js/translate/utils/JsAstUtils.java | 18 - .../js/translate/utils/TranslationUtils.java | 2 +- .../kotlin/js/translate/utils/utils.kt | 4 +- js/js.translator/testData/kotlin_lib.js | 475 +----------------- js/js.translator/testData/kotlin_lib_ecma5.js | 41 +- js/js.translator/testData/long.js | 2 +- js/js.translator/testData/merge-builtins.js | 12 + js/js.translator/testData/merge.js | 16 +- jslib_files.xml | 15 + 38 files changed, 588 insertions(+), 1016 deletions(-) create mode 100644 js/js.libraries/src/builtins/annotations.kt create mode 100644 js/js.libraries/src/builtins/kotlin.kt rename js/js.libraries/src/{internal => builtins}/primitiveCompanionObjects.kt (82%) create mode 100644 js/js.libraries/src/core/builtins.kt delete mode 100644 js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StandardClasses.java delete mode 100644 js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DefineInvocation.java create mode 100644 js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/basic/FqnCallIntrinsic.kt create mode 100644 js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/basic/LazyImportedCallIntrinsic.kt delete mode 100644 js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/StringOperationFIF.java create mode 100644 js/js.translator/testData/merge-builtins.js diff --git a/build.xml b/build.xml index 6022cd4f56b..75607fd8f67 100644 --- a/build.xml +++ b/build.xml @@ -366,6 +366,14 @@ + + + + + + + + @@ -384,6 +392,13 @@ + + + + + + + @@ -392,6 +407,7 @@ + diff --git a/js/js.dart-ast/src/com/google/dart/compiler/backend/js/ast/jsScopes.kt b/js/js.dart-ast/src/com/google/dart/compiler/backend/js/ast/jsScopes.kt index 210bc0369cb..f037125dd8e 100644 --- a/js/js.dart-ast/src/com/google/dart/compiler/backend/js/ast/jsScopes.kt +++ b/js/js.dart-ast/src/com/google/dart/compiler/backend/js/ast/jsScopes.kt @@ -100,7 +100,11 @@ open class JsFunctionScope(parent: JsScope, description: String) : JsScope(paren "NaN", "Infinity", "undefined", // the special Kotlin object - "Kotlin" + "Kotlin", + + "Error", "Object", "Math", "String", "Number", "Boolean", "Date", "Array", "RegExp", "JSON", + + "require", "define", "module", "window", "self" ) } } diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt index dcbc259f565..e8e91afa812 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt @@ -19,7 +19,8 @@ package org.jetbrains.kotlin.js.naming import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName -import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.* +import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.getNameForAnnotatedObject +import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isNativeObject import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic @@ -198,6 +199,13 @@ class NameSuggestion { val nativeName = getNameForAnnotatedObject(overriddenDescriptor) if (nativeName != null) return NameAndStability(nativeName, true) + if (overriddenDescriptor is FunctionDescriptor) { + when (overriddenDescriptor.fqNameUnsafe.asString()) { + "kotlin.CharSequence.subSequence" -> return NameAndStability("substring", true) + "kotlin.CharSequence.get" -> return NameAndStability("charAt", true) + } + } + return mangleRegularNameIfNecessary(baseName, overriddenDescriptor) } diff --git a/js/js.libraries/src/builtins/annotations.kt b/js/js.libraries/src/builtins/annotations.kt new file mode 100644 index 00000000000..109a3f391e0 --- /dev/null +++ b/js/js.libraries/src/builtins/annotations.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kotlin.js + +import kotlin.annotation.AnnotationTarget.* + +@Retention(AnnotationRetention.BINARY) +@Target(CLASS, FUNCTION, PROPERTY, CONSTRUCTOR, PROPERTY_GETTER, PROPERTY_SETTER) +@native annotation class JsName(val name: String) + +@native annotation class native + +@native fun js(code: String): dynamic \ No newline at end of file diff --git a/js/js.libraries/src/builtins/kotlin.kt b/js/js.libraries/src/builtins/kotlin.kt new file mode 100644 index 00000000000..93d9ca34825 --- /dev/null +++ b/js/js.libraries/src/builtins/kotlin.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kotlin + +class Enum> : Comparable> { + @JsName("name$") private var _name: String = "" + @JsName("ordinal$") private var _ordinal: Int = 0 + + val name: String + get() = _name + + val ordinal: Int + get() = _ordinal + + override fun compareTo(other: Enum) = ordinal.compareTo(other.ordinal) + + override fun toString() = name +} + +interface Annotation \ No newline at end of file diff --git a/js/js.libraries/src/internal/primitiveCompanionObjects.kt b/js/js.libraries/src/builtins/primitiveCompanionObjects.kt similarity index 82% rename from js/js.libraries/src/internal/primitiveCompanionObjects.kt rename to js/js.libraries/src/builtins/primitiveCompanionObjects.kt index 4ad6e8855b3..e15933124df 100644 --- a/js/js.libraries/src/internal/primitiveCompanionObjects.kt +++ b/js/js.libraries/src/builtins/primitiveCompanionObjects.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ package kotlin.js.internal -private object DoubleCompanionObject { +@JsName("DoubleCompanionObject") private object DoubleCompanionObject { @JsName("MIN_VALUE") val MIN_VALUE: Double = js("Number.MIN_VALUE") @JsName("MAX_VALUE") val MAX_VALUE: Double = js("Number.MAX_VALUE") @JsName("POSITIVE_INFINITY") val POSITIVE_INFINITY: Double = js("Number.POSITIVE_INFINITY") @@ -24,7 +24,7 @@ private object DoubleCompanionObject { @JsName("NaN") val NaN: Double = js("Number.NaN") } -private object FloatCompanionObject { +@JsName("FloatCompanionObject") private object FloatCompanionObject { @JsName("MIN_VALUE") val MIN_VALUE: Float = js("Number.MIN_VALUE") @JsName("MAX_VALUE") val MAX_VALUE: Float = js("Number.MAX_VALUE") @JsName("POSITIVE_INFINITY") val POSITIVE_INFINITY: Float = js("Number.POSITIVE_INFINITY") @@ -32,27 +32,27 @@ private object FloatCompanionObject { @JsName("NaN") val NaN: Float = js("Number.NaN") } -private object IntCompanionObject { +@JsName("IntCompanionObject") private object IntCompanionObject { @JsName("MIN_VALUE") val MIN_VALUE: Int = -2147483647 - 1 @JsName("MAX_VALUE") val MAX_VALUE: Int = 2147483647 } -private object LongCompanionObject { +@JsName("LongCompanionObject") private object LongCompanionObject { @JsName("MIN_VALUE") val MIN_VALUE: Long = js("Kotlin.Long.MIN_VALUE") @JsName("MAX_VALUE") val MAX_VALUE: Long = js("Kotlin.Long.MAX_VALUE") } -private object ShortCompanionObject { +@JsName("ShortCompanionObject") private object ShortCompanionObject { @JsName("MIN_VALUE") val MIN_VALUE: Short = -32768 @JsName("MAX_VALUE") val MAX_VALUE: Short = 32767 } -private object ByteCompanionObject { +@JsName("ByteCompanionObject") private object ByteCompanionObject { @JsName("MIN_VALUE") val MIN_VALUE: Byte = -128 @JsName("MAX_VALUE") val MAX_VALUE: Byte = 127 } -private object CharCompanionObject { +@JsName("CharCompanionObject") private object CharCompanionObject { @JsName("MIN_HIGH_SURROGATE") public const val MIN_HIGH_SURROGATE: Char = '\uD800' @JsName("MAX_HIGH_SURROGATE") public const val MAX_HIGH_SURROGATE: Char = '\uDBFF' @JsName("MIN_LOW_SURROGATE") public const val MIN_LOW_SURROGATE: Char = '\uDC00' diff --git a/js/js.libraries/src/core/builtins.kt b/js/js.libraries/src/core/builtins.kt new file mode 100644 index 00000000000..9d1ebc3d2d3 --- /dev/null +++ b/js/js.libraries/src/core/builtins.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@JsName("arrayIterator") +internal fun arrayIterator(array: dynamic): MutableIterator { + return object : MutableIterator { + var index = 0; + + override fun hasNext(): Boolean { + val length: Int = array.length + return index < length + } + + override fun next() = array[index++] + + override fun remove() { + array.splice(--index, 1) + } + } +} diff --git a/js/js.libraries/src/core/exceptions.kt b/js/js.libraries/src/core/exceptions.kt index 9a522357cc5..57dbb7289f4 100644 --- a/js/js.libraries/src/core/exceptions.kt +++ b/js/js.libraries/src/core/exceptions.kt @@ -16,41 +16,28 @@ package kotlin -@library -public open class Error(message: String? = null) : Throwable(message) {} +open class Error(message: String? = null) : Throwable(message, null) {} -@library -public open class Exception(message: String? = null) : Throwable(message) {} +open class Exception(message: String? = null) : Throwable(message, null) {} -@library -public open class RuntimeException(message: String? = null) : Exception(message) {} +open class RuntimeException(message: String? = null) : Exception(message) {} -@library -public open class IllegalArgumentException(message: String? = null) : RuntimeException(message) {} +open class IllegalArgumentException(message: String? = null) : RuntimeException(message) {} -@library -public open class IllegalStateException(message: String? = null) : RuntimeException(message) {} +open class IllegalStateException(message: String? = null) : RuntimeException(message) {} -@library -public open class IndexOutOfBoundsException(message: String? = null) : RuntimeException(message) {} +open class IndexOutOfBoundsException(message: String? = null) : RuntimeException(message) {} -@library -public open class ConcurrentModificationException(message: String? = null) : RuntimeException(message) {} +open class ConcurrentModificationException(message: String? = null) : RuntimeException(message) {} -@library -public open class UnsupportedOperationException(message: String? = null) : RuntimeException(message) {} +open class UnsupportedOperationException(message: String? = null) : RuntimeException(message) {} -@library -public open class NumberFormatException(message: String? = null) : RuntimeException(message) {} +open class NumberFormatException(message: String? = null) : RuntimeException(message) {} -@library -public open class NullPointerException(message: String? = null) : RuntimeException(message) {} +open class NullPointerException(message: String? = null) : RuntimeException(message) {} -@library -public open class ClassCastException(message: String? = null) : RuntimeException(message) {} +open class ClassCastException(message: String? = null) : RuntimeException(message) {} -@library -public open class AssertionError(message: String? = null) : Error(message) {} +open class AssertionError(message: String? = null) : Error(message) {} -@library -public open class NoSuchElementException(message: String? = null) : Exception() {} +open class NoSuchElementException(message: String? = null) : Exception() {} diff --git a/js/js.libraries/src/core/javalang.kt b/js/js.libraries/src/core/javalang.kt index 7445d8df3ef..be57e90250f 100644 --- a/js/js.libraries/src/core/javalang.kt +++ b/js/js.libraries/src/core/javalang.kt @@ -17,25 +17,50 @@ package java.lang -@library -public interface Appendable { - public fun append(csq: CharSequence?): Appendable - public fun append(csq: CharSequence?, start: Int, end: Int): Appendable - public fun append(c: Char): Appendable +interface Appendable { + fun append(csq: CharSequence?): Appendable + fun append(csq: CharSequence?, start: Int, end: Int): Appendable + fun append(c: Char): Appendable } -@library -public class StringBuilder(content: String = "") : Appendable, CharSequence { - override val length: Int = noImpl - override fun get(index: Int): Char = noImpl - override fun subSequence(start: Int, end: Int): CharSequence = noImpl - override fun append(c: Char): StringBuilder = noImpl - override fun append(csq: CharSequence?): StringBuilder = noImpl - override fun append(csq: CharSequence?, start: Int, end: Int): StringBuilder = noImpl - public fun append(obj: Any?): StringBuilder = noImpl - public fun reverse(): StringBuilder = noImpl - override fun toString(): String = noImpl -} +class StringBuilder(content: String = "") : Appendable, CharSequence { + constructor(capacity: Int) : this() {} -public inline fun StringBuilder(capacity: Int): StringBuilder = StringBuilder() -public inline fun StringBuilder(content: CharSequence): StringBuilder = StringBuilder(content.toString()) + constructor(content: CharSequence) : this(content.toString()) {} + + private var string: String = content + + override val length: Int = string.length + + override fun get(index: Int): Char = string[index] + + override fun subSequence(start: Int, end: Int): CharSequence = string.substring(start, end) + + override fun append(c: Char): StringBuilder { + string += c + return this + } + + override fun append(csq: CharSequence?): StringBuilder { + string += csq.toString() + return this + } + + override fun append(csq: CharSequence?, start: Int, end: Int): StringBuilder { + string += csq.toString().substring(start, end) + return this + } + + fun append(obj: Any?): StringBuilder { + string += obj.toString() + return this + } + + fun reverse(): StringBuilder { + val nativeString: dynamic = string + string = nativeString.split("").reverse().join("") + return this + } + + override fun toString(): String = string +} diff --git a/js/js.libraries/src/core/javautil.kt b/js/js.libraries/src/core/javautil.kt index 2fa0fd8d849..d891d72dab4 100644 --- a/js/js.libraries/src/core/javautil.kt +++ b/js/js.libraries/src/core/javautil.kt @@ -16,12 +16,11 @@ package java.util -@library -public interface Comparator { - public fun compare(a: T, b: T): Int +interface Comparator { + @JsName("compare") fun compare(a: T, b: T): Int } -public inline fun Comparator(crossinline comparison: (T, T) -> Int): Comparator = object : Comparator { +inline fun Comparator(crossinline comparison: (T, T) -> Int): Comparator = object : Comparator { override fun compare(a: T, b: T): Int = comparison(a, b) } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java index 951c323c1fe..6d56a2efc65 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java @@ -56,8 +56,8 @@ public final class Namer { public static final String EQUALS_METHOD_NAME = getStableMangledNameForDescriptor(JsPlatform.INSTANCE.getBuiltIns().getAny(), "equals"); public static final String COMPARE_TO_METHOD_NAME = getStableMangledNameForDescriptor(JsPlatform.INSTANCE.getBuiltIns().getComparable(), "compareTo"); - public static final String NUMBER_RANGE = "NumberRange"; - public static final String CHAR_RANGE = "CharRange"; + public static final String INT_RANGE = "kotlin.ranges.IntRange"; + public static final String CHAR_RANGE = "kotlin.ranges.CharRange"; public static final String LONG_FROM_NUMBER = "fromNumber"; public static final String LONG_TO_NUMBER = "toNumber"; public static final String LONG_FROM_INT = "fromInt"; @@ -380,11 +380,6 @@ public final class Namer { return result; } - @NotNull - /*package*/ JsObjectScope getKotlinScope() { - return kotlinScope; - } - @NotNull static String generatePackageName(@NotNull FqName packageFqName) { return packageFqName.isRoot() ? getRootPackageName() : packageFqName.shortName().asString(); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StandardClasses.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StandardClasses.java deleted file mode 100644 index e6c16efbf7d..00000000000 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StandardClasses.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.kotlin.js.translate.context; - -import com.google.common.collect.Maps; -import com.google.dart.compiler.backend.js.ast.JsName; -import com.google.dart.compiler.backend.js.ast.JsObjectScope; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.builtins.PrimitiveType; -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; -import org.jetbrains.kotlin.name.FqNameUnsafe; -import org.jetbrains.kotlin.name.Name; - -import java.util.Map; - -import static com.google.dart.compiler.backend.js.ast.JsScopesKt.JsObjectScope; -import static org.jetbrains.kotlin.resolve.DescriptorUtils.getFqName; - -/** - * Provides a mechanism to bind some of the Kotlin/Java declarations with library implementations. - * Makes sense only for those declaration that cannot be annotated. (Use library annotation in this case) - */ -public final class StandardClasses { - - private final class Builder { - - @Nullable - private /*var*/ FqNameUnsafe currentFQName = null; - @Nullable - private /*var*/ String currentObjectName = null; - - @NotNull - public Builder forFQ(@NotNull String classFQName) { - currentFQName = new FqNameUnsafe(classFQName); - return this; - } - - @NotNull - public Builder kotlinClass(@NotNull String kotlinName) { - kotlinTopLevelObject(kotlinName); - constructor(); - return this; - } - - private void kotlinTopLevelObject(@NotNull String kotlinName) { - assert currentFQName != null; - currentObjectName = kotlinName; - declareKotlinObject(currentFQName, kotlinName); - } - - @NotNull - private Builder constructor() { - assert currentFQName != null; - assert currentObjectName != null; - declareInner(currentFQName, "", currentObjectName); - return this; - } - - @NotNull - public Builder methods(@NotNull String... methodNames) { - assert currentFQName != null; - declareMethods(currentFQName, methodNames); - return this; - } - - @NotNull - public Builder properties(@NotNull String... propertyNames) { - assert currentFQName != null; - declareReadonlyProperties(currentFQName, propertyNames); - return this; - } - } - - @NotNull - public static StandardClasses bindImplementations(@NotNull JsObjectScope kotlinObjectScope) { - StandardClasses standardClasses = new StandardClasses(kotlinObjectScope); - declareKotlinStandardClasses(standardClasses); - return standardClasses; - } - - private static void declareKotlinStandardClasses(@NotNull StandardClasses standardClasses) { - for (PrimitiveType type : PrimitiveType.NUMBER_TYPES) { - if (type == PrimitiveType.CHAR || type == PrimitiveType.LONG) continue; - - String typeName = type.getTypeName().asString(); - standardClasses.declare().forFQ("kotlin.ranges." + typeName + "Range").kotlinClass("NumberRange"); - standardClasses.declare().forFQ("kotlin.ranges." + typeName + "Progression").kotlinClass("NumberProgression"); - } - - standardClasses.declare().forFQ("kotlin.ranges.LongRange").kotlinClass("LongRange"); - standardClasses.declare().forFQ("kotlin.ranges.CharRange").kotlinClass("CharRange"); - - standardClasses.declare().forFQ("kotlin.ranges.LongProgression").kotlinClass("LongProgression"); - standardClasses.declare().forFQ("kotlin.ranges.CharProgression").kotlinClass("CharProgression"); - - standardClasses.declare().forFQ("kotlin.Enum").kotlinClass("Enum"); - - standardClasses.declare().forFQ("kotlin.Comparable").kotlinClass("Comparable"); - - standardClasses.declare().forFQ("kotlin.Throwable").kotlinClass("Throwable"); - standardClasses.declare().forFQ("kotlin.Annotation").kotlinClass("Annotation"); - } - - - @NotNull - private final JsObjectScope kotlinScope; - - - @NotNull - private final Map standardObjects = Maps.newHashMap(); - - @NotNull - private final Map scopeMap = Maps.newHashMap(); - - private StandardClasses(@NotNull JsObjectScope kotlinScope) { - this.kotlinScope = kotlinScope; - } - - private void declareTopLevelObjectInScope(@NotNull JsObjectScope scope, @NotNull Map map, - @NotNull FqNameUnsafe fullQualifiedName, @NotNull String name) { - JsName declaredName = scope.declareName(name); - map.put(fullQualifiedName, declaredName); - scopeMap.put(fullQualifiedName, JsObjectScope(scope, "scope for " + name)); - } - - private void declareKotlinObject(@NotNull FqNameUnsafe fullQualifiedName, @NotNull String kotlinLibName) { - declareTopLevelObjectInScope(kotlinScope, standardObjects, fullQualifiedName, kotlinLibName); - } - - private void declareInner(@NotNull FqNameUnsafe fullQualifiedClassName, - @NotNull String shortMethodName, - @NotNull String javascriptName) { - JsObjectScope classScope = scopeMap.get(fullQualifiedClassName); - assert classScope != null; - FqNameUnsafe fullQualifiedMethodName = fullQualifiedClassName.child(Name.guessByFirstCharacter(shortMethodName)); - standardObjects.put(fullQualifiedMethodName, classScope.declareName(javascriptName)); - } - - private void declareMethods(@NotNull FqNameUnsafe classFQName, - @NotNull String... methodNames) { - for (String methodName : methodNames) { - declareInner(classFQName, methodName, methodName); - } - } - - private void declareReadonlyProperties(@NotNull FqNameUnsafe classFQName, - @NotNull String... propertyNames) { - for (String propertyName : propertyNames) { - declareInner(classFQName, propertyName, propertyName); - } - } - - public boolean isStandardObject(@NotNull DeclarationDescriptor descriptor) { - return standardObjects.containsKey(getFqName(descriptor)); - } - - @NotNull - public JsName getStandardObjectName(@NotNull DeclarationDescriptor descriptor) { - return standardObjects.get(getFqName(descriptor)); - } - - @NotNull - private Builder declare() { - return new Builder(); - } -} diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java index b6bf6731e94..95e41e59b02 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java @@ -35,9 +35,11 @@ import org.jetbrains.kotlin.js.naming.NameSuggestion; import org.jetbrains.kotlin.js.naming.SuggestedName; import org.jetbrains.kotlin.js.translate.context.generator.Generator; import org.jetbrains.kotlin.js.translate.context.generator.Rule; +import org.jetbrains.kotlin.js.translate.declaration.ClassTranslator; import org.jetbrains.kotlin.js.translate.intrinsic.Intrinsics; import org.jetbrains.kotlin.js.translate.utils.JsAstUtils; import org.jetbrains.kotlin.name.FqName; +import org.jetbrains.kotlin.name.FqNameUnsafe; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingTrace; @@ -65,11 +67,8 @@ public final class StaticContext { @NotNull ModuleDescriptor moduleDescriptor) { JsProgram program = new JsProgram("main"); Namer namer = Namer.newInstance(program.getRootScope()); - Intrinsics intrinsics = new Intrinsics(); - StandardClasses standardClasses = StandardClasses.bindImplementations(namer.getKotlinScope()); JsFunction rootFunction = JsAstUtils.createFunctionWithEmptyBody(program.getScope()); - return new StaticContext(program, rootFunction, bindingTrace, namer, intrinsics, standardClasses, program.getRootScope(), config, - moduleDescriptor); + return new StaticContext(program, rootFunction, bindingTrace, namer, program.getRootScope(), config, moduleDescriptor); } @NotNull @@ -83,9 +82,6 @@ public final class StaticContext { @NotNull private final Intrinsics intrinsics; - @NotNull - private final StandardClasses standardClasses; - @NotNull private final JsScope rootScope; @@ -139,6 +135,9 @@ public final class StaticContext { @NotNull private final List declarationStatements = new ArrayList(); + @NotNull + private final List topLevelStatements = new ArrayList(); + @NotNull private final List importStatements = new ArrayList(); @@ -160,8 +159,6 @@ public final class StaticContext { @NotNull JsFunction rootFunction, @NotNull BindingTrace bindingTrace, @NotNull Namer namer, - @NotNull Intrinsics intrinsics, - @NotNull StandardClasses standardClasses, @NotNull JsScope rootScope, @NotNull JsConfig config, @NotNull ModuleDescriptor moduleDescriptor @@ -170,9 +167,8 @@ public final class StaticContext { this.rootFunction = rootFunction; this.bindingTrace = bindingTrace; this.namer = namer; - this.intrinsics = intrinsics; + this.intrinsics = new Intrinsics(this); this.rootScope = rootScope; - this.standardClasses = standardClasses; this.config = config; this.currentModule = moduleDescriptor; this.rootFunction = rootFunction; @@ -247,8 +243,14 @@ public final class StaticContext { @NotNull private JsExpression buildQualifiedExpression(@NotNull DeclarationDescriptor descriptor) { - if (descriptor instanceof ClassDescriptor && KotlinBuiltIns.isAny((ClassDescriptor) descriptor)) { - return new JsNameRef("Object"); + if (descriptor instanceof ClassDescriptor) { + ClassDescriptor classDescriptor = (ClassDescriptor) descriptor; + if (KotlinBuiltIns.isAny(classDescriptor)) { + return pureFqn("Object", null); + } + if (DescriptorUtils.getFqName(classDescriptor).asString().equals("kotlin.Throwable")) { + return pureFqn("Error", null); + } } SuggestedName suggested = nameSuggestion.suggest(descriptor); @@ -259,26 +261,20 @@ public final class StaticContext { } JsExpression expression; - List partNames; - if (standardClasses.isStandardObject(suggested.getDescriptor())) { + List partNames = getActualNameFromSuggested(suggested); + if (isLibraryObject(suggested.getDescriptor())) { expression = Namer.kotlinObject(); - partNames = Collections.singletonList(standardClasses.getStandardObjectName(suggested.getDescriptor())); + } + // Don't generate qualifier for top-level native declarations + // Don't generate qualifier for local declarations + else if (isNativeObject(suggested.getDescriptor()) && !isNativeObject(suggested.getScope()) || + suggested.getDescriptor() instanceof CallableDescriptor && suggested.getScope() instanceof FunctionDescriptor) { + expression = null; } else { - partNames = getActualNameFromSuggested(suggested); - if (isLibraryObject(suggested.getDescriptor())) { - expression = Namer.kotlinObject(); - } - // Don't generate qualifier for top-level native declarations - // Don't generate qualifier for local declarations - else if (isNativeObject(suggested.getDescriptor()) && !isNativeObject(suggested.getScope()) || - suggested.getDescriptor() instanceof CallableDescriptor && suggested.getScope() instanceof FunctionDescriptor) { - expression = null; - } - else { - expression = getQualifiedExpression(suggested.getScope()); - } + expression = getQualifiedExpression(suggested.getScope()); } + for (JsName partName : partNames) { expression = new JsNameRef(partName, expression); applySideEffects(expression, suggested.getDescriptor()); @@ -408,6 +404,13 @@ public final class StaticContext { return config; } + @NotNull + public JsName importDeclaration(@NotNull String suggestedName, @NotNull JsExpression declaration) { + JsName result = rootFunction.getScope().declareFreshName(suggestedName); + importStatements.add(JsAstUtils.newVar(result, declaration)); + return result; + } + private final class InnerNameGenerator extends Generator { public InnerNameGenerator() { addRule(new Rule() { @@ -643,12 +646,13 @@ public final class StaticContext { } @NotNull - public List getDeclarationStatements() { - return declarationStatements; + public List getTopLevelStatements() { + return topLevelStatements; } - public void addRootStatement(@NotNull JsStatement statement) { - declarationStatements.add(statement); + @NotNull + public List getDeclarationStatements() { + return declarationStatements; } public void addClass(@NotNull ClassDescriptor classDescriptor) { @@ -690,9 +694,11 @@ public final class StaticContext { } public void postProcess() { + addInterfaceDefaultMethods(); rootFunction.getBody().getStatements().addAll(importStatements); addClassPrototypes(); rootFunction.getBody().getStatements().addAll(declarationStatements); + rootFunction.getBody().getStatements().addAll(topLevelStatements); JsName rootPackageName = rootFunction.getScope().declareName(Namer.getRootPackageName()); rootFunction.getBody().getStatements().add(JsAstUtils.newVar(rootPackageName, exportObject)); @@ -727,6 +733,24 @@ public final class StaticContext { } } + private void addInterfaceDefaultMethods() { + for (ClassDescriptor classDescriptor : classes) { + if (classDescriptor.getKind() != ClassKind.INTERFACE) { + ClassTranslator.addInterfaceDefaultMembers(classDescriptor, this); + } + } + } + + public boolean isBuiltinModule() { + for (ClassDescriptor cls : classes) { + FqNameUnsafe fqn = DescriptorUtils.getFqName(cls); + if ("kotlin.Enum".equals(fqn.asString())) { + return true; + } + } + return false; + } + private static class ExportedPackage { @NotNull final String name; @NotNull final Map subpackages = new HashMap(); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java index c7c5427efe0..202d21393f3 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java @@ -63,7 +63,7 @@ public class TranslationContext { @NotNull StaticContext staticContext, @NotNull JsFunction rootFunction ) { - JsBlock block = new JsBlock(staticContext.getDeclarationStatements()); + JsBlock block = new JsBlock(staticContext.getTopLevelStatements()); DynamicContext rootDynamicContext = DynamicContext.rootContext(rootFunction.getScope(), block); AliasingContext rootAliasingContext = AliasingContext.getCleanContext(); return new TranslationContext(null, staticContext, rootDynamicContext, rootAliasingContext, null, null); @@ -178,6 +178,11 @@ public class TranslationContext { return this.innerWithAliasingContext(aliasingContext.withDescriptorsAliased(aliases)); } + @NotNull + public JsName importDeclaration(@NotNull String suggestedName, @NotNull JsExpression declaration) { + return staticContext.importDeclaration(suggestedName, declaration); + } + @Nullable private JsBlock getBlockForDescriptor(@NotNull DeclarationDescriptor descriptor) { if (descriptor instanceof CallableDescriptor) { @@ -225,8 +230,8 @@ public class TranslationContext { } @NotNull - public JsName declarePropertyOrPropertyAccessorName(@NotNull DeclarationDescriptor descriptor, @NotNull String name, boolean fresh) { - return staticContext.declarePropertyOrPropertyAccessorName(descriptor, name, fresh); + public JsName declarePropertyOrPropertyAccessorName(@NotNull DeclarationDescriptor descriptor, @NotNull String name) { + return staticContext.declarePropertyOrPropertyAccessorName(descriptor, name, false); } @NotNull @@ -235,13 +240,13 @@ public class TranslationContext { } @NotNull - public JsNameRef getInnerReference(@NotNull DeclarationDescriptor descriptor) { - return JsAstUtils.pureFqn(getInnerNameForDescriptor(descriptor), null); + public JsNameRef getQualifiedReference(@NotNull FqName fqName) { + return staticContext.getQualifiedReference(fqName); } @NotNull - public JsNameRef getQualifiedReference(@NotNull FqName packageFqName) { - return staticContext.getQualifiedReference(packageFqName); + public JsNameRef getInnerReference(@NotNull DeclarationDescriptor descriptor) { + return JsAstUtils.pureFqn(getInnerNameForDescriptor(descriptor), null); } @NotNull @@ -567,14 +572,18 @@ public class TranslationContext { return staticContext.getRootFunction(); } - public void addRootStatement(@NotNull JsStatement statement) { - staticContext.addRootStatement(statement); + public void addDeclarationStatement(@NotNull JsStatement statement) { + staticContext.getDeclarationStatements().add(statement); + } + + public void addTopLevelStatement(@NotNull JsStatement statement) { + staticContext.getTopLevelStatements().add(statement); } @NotNull public JsFunction defineTopLevelFunction(@NotNull DeclarationDescriptor descriptor) { JsFunction function = createTopLevelFunction(descriptor); - addRootStatement(function.makeStmt()); + addDeclarationStatement(function.makeStmt()); return function; } @@ -584,7 +593,7 @@ public class TranslationContext { } @NotNull - public JsFunction createTopLevelFunction(@NotNull DeclarationDescriptor descriptor) { + private JsFunction createTopLevelFunction(@NotNull DeclarationDescriptor descriptor) { JsFunction function = createTopLevelAnonymousFunction(descriptor); function.setName(staticContext.getInnerNameForDescriptor(descriptor)); return function; @@ -606,4 +615,14 @@ public class TranslationContext { public boolean isFromCurrentModule(@NotNull DeclarationDescriptor descriptor) { return staticContext.getCurrentModule() == DescriptorUtilsKt.getModule(descriptor); } + + @NotNull + public ModuleDescriptor getCurrentModule() { + return staticContext.getCurrentModule(); + } + + @Nullable + public TranslationContext getParent() { + return parent; + } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt index d518498b463..c87cf9e8325 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.js.translate.initializer.ClassInitializerTranslator import org.jetbrains.kotlin.js.translate.utils.* import org.jetbrains.kotlin.js.translate.utils.BindingUtils.getClassDescriptor import org.jetbrains.kotlin.js.translate.utils.BindingUtils.getPropertyDescriptorForConstructorParameter +import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getSupertypesWithoutFakes import org.jetbrains.kotlin.js.translate.utils.PsiUtils.getPrimaryConstructorParameters import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.toInvocationWith @@ -62,15 +63,11 @@ class ClassTranslator private constructor( private lateinit var cachedInstanceName: JsName private val metadataLiteral = JsObjectLiteral(true) - private fun translate() { - generateClassCreateInvocationArguments() - } - private fun isTrait(): Boolean = descriptor.kind == ClassKind.INTERFACE private fun isAnnotation(): Boolean = descriptor.kind == ClassKind.ANNOTATION_CLASS - private fun generateClassCreateInvocationArguments() { + private fun translate() { val scope = context().getScopeForDescriptor(descriptor) val context = context().newDeclaration(descriptor) @@ -92,10 +89,6 @@ class ClassTranslator private constructor( addSuperclassReferences() classDeclaration.getSecondaryConstructors().forEach { generateSecondaryConstructor(context, it) } - if (descriptor.kind != ClassKind.INTERFACE) { - addInterfaceDefaultMembers() - } - generatedBridgeMethods() if (descriptor.isData) { @@ -148,7 +141,7 @@ class ClassTranslator private constructor( } private fun addMetadataObject() { - context().addRootStatement(JsAstUtils.assignment(createMetadataRef(), metadataLiteral).makeStmt()) + context().addDeclarationStatement(JsAstUtils.assignment(createMetadataRef(), metadataLiteral).makeStmt()) } private fun createMetadataRef() = JsNameRef(Namer.METADATA, context().getInnerReference(descriptor)) @@ -247,6 +240,10 @@ class ClassTranslator private constructor( } secondaryConstructors += ConstructorInfo(constructorInitializer, context, constructorDescriptor, compositeSuperCallGenerator) + + if (DescriptorUtils.isTopLevelDeclaration(classDescriptor)) { + context.export(constructorDescriptor) + } } private val allConstructors: Sequence @@ -378,58 +375,13 @@ class ClassTranslator private constructor( } } - private fun addInterfaceDefaultMembers() { - val members = descriptor.unsubstitutedMemberScope - .getContributedDescriptors(DescriptorKindFilter.FUNCTIONS) - .mapNotNull { it as? CallableMemberDescriptor } - for (member in members) { - if (member.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE) continue - if (member.modality == Modality.ABSTRACT || member.overriddenDescriptors.size != 1) continue - - val overriddenFunction = generateSequence(member) { it.overriddenDescriptors.firstOrNull() } - .drop(1) - .dropWhile { it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE && - DescriptorUtils.isInterface(it.containingDeclaration) } - .firstOrNull() ?: continue - - val interfaceDescriptor = overriddenFunction.containingDeclaration as ClassDescriptor - if (interfaceDescriptor.kind != ClassKind.INTERFACE) continue - - when (member) { - is FunctionDescriptor -> addDefaultMethodFromInterface(member, interfaceDescriptor) - is PropertyDescriptor -> addDefaultPropertyFromInterface(member, interfaceDescriptor) - } - } - } - - private fun addDefaultMethodFromInterface(function: FunctionDescriptor, interfaceDescriptor: ClassDescriptor) { - val classPrototype = JsAstUtils.prototypeOf(context().getInnerReference(descriptor)) - val interfacePrototype = JsAstUtils.prototypeOf(context().getInnerReference(interfaceDescriptor)) - val functionName = context().getNameForDescriptor(function) - val classFunction = JsNameRef(functionName, classPrototype) - val interfaceFunction = JsNameRef(functionName, interfacePrototype) - context().addRootStatement(JsAstUtils.assignment(classFunction, interfaceFunction).makeStmt()) - } - - private fun addDefaultPropertyFromInterface(property: PropertyDescriptor, interfaceDescriptor: ClassDescriptor) { - val classPrototype = JsAstUtils.prototypeOf(context().getInnerReference(descriptor)) - val interfacePrototype = JsAstUtils.prototypeOf(context().getInnerReference(interfaceDescriptor)) - val functionName = context().getNameForDescriptor(property) - val nameLiteral = context().program().getStringLiteral(functionName.ident) - - val getPropertyDescriptor = JsInvocation(JsNameRef("getOwnPropertyDescriptor", "Object"), interfacePrototype, nameLiteral) - val defineProperty = JsAstUtils.defineProperty(classPrototype, functionName.ident, getPropertyDescriptor, context().program()) - - context().addRootStatement(defineProperty.makeStmt()) - } - private fun addObjectCache(statements: MutableList) { cachedInstanceName = context().createGlobalName(StaticContext.getSuggestedName(descriptor) + Namer.OBJECT_INSTANCE_VAR_SUFFIX) statements += JsAstUtils.assignment(cachedInstanceName.makeRef(), JsObjectLiteral.THIS).makeStmt() } private fun addObjectMethods() { - context().addRootStatement(JsAstUtils.newVar(cachedInstanceName, JsLiteral.NULL)) + context().addDeclarationStatement(JsAstUtils.newVar(cachedInstanceName, JsLiteral.NULL)) val instanceFun = JsFunction(context().rootFunction.scope, JsBlock(), "Instance function: " + descriptor) instanceFun.name = context().getNameForObjectInstance(descriptor) @@ -444,7 +396,7 @@ class ClassTranslator private constructor( instanceFun.body.statements += JsReturn(cachedInstanceName.makeRef()) - context().addRootStatement(instanceFun.makeStmt()) + context().addDeclarationStatement(instanceFun.makeStmt()) } private fun generatedBridgeMethods() { @@ -499,6 +451,61 @@ class ClassTranslator private constructor( @JvmStatic fun translate(classDeclaration: KtClassOrObject, context: TranslationContext) { return ClassTranslator(classDeclaration, context).translate() } + + @JvmStatic fun addInterfaceDefaultMembers(descriptor: ClassDescriptor, context: StaticContext) { + val members = descriptor.unsubstitutedMemberScope + .getContributedDescriptors(DescriptorKindFilter.FUNCTIONS) + .mapNotNull { it as? CallableMemberDescriptor } + for (member in members) { + if (member.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE) continue + if (member.modality == Modality.ABSTRACT || member.overriddenDescriptors.size != 1) continue + + val overriddenFunction = generateSequence(member) { it.overriddenDescriptors.firstOrNull() } + .drop(1) + .dropWhile { it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE && + DescriptorUtils.isInterface(it.containingDeclaration) } + .firstOrNull() ?: continue + + val interfaceDescriptor = overriddenFunction.containingDeclaration as ClassDescriptor + if (interfaceDescriptor.kind != ClassKind.INTERFACE) continue + + when (member) { + is FunctionDescriptor -> addDefaultMethodFromInterface(member, interfaceDescriptor, descriptor, context) + is PropertyDescriptor -> addDefaultPropertyFromInterface(member, interfaceDescriptor, descriptor, context) + } + } + } + + private fun addDefaultMethodFromInterface( + function: FunctionDescriptor, + interfaceDescriptor: ClassDescriptor, + descriptor: ClassDescriptor, + context: StaticContext + ) { + val classPrototype = JsAstUtils.prototypeOf(pureFqn(context.getInnerNameForDescriptor(descriptor), null)) + val interfacePrototype = JsAstUtils.prototypeOf(pureFqn(context.getInnerNameForDescriptor(interfaceDescriptor), null)) + val functionName = context.getNameForDescriptor(function) + val classFunction = JsNameRef(functionName, classPrototype) + val interfaceFunction = JsNameRef(functionName, interfacePrototype) + context.declarationStatements += JsAstUtils.assignment(classFunction, interfaceFunction).makeStmt() + } + + private fun addDefaultPropertyFromInterface( + property: PropertyDescriptor, + interfaceDescriptor: ClassDescriptor, + descriptor: ClassDescriptor, + context: StaticContext + ) { + val classPrototype = JsAstUtils.prototypeOf(pureFqn(context.getInnerNameForDescriptor(descriptor), null)) + val interfacePrototype = JsAstUtils.prototypeOf(pureFqn(context.getInnerNameForDescriptor(interfaceDescriptor), null)) + val functionName = context.getNameForDescriptor(property) + val nameLiteral = context.program.getStringLiteral(functionName.ident) + + val getPropertyDescriptor = JsInvocation(JsNameRef("getOwnPropertyDescriptor", "Object"), interfacePrototype, nameLiteral) + val defineProperty = JsAstUtils.defineProperty(classPrototype, functionName.ident, getPropertyDescriptor, context.program) + + context.declarationStatements += defineProperty.makeStmt() + } } private class ConstructorInfo( diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.kt index fcaee0d6450..a5850e50257 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.kt @@ -67,14 +67,14 @@ class DeclarationBodyVisitor( val enumInstanceFunction = context.createTopLevelAnonymousFunction(descriptor) enumInstanceFunction.name = context.getNameForObjectInstance(descriptor) - context.addRootStatement(enumInstanceFunction.makeStmt()) + context.addDeclarationStatement(enumInstanceFunction.makeStmt()) val classRef = context.getInnerReference(descriptor.containingDeclaration) val enumExtName = context.getNameForDescriptor(descriptor) val enumExtFq = JsNameRef(enumExtName, classRef) - context.addRootStatement(JsAstUtils.assignment(enumExtFq, enumInstanceFunction.name.makeRef()).makeStmt()) + context.addDeclarationStatement(JsAstUtils.assignment(enumExtFq, enumInstanceFunction.name.makeRef()).makeStmt()) - context.addRootStatement(JsAstUtils.newVar(enumInstanceName, jsEnumEntryCreation)) + context.addDeclarationStatement(JsAstUtils.newVar(enumInstanceName, jsEnumEntryCreation)) enumInstanceFunction.body.statements.add(JsReturn(enumInstanceName.makeRef())) } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DefineInvocation.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DefineInvocation.java deleted file mode 100644 index af97cde2746..00000000000 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DefineInvocation.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.kotlin.js.translate.declaration; - -import com.google.dart.compiler.backend.js.ast.*; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.js.translate.context.TranslationContext; -import org.jetbrains.kotlin.js.translate.utils.JsAstUtils; -import org.jetbrains.kotlin.name.FqName; - -import java.util.AbstractList; -import java.util.List; - -public class DefineInvocation { - - /* package */ - @NotNull - static DefineInvocation create( - @NotNull FqName packageFqName, - @Nullable JsExpression initializer, - @NotNull JsObjectLiteral members, - @NotNull TranslationContext context - ) { - return new DefineInvocation(initializer == null ? JsLiteral.NULL : initializer, - new JsDocComment(JsAstUtils.LENDS_JS_DOC_TAG, context.getQualifiedReference(packageFqName)), - members); - } - - @NotNull - private JsExpression initializer; - @NotNull - private final JsDocComment jsDocComment; - @NotNull - private final JsObjectLiteral membersObjectLiteral; - - private DefineInvocation( - @NotNull JsExpression initializer, - @NotNull JsDocComment jsDocComment, - @NotNull JsObjectLiteral membersObjectLiteral - ) { - this.initializer = initializer; - this.jsDocComment = jsDocComment; - this.membersObjectLiteral = membersObjectLiteral; - } - - @NotNull - public JsExpression getInitializer() { - return initializer; - } - - public void setInitializer(@NotNull JsExpression initializer) { - this.initializer = initializer; - } - - @NotNull - public List getMembers() { - return membersObjectLiteral.getPropertyInitializers(); - } - - @NotNull - public List asList() { - return new AbstractList() { // because initializer is mutable - @NotNull - @Override - public JsExpression get(int index) { - switch (index) { - case 0: - return initializer; - case 1: - return jsDocComment; - case 2: - return membersObjectLiteral; - } - throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size()); - } - - @Override - public int size() { - return 3; - } - }; - } - -} diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/FileDeclarationVisitor.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/FileDeclarationVisitor.kt index 33a80152be8..f2be3e1cbf4 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/FileDeclarationVisitor.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/FileDeclarationVisitor.kt @@ -37,7 +37,10 @@ class FileDeclarationVisitor(private val context: TranslationContext) : Abstract val backingFieldRequired = context.bindingContext()[BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor] ?: false if (backingFieldRequired || expression.delegateExpression != null) { val initializer = expression.delegateExpressionOrInitializer?.let { Translation.translateAsExpression(it, context) } - context.addRootStatement(JsAstUtils.newVar(innerName, initializer)) + context.addDeclarationStatement(JsAstUtils.newVar(innerName, null)) + if (initializer != null) { + context.addTopLevelStatement(JsAstUtils.assignment(innerName.makeRef(), initializer).makeStmt()) + } } super.visitProperty(expression, context) @@ -71,10 +74,10 @@ class FileDeclarationVisitor(private val context: TranslationContext) : Abstract when (expression) { is JsFunction -> { expression.name = name - context.addRootStatement(expression.makeStmt()) + context.addDeclarationStatement(expression.makeStmt()) } else -> { - context.addRootStatement(JsAstUtils.newVar(name, expression)) + context.addDeclarationStatement(JsAstUtils.newVar(name, expression)) } } return name diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/LiteralFunctionTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/LiteralFunctionTranslator.kt index ddb45dff492..2926152e1d6 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/LiteralFunctionTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/LiteralFunctionTranslator.kt @@ -78,7 +78,7 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato lambda.isLocal = true - context().addRootStatement(lambda.makeStmt()) + context().addDeclarationStatement(lambda.makeStmt()) return lambda.name.makeRef().apply { sideEffects = SideEffectKind.PURE } } @@ -96,7 +96,7 @@ fun JsFunction.withCapturedParameters( context: TranslationContext, invokingContext: TranslationContext ): JsExpression { - context.addRootStatement(makeStmt()) + context.addDeclarationStatement(makeStmt()) val ref = name.makeRef().apply { sideEffects = SideEffectKind.PURE } val invocation = JsInvocation(ref).apply { sideEffects = SideEffectKind.PURE } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Translation.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Translation.java index dbe65b8c70d..59492220816 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Translation.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Translation.java @@ -263,7 +263,9 @@ public final class Translation { PackageDeclarationTranslator.translateFiles(files, context); staticContext.postProcess(); statements.add(0, program.getStringLiteral("use strict").makeStmt()); - defineModule(context, statements, config.getModuleId()); + if (!staticContext.isBuiltinModule()) { + defineModule(context, statements, config.getModuleId()); + } mayBeGenerateTests(files, config, rootBlock, context); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/Intrinsics.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/Intrinsics.java index e6aa3166f42..a010936b3d2 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/Intrinsics.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/Intrinsics.java @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.js.translate.intrinsic; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.descriptors.ClassDescriptor; import org.jetbrains.kotlin.descriptors.FunctionDescriptor; +import org.jetbrains.kotlin.js.translate.context.StaticContext; import org.jetbrains.kotlin.js.translate.context.TranslationContext; import org.jetbrains.kotlin.js.translate.intrinsic.functions.FunctionIntrinsics; import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsic; @@ -34,7 +35,11 @@ import org.jetbrains.kotlin.psi.KtBinaryExpression; public final class Intrinsics { private final FunctionIntrinsics functionIntrinsics = new FunctionIntrinsics(); private final BinaryOperationIntrinsics binaryOperationIntrinsics = new BinaryOperationIntrinsics(); - private final ObjectIntrinsics objectIntrinsics = new ObjectIntrinsics(); + private final ObjectIntrinsics objectIntrinsics; + + public Intrinsics(@NotNull StaticContext staticContext) { + objectIntrinsics = new ObjectIntrinsics(staticContext); + } @NotNull public BinaryOperationIntrinsic getBinaryOperationIntrinsic( diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/FunctionIntrinsics.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/FunctionIntrinsics.java index c38c7095fc4..a6291b05b60 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/FunctionIntrinsics.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/FunctionIntrinsics.java @@ -43,7 +43,7 @@ public final class FunctionIntrinsics { register(LongOperationFIF.INSTANCE); register(PrimitiveUnaryOperationFIF.INSTANCE); register(PrimitiveBinaryOperationFIF.INSTANCE); - register(StringOperationFIF.INSTANCE); + //register(StringOperationFIF.INSTANCE); register(ArrayFIF.INSTANCE); register(TopLevelFIF.INSTANCE); register(NumberAndCharConversionFIF.INSTANCE); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/basic/FqnCallIntrinsic.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/basic/FqnCallIntrinsic.kt new file mode 100644 index 00000000000..884fb145605 --- /dev/null +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/basic/FqnCallIntrinsic.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.js.translate.intrinsic.functions.basic + +import com.google.dart.compiler.backend.js.ast.JsExpression +import org.jetbrains.kotlin.js.translate.context.Namer +import org.jetbrains.kotlin.js.translate.context.TranslationContext +import org.jetbrains.kotlin.js.translate.utils.JsAstUtils +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter + +class FqnCallIntrinsic( + simpleName: String, + fqn: String, + isConstructor: Boolean = false, + receiverAsArgument: Boolean = true +) : LazyImportedCallIntrinsic(simpleName, isConstructor = isConstructor, receiverAsArgument = receiverAsArgument) { + val fqn = FqName(fqn) + + override fun getExpression(context: TranslationContext): JsExpression { + val packageDescriptor = context.currentModule.getPackage(fqn.parent()) + + // Hack to compile stdlib + val descriptors = packageDescriptor.memberScope.getContributedDescriptors(DescriptorKindFilter.ALL) { + it.asString() == fqn.shortName().asString() + } + + return if (descriptors.size == 1) { + JsAstUtils.replaceRootReference(context.getQualifiedReference(fqn), Namer.kotlinObject()) + } + else { + context.getInnerReference(descriptors.first()) + } + } +} \ No newline at end of file diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/basic/LazyImportedCallIntrinsic.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/basic/LazyImportedCallIntrinsic.kt new file mode 100644 index 00000000000..642d34937af --- /dev/null +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/basic/LazyImportedCallIntrinsic.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.js.translate.intrinsic.functions.basic + +import com.google.dart.compiler.backend.js.ast.* +import org.jetbrains.kotlin.js.translate.context.TranslationContext +import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn +import org.jetbrains.kotlin.utils.singletonOrEmptyList +import java.util.* + +abstract class LazyImportedCallIntrinsic( + val simpleName: String, + val isConstructor: Boolean = false, + val receiverAsArgument: Boolean = true +) : FunctionIntrinsic() { + private val internalNameMap = WeakHashMap() + + override fun apply(receiver: JsExpression?, arguments: MutableList, context: TranslationContext): JsExpression { + val rootContext = generateSequence(context) { it.parent }.last() + val functionName = internalNameMap.getOrPut(rootContext) { + val declaration = getExpression(rootContext) + if (declaration is JsNameRef && declaration.name != null && declaration.qualifier == null) { + declaration.name!! + } + else { + rootContext.importDeclaration(simpleName, declaration) + } + } + val allArguments = (if (receiverAsArgument) receiver else null).singletonOrEmptyList() + arguments + val function = pureFqn(functionName, null) + return if (isConstructor) JsNew(function, allArguments) else JsInvocation(function, allArguments) + } + + abstract fun getExpression(context: TranslationContext): JsExpression +} \ No newline at end of file diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/LongOperationFIF.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/LongOperationFIF.kt index 80d659073ec..f04c7a695b0 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/LongOperationFIF.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/LongOperationFIF.kt @@ -60,7 +60,6 @@ object LongOperationFIF : FunctionIntrinsicFactory { private val floatBinaryIntrinsics: Map = mapOf( "compareTo" to BaseBinaryIntrinsic(::primitiveCompareTo), - "rangeTo" to BaseBinaryIntrinsic(::numberRangeTo), "plus" to BaseBinaryIntrinsic(::sum), "minus" to BaseBinaryIntrinsic(::subtract), "times" to BaseBinaryIntrinsic(::mul), diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/PrimitiveBinaryOperationFIF.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/PrimitiveBinaryOperationFIF.java index afec170115f..469edb8177a 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/PrimitiveBinaryOperationFIF.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/PrimitiveBinaryOperationFIF.java @@ -28,7 +28,9 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.descriptors.FunctionDescriptor; import org.jetbrains.kotlin.js.patterns.DescriptorPredicate; import org.jetbrains.kotlin.js.patterns.NamePredicate; +import org.jetbrains.kotlin.js.translate.context.Namer; import org.jetbrains.kotlin.js.translate.context.TranslationContext; +import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FqnCallIntrinsic; import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsic; import org.jetbrains.kotlin.js.translate.operation.OperatorTable; import org.jetbrains.kotlin.js.translate.utils.JsAstUtils; @@ -61,24 +63,10 @@ public enum PrimitiveBinaryOperationFIF implements FunctionIntrinsicFactory { } @NotNull - private static final BinaryOperationIntrinsicBase RANGE_TO_INTRINSIC = new BinaryOperationIntrinsicBase() { - @NotNull - @Override - public JsExpression doApply(@NotNull JsExpression left, @NotNull JsExpression right, @NotNull TranslationContext context) { - //TODO: add tests and correct expression for reversed ranges. - return JsAstUtils.numberRangeTo(left, right); - } - }; + private static final FunctionIntrinsic RANGE_TO_INTRINSIC = new FqnCallIntrinsic("IntRange", Namer.INT_RANGE, true, true); @NotNull - private static final BinaryOperationIntrinsicBase CHAR_RANGE_TO_INTRINSIC = new BinaryOperationIntrinsicBase() { - @NotNull - @Override - public JsExpression doApply(@NotNull JsExpression left, @NotNull JsExpression right, @NotNull TranslationContext context) { - //TODO: add tests and correct expression for reversed ranges. - return JsAstUtils.charRangeTo(left, right); - } - }; + private static final FunctionIntrinsic CHAR_RANGE_TO_INTRINSIC = new FqnCallIntrinsic("CharRange", Namer.CHAR_RANGE, true, true); @NotNull private static final BinaryOperationIntrinsicBase INTEGER_DIVISION_INTRINSIC = new BinaryOperationIntrinsicBase() { diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/ProgressionCompanionFIF.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/ProgressionCompanionFIF.kt index d31a7707844..4d93d06f931 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/ProgressionCompanionFIF.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/ProgressionCompanionFIF.kt @@ -21,24 +21,23 @@ import com.google.dart.compiler.backend.js.ast.JsNew import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.js.patterns.PatternBuilder.pattern import org.jetbrains.kotlin.js.translate.context.TranslationContext +import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FqnCallIntrinsic import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsic object ProgressionCompanionFIF : CompositeFIF() { init { - val numberProgressionConstructor = CallProgressionConstructorIntrinsic("NumberProgression") - for (type in arrayOf(PrimitiveType.BYTE, PrimitiveType.SHORT, PrimitiveType.INT)) { + val numberProgressionConstructor = FqnCallIntrinsic("IntProgression", "kotlin.ranges.IntProgression", isConstructor = true, + receiverAsArgument = false) + for (type in arrayOf(PrimitiveType.INT)) { add(methodPattern("${type.typeName}Progression"), numberProgressionConstructor) } - add(methodPattern("LongProgression"), CallProgressionConstructorIntrinsic("LongProgression")) - add(methodPattern("CharProgression"), CallProgressionConstructorIntrinsic("CharProgression")) - } - - private fun methodPattern(builtinProgressionName: String) = pattern("kotlin.ranges", builtinProgressionName, "Companion", "fromClosedRange") - - private class CallProgressionConstructorIntrinsic(val libraryProgressionName: String) : FunctionIntrinsic() { - override fun apply(receiver: JsExpression?, arguments: MutableList, context: TranslationContext): JsExpression - = JsNew(context.namer().kotlin(libraryProgressionName), arguments) + add(methodPattern("LongProgression"), FqnCallIntrinsic("LongProgression", "kotlin.ranges.LongProgression", isConstructor = true, + receiverAsArgument = false)) + add(methodPattern("CharProgression"), FqnCallIntrinsic("CharProgression", "kotlin.ranges.CharProgression", isConstructor = true, + receiverAsArgument = false)) } + private fun methodPattern(builtinProgressionName: String) = + pattern("kotlin.ranges", builtinProgressionName, "Companion", "fromClosedRange") } \ No newline at end of file diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/StringOperationFIF.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/StringOperationFIF.java deleted file mode 100644 index e9710693284..00000000000 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/StringOperationFIF.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.kotlin.js.translate.intrinsic.functions.factories; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.BuiltInFunctionIntrinsic; - -import static org.jetbrains.kotlin.js.patterns.PatternBuilder.pattern; - -public final class StringOperationFIF extends CompositeFIF { - @NotNull - public static final FunctionIntrinsicFactory INSTANCE = new StringOperationFIF(); - - private StringOperationFIF() { - add(pattern("kotlin", "CharSequence", "get").checkOverridden(), new BuiltInFunctionIntrinsic("charAt")); - add(pattern("kotlin", "CharSequence", "").checkOverridden(), LENGTH_PROPERTY_INTRINSIC); - add(pattern("kotlin", "CharSequence", "subSequence").checkOverridden(), new BuiltInFunctionIntrinsic("substring")); - } -} diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/objects/objectsIntrinsics.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/objects/objectsIntrinsics.kt index d19d74e21b7..1201edc0e5c 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/objects/objectsIntrinsics.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/objects/objectsIntrinsics.kt @@ -17,29 +17,37 @@ package org.jetbrains.kotlin.js.translate.intrinsic.objects import com.google.dart.compiler.backend.js.ast.JsExpression +import com.google.dart.compiler.backend.js.ast.JsName import org.jetbrains.kotlin.builtins.CompanionObjectMapping import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.js.translate.context.Namer +import org.jetbrains.kotlin.js.translate.context.StaticContext import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.utils.JsAstUtils import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name -class DefaultClassObjectIntrinsic(val fqName: FqName): ObjectIntrinsic { - override fun apply(context: TranslationContext): JsExpression { - val nameRef = context.getQualifiedReference(fqName) - return JsAstUtils.replaceRootReference(nameRef, Namer.kotlinObject()) +class DefaultClassObjectIntrinsic(val staticContext: StaticContext, val fqName: FqName): ObjectIntrinsic { + private val innerName: JsName by lazy { + val declaration = JsAstUtils.replaceRootReference(staticContext.getQualifiedReference(fqName), Namer.kotlinObject()) + staticContext.importDeclaration(fqName.shortName().asString(), declaration) } + + override fun apply(context: TranslationContext) = JsAstUtils.pureFqn(innerName, null) } -class ObjectIntrinsics { - fun getIntrinsic(classDescriptor: ClassDescriptor): ObjectIntrinsic { +class ObjectIntrinsics(private val staticContext: StaticContext) { + private val cache = mutableMapOf() + + fun getIntrinsic(classDescriptor: ClassDescriptor) = cache.getOrPut(classDescriptor) { createIntrinsic(classDescriptor) } + + private fun createIntrinsic(classDescriptor: ClassDescriptor): ObjectIntrinsic { if (!CompanionObjectMapping.isMappedIntrinsicCompanionObject(classDescriptor)) return NO_OBJECT_INTRINSIC val containingDeclaration = classDescriptor.containingDeclaration val name = Name.identifier(containingDeclaration.name.asString() + "CompanionObject") - return DefaultClassObjectIntrinsic(FqName("kotlin.js.internal").child(name)); + return DefaultClassObjectIntrinsic(staticContext, FqName("kotlin.js.internal").child(name)) } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsAstUtils.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsAstUtils.java index 4b1b84f3971..da1d7e5959b 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsAstUtils.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsAstUtils.java @@ -172,24 +172,6 @@ public final class JsAstUtils { return invokeKotlinFunction(Namer.PRIMITIVE_COMPARE_TO, left, right); } - @NotNull - private static JsExpression rangeTo(@NotNull String rangeClassName, @NotNull JsExpression rangeStart, @NotNull JsExpression rangeEnd) { - JsNameRef expr = pureFqn(rangeClassName, Namer.kotlinObject()); - JsNew numberRangeConstructorInvocation = new JsNew(expr); - setArguments(numberRangeConstructorInvocation, rangeStart, rangeEnd); - return numberRangeConstructorInvocation; - } - - @NotNull - public static JsExpression numberRangeTo(@NotNull JsExpression rangeStart, @NotNull JsExpression rangeEnd) { - return rangeTo(Namer.NUMBER_RANGE, rangeStart, rangeEnd); - } - - @NotNull - public static JsExpression charRangeTo(@NotNull JsExpression rangeStart, @NotNull JsExpression rangeEnd) { - return rangeTo(Namer.CHAR_RANGE, rangeStart, rangeEnd); - } - public static JsExpression newLong(long value, @NotNull TranslationContext context) { if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) { int low = (int) value; diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java index c7b41f8116b..77932f35f7d 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java @@ -154,7 +154,7 @@ public final class TranslationUtils { if (!JsDescriptorUtils.isSimpleFinalProperty(descriptor) && !(containingDescriptor instanceof PackageFragmentDescriptor)) { JsName backingFieldMangledName = context.getNameForBackingField(descriptor); - backingFieldName = context.declarePropertyOrPropertyAccessorName(descriptor, backingFieldMangledName.getIdent(), false); + backingFieldName = context.declarePropertyOrPropertyAccessorName(descriptor, backingFieldMangledName.getIdent()); } JsExpression receiver; diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt index ff354ea8aa2..04aa876a077 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt @@ -107,7 +107,7 @@ fun getReferenceToJsClass(type: KotlinType, context: TranslationContext): JsName fun TranslationContext.addFunctionToPrototype(classDescriptor: ClassDescriptor, descriptor: FunctionDescriptor, function: JsExpression) { val prototypeRef = JsAstUtils.prototypeOf(getInnerReference(classDescriptor)) val functionRef = JsNameRef(getNameForDescriptor(descriptor), prototypeRef) - addRootStatement(JsAstUtils.assignment(functionRef, function).makeStmt()) + addDeclarationStatement(JsAstUtils.assignment(functionRef, function).makeStmt()) } fun TranslationContext.addAccessorsToPrototype( @@ -118,5 +118,5 @@ fun TranslationContext.addAccessorsToPrototype( val prototypeRef = JsAstUtils.prototypeOf(getInnerReference(containingClass)) val propertyName = getNameForDescriptor(propertyDescriptor) val defineProperty = JsAstUtils.defineProperty(prototypeRef, propertyName.ident, literal, program()) - addRootStatement(defineProperty.makeStmt()) + addDeclarationStatement(defineProperty.makeStmt()) } \ No newline at end of file diff --git a/js/js.translator/testData/kotlin_lib.js b/js/js.translator/testData/kotlin_lib.js index b9e8c4c5e8d..9e38aec4ca8 100644 --- a/js/js.translator/testData/kotlin_lib.js +++ b/js/js.translator/testData/kotlin_lib.js @@ -17,8 +17,6 @@ (function (Kotlin) { "use strict"; - var CharSequence = Kotlin.createTraitNow(null); - // Shims for String if (typeof String.prototype.startsWith === "undefined") { String.prototype.startsWith = function(searchString, position) { @@ -197,59 +195,23 @@ }; Kotlin.intUpto = function (from, to) { - return new Kotlin.NumberRange(from, to); + return new Kotlin.kotlin.ranges.IntRange(from, to); }; Kotlin.intDownto = function (from, to) { - return new Kotlin.Progression(from, to, -1); + return new Kotlin.kotlin.ranges.IntProgression(from, to, -1); }; Kotlin.Throwable = Error; - - function createClassNowWithMessage(base) { - return Kotlin.createClassNow(base, - /** @constructs */ - function (message) { - this.message = (message !== void 0) ? message : null; - } - ); - } - - Kotlin.Error = createClassNowWithMessage(Kotlin.Throwable); - Kotlin.Exception = createClassNowWithMessage(Kotlin.Throwable); - Kotlin.RuntimeException = createClassNowWithMessage(Kotlin.Exception); - Kotlin.NullPointerException = createClassNowWithMessage(Kotlin.RuntimeException); - Kotlin.NoSuchElementException = createClassNowWithMessage(Kotlin.RuntimeException); - Kotlin.IllegalArgumentException = createClassNowWithMessage(Kotlin.RuntimeException); - Kotlin.IllegalStateException = createClassNowWithMessage(Kotlin.RuntimeException); - Kotlin.UnsupportedOperationException = createClassNowWithMessage(Kotlin.RuntimeException); - Kotlin.IndexOutOfBoundsException = createClassNowWithMessage(Kotlin.RuntimeException); - Kotlin.ConcurrentModificationException = createClassNowWithMessage(Kotlin.RuntimeException); - Kotlin.ClassCastException = createClassNowWithMessage(Kotlin.RuntimeException); - Kotlin.AssertionError = createClassNowWithMessage(Kotlin.Error); - Kotlin.throwNPE = function (message) { - throw new Kotlin.NullPointerException(message); + throw new Kotlin.kotlin.ranges.NullPointerException(message); }; Kotlin.throwCCE = function () { - throw new Kotlin.ClassCastException("Illegal cast"); + throw new Kotlin.kotlin.ClassCastException("Illegal cast"); }; - function throwAbstractFunctionInvocationError(funName) { - return function () { - var message; - if (funName !== void 0) { - message = "Function " + funName + " is abstract"; - } - else { - message = "Function is abstract"; - } - throw new TypeError(message); - }; - } - /** @const */ var POW_2_32 = 4294967296; // TODO: consider switching to Symbol type once we are on ES6. @@ -273,88 +235,12 @@ return hash; } - var lazyInitClasses = {}; - - /** - * @class - * @implements {Kotlin.Iterator.} - * - * @constructor - * @param {Array.} array - * @template T - */ - lazyInitClasses.ArrayIterator = Kotlin.createClass( - function () { - return [Kotlin.kotlin.collections.MutableIterator]; - }, - /** @constructs */ - function (array) { - this.array = array; - this.index = 0; - }, - /** @lends {ArrayIterator.prototype} */ - { - next: function () { - return this.array[this.index++]; - }, - hasNext: function () { - return this.index < this.array.length; - }, - remove: function () { - if (this.index < 0 || this.index > this.array.length) throw new RangeError(); - this.index--; - this.array.splice(this.index, 1); - } - }); - - lazyInitClasses.Enum = Kotlin.createClass( - function() { - return [Kotlin.Comparable]; - }, - function () { - this.name$ = void 0; - this.ordinal$ = void 0; - }, { - name: { - get: function () { - return this.name$; - } - }, - ordinal: { - get: function () { - return this.ordinal$; - } - }, - equals_za3rmp$: function (o) { - return this === o; - }, - hashCode: function () { - return getObjectHashCode(this); - }, - compareTo_za3rmp$: function (o) { - return this.ordinal$ < o.ordinal$ ? -1 : this.ordinal$ > o.ordinal$ ? 1 : 0; - }, - toString: function () { - return this.name; - } - } - ); - Kotlin.PropertyMetadata = Kotlin.createClassNow(null, function (name) { this.name = name; } ); - - Kotlin.Comparable = Kotlin.createTraitNow(null, null, { - compareTo: throwAbstractFunctionInvocationError("Comparable#compareTo") - }); - - Kotlin.Appendable = Kotlin.createTraitNow(null, null, { - append: throwAbstractFunctionInvocationError("Appendable#append") - }); - Kotlin.safeParseInt = function (str) { var r = parseInt(str, 10); return isNaN(r) ? null : r; @@ -502,306 +388,21 @@ Kotlin.out.print(s); }; - lazyInitClasses.RangeIterator = Kotlin.createClass( - function () { - return [Kotlin.kotlin.collections.Iterator]; - }, - function (start, end, step) { - this.start = start; - this.end = end; - this.step = step; - this.i = start; - }, { - next: function () { - var value = this.i; - this.i = this.i + this.step; - return value; - }, - hasNext: function () { - if (this.step > 0) - return this.i <= this.end; - else - return this.i >= this.end; + Kotlin.collectionsMax = function (c, comp) { + if (c.isEmpty()) { + //TODO: which exception? + throw new Error(); + } + var it = c.iterator(); + var max = it.next(); + while (it.hasNext()) { + var el = it.next(); + if (comp.compare(max, el) < 0) { + max = el; } - }); - - function isSameNotNullRanges(other) { - var classObject = this.constructor; - if (this instanceof classObject && other instanceof classObject) { - return this.isEmpty() && other.isEmpty() || - (this.first === other.first && this.last === other.last && this.step === other.step); } - return false; - } - - function isSameLongRanges(other) { - var classObject = this.constructor; - if (this instanceof classObject && other instanceof classObject) { - return this.isEmpty() && other.isEmpty() || - (this.first.equals_za3rmp$(other.first) && this.last.equals_za3rmp$(other.last) && this.step.equals_za3rmp$(other.step)); - } - return false; - } - - // reference implementation in core/builtins/src/kotlin/internal/progressionUtil.kt - function getProgressionFinalElement(start, end, step) { - function mod(a, b) { - var mod = a % b; - return mod >= 0 ? mod : mod + b; - } - function differenceModulo(a, b, c) { - return mod(mod(a, c) - mod(b, c), c); - } - - if (step > 0) { - return end - differenceModulo(end, start, step); - } - else if (step < 0) { - return end + differenceModulo(start, end, -step); - } - else { - throw new Kotlin.IllegalArgumentException('Step is zero.'); - } - } - - // reference implementation in core/builtins/src/kotlin/internal/progressionUtil.kt - function getProgressionFinalElementLong(start, end, step) { - function mod(a, b) { - var mod = a.modulo(b); - return !mod.isNegative() ? mod : mod.add(b); - } - function differenceModulo(a, b, c) { - return mod(mod(a, c).subtract(mod(b, c)), c); - } - - var diff; - if (step.compareTo_za3rmp$(Kotlin.Long.ZERO) > 0) { - diff = differenceModulo(end, start, step); - return diff.isZero() ? end : end.subtract(diff); - } - else if (step.compareTo_za3rmp$(Kotlin.Long.ZERO) < 0) { - diff = differenceModulo(start, end, step.unaryMinus()); - return diff.isZero() ? end : end.add(diff); - } - else { - throw new Kotlin.IllegalArgumentException('Step is zero.'); - } - } - - lazyInitClasses.NumberProgression = Kotlin.createClass( - function () { - return [Kotlin.kotlin.collections.Iterable]; - }, - function (start, end, step) { - this.first = start; - this.last = getProgressionFinalElement(start, end, step); - this.step = step; - if (this.step === 0) - throw new Kotlin.IllegalArgumentException('Step must be non-zero'); - }, { - iterator: function () { - return new Kotlin.RangeIterator(this.first, this.last, this.step); - }, - isEmpty: function () { - return this.step > 0 ? this.first > this.last : this.first < this.last; - }, - hashCode: function () { - return this.isEmpty() ? -1 : 31 * (31 * this.first + this.last) + this.step; - }, - equals_za3rmp$: isSameNotNullRanges, - toString: function () { - return this.step > 0 ? this.first.toString() + '..' + this.last + ' step ' + this.step : this.first.toString() + ' downTo ' + this.last + ' step ' + -this.step; - } - }); - - lazyInitClasses.NumberRange = Kotlin.createClass( - function() { - return [Kotlin.kotlin.ranges.ClosedRange, Kotlin.NumberProgression] - }, - function $fun(start, endInclusive) { - $fun.baseInitializer.call(this, start, endInclusive, 1); - this.start = start; - this.endInclusive = endInclusive; - }, { - contains_htax2k$: function (item) { - return this.start <= item && item <= this.endInclusive; - }, - isEmpty: function () { - return this.start > this.endInclusive; - }, - hashCode: function () { - return this.isEmpty() ? -1 : 31 * this.start + this.endInclusive; - }, - equals_za3rmp$: isSameNotNullRanges, - toString: function () { - return this.start.toString() + '..' + this.endInclusive; - } - }, { - Companion: Kotlin.createObject(null, function () { - this.EMPTY = new Kotlin.NumberRange(1, 0); - }) - }); - - - - lazyInitClasses.LongRangeIterator = Kotlin.createClass( - function () { - return [Kotlin.kotlin.collections.Iterator]; - }, - function (start, end, step) { - this.start = start; - this.end = end; - this.step = step; - this.i = start; - }, { - next: function () { - var value = this.i; - this.i = this.i.add(this.step); - return value; - }, - hasNext: function () { - if (this.step.isNegative()) - return this.i.compare(this.end) >= 0; - else - return this.i.compare(this.end) <= 0; - } - }); - - lazyInitClasses.LongProgression = Kotlin.createClass( - function () { - return [Kotlin.kotlin.collections.Iterable]; - }, - function (start, end, step) { - this.first = start; - this.last = getProgressionFinalElementLong(start, end, step); - this.step = step; - if (this.step.isZero()) - throw new Kotlin.IllegalArgumentException('Step must be non-zero'); - }, { - iterator: function () { - return new Kotlin.LongRangeIterator(this.first, this.last, this.step); - }, - isEmpty: function() { - return this.step.isNegative() ? this.first.compare(this.last) < 0 : this.first.compare(this.last) > 0; - }, - hashCode: function() { - return this.isEmpty() ? -1 : (31 * (31 * this.first.toInt() + this.last.toInt()) + this.step.toInt()); - }, - equals_za3rmp$: isSameLongRanges, - toString: function () { - return !this.step.isNegative() ? this.first.toString() + '..' + this.last + ' step ' + this.step : this.first.toString() + ' downTo ' + this.last + ' step ' + this.step.unaryMinus(); - } - }); - - lazyInitClasses.LongRange = Kotlin.createClass( - function () { - return [Kotlin.kotlin.ranges.ClosedRange, Kotlin.LongProgression]; - }, - function $fun(start, endInclusive) { - $fun.baseInitializer.call(this, start, endInclusive, Kotlin.Long.ONE); - this.start = start; - this.endInclusive = endInclusive; - }, { - contains_htax2k$: function (item) { - return this.start.compareTo_za3rmp$(item) <= 0 && item.compareTo_za3rmp$(this.endInclusive) <= 0; - }, - isEmpty: function () { - return this.start.compare(this.endInclusive) > 0; - }, - hashCode: function() { - return this.isEmpty() ? -1 : (31 * this.start.toInt() + this.endInclusive.toInt()); - }, - equals_za3rmp$: isSameLongRanges, - toString: function () { - return this.start.toString() + '..' + this.endInclusive; - } - }, { - Companion: Kotlin.createObject(null, function () { - this.EMPTY = new Kotlin.LongRange(Kotlin.Long.ONE, Kotlin.Long.ZERO); - }) - }); - - - - lazyInitClasses.CharRangeIterator = Kotlin.createClass( - function () { - return [Kotlin.RangeIterator]; - }, - function (start, end, step) { - Kotlin.RangeIterator.call(this, start, end, step); - }, { - next: function () { - var value = this.i; - this.i = this.i + this.step; - return String.fromCharCode(value); - } - }); - - lazyInitClasses.CharProgression = Kotlin.createClassNow( - function () { - return [Kotlin.kotlin.collections.Iterable]; - }, - function (start, end, step) { - this.first = start; - this.startCode = start.charCodeAt(0); - this.endCode = getProgressionFinalElement(this.startCode, end.charCodeAt(0), step); - this.last = String.fromCharCode(this.endCode); - this.step = step; - if (this.step === 0) - throw new Kotlin.IllegalArgumentException('Increment must be non-zero'); - }, { - iterator: function () { - return new Kotlin.CharRangeIterator(this.startCode, this.endCode, this.step); - }, - isEmpty: function() { - return this.step > 0 ? this.startCode > this.endCode : this.startCode < this.endCode; - }, - hashCode: function() { - return this.isEmpty() ? -1 : (31 * (31 * this.startCode|0 + this.endCode|0) + this.step|0); - }, - equals_za3rmp$: isSameNotNullRanges, - toString: function () { - return this.step > 0 ? this.first.toString() + '..' + this.last + ' step ' + this.step : this.first.toString() + ' downTo ' + this.last + ' step ' + -this.step; - } - }); - - - lazyInitClasses.CharRange = Kotlin.createClass( - function() { - return [Kotlin.kotlin.ranges.ClosedRange, Kotlin.CharProgression] - }, - function $fun(start, endInclusive) { - $fun.baseInitializer.call(this, start, endInclusive, 1); - this.start = start; - this.endInclusive = endInclusive; - }, { - contains_htax2k$: function (item) { - return this.start <= item && item <= this.endInclusive; - }, - isEmpty: function () { - return this.start > this.endInclusive; - }, - hashCode: function() { - return this.isEmpty() ? -1 : (31 * this.startCode|0 + this.endCode|0); - }, - equals_za3rmp$: isSameNotNullRanges, - toString: function () { - return this.start.toString() + '..' + this.endInclusive; - } - }, { - Companion: Kotlin.createObject(null, function () { - this.EMPTY = new Kotlin.CharRange(Kotlin.toChar(1), Kotlin.toChar(0)); - }) - }); - - - /** - * @interface - * @template T - */ - Kotlin.Comparator = Kotlin.createClassNow(null, null, { - compare: throwAbstractFunctionInvocationError("Comparator#compare") - }); + return max; + }; Kotlin.collectionsSort = function (mutableList, comparator) { var boundComparator = void 0; @@ -839,42 +440,6 @@ return array; }; - - Kotlin.StringBuilder = Kotlin.createClassNow([CharSequence], - function (content) { - this.string = typeof(content) == "string" ? content : ""; - }, { - length: { - get: function() { - return this.string.length; - } - }, - substring: function(start, end) { - return this.string.substring(start, end); - }, - charAt: function(index) { - return this.string.charAt(index); - }, - append: function (obj, from, to) { - if (from == void 0 && to == void 0) { - this.string = this.string + obj.toString(); - } else if (to == void 0) { - this.string = this.string + obj.toString().substring(from); - } else { - this.string = this.string + obj.toString().substring(from, to); - } - - return this; - }, - reverse: function () { - this.string = this.string.split("").reverse().join(""); - return this; - }, - toString: function () { - return this.string; - } - }); - Kotlin.splitString = function (str, regex, limit) { return str.split(new RegExp(regex), limit); }; @@ -920,10 +485,6 @@ return result; }; - Kotlin.arrayIterator = function (array) { - return new Kotlin.ArrayIterator(array); - }; - Kotlin.deleteProperty = function (object, property) { delete object[property]; }; @@ -936,7 +497,5 @@ } return obj1; }; - - Kotlin.createDefinition(lazyInitClasses, Kotlin); })(Kotlin); diff --git a/js/js.translator/testData/kotlin_lib_ecma5.js b/js/js.translator/testData/kotlin_lib_ecma5.js index 843a27e2276..f7ba2ef3318 100644 --- a/js/js.translator/testData/kotlin_lib_ecma5.js +++ b/js/js.translator/testData/kotlin_lib_ecma5.js @@ -343,17 +343,41 @@ }; Kotlin.callGetter = function (thisObject, klass, propertyName) { - return klass.$metadata$.properties[propertyName].get.call(thisObject); + var propertyDescriptor = Object.getOwnPropertyDescriptor(klass, propertyName); + if (propertyDescriptor != null) { + if (propertyDescriptor.get != null) { + return propertyDescriptor.get.call(thisObject); + } + else if ("value" in propertyDescriptor) { + return propertyDescriptor.value; + } + } + else { + return Kotlin.callGetter(thisObject, Object.getPrototypeOf(klass), propertyName); + } + return null; }; Kotlin.callSetter = function (thisObject, klass, propertyName, value) { - klass.$metadata$.properties[propertyName].set.call(thisObject, value); + var propertyDescriptor = Object.getOwnPropertyDescriptor(klass, propertyName); + if (propertyDescriptor != null) { + if (propertyDescriptor.set != null) { + propertyDescriptor.set.call(thisObject, value); + } + else if ("value" in propertyDescriptor) { + propertyDescriptor.value = value; + } + } + else { + return Kotlin.callSetter(thisObject, Object.getPrototypeOf(klass), propertyName, value); + } }; function isInheritanceFromTrait(metadata, trait) { - if (metadata == null || metadata.classIndex < trait.$metadata$.classIndex) { + // TODO: return this optimization + /*if (metadata == null || metadata.classIndex < trait.$metadata$.classIndex) { return false; - } + }*/ var baseClasses = metadata.baseClasses; var i; for (i = 0; i < baseClasses.length; i++) { @@ -380,8 +404,8 @@ return false; } - if (typeof klass === "function") { - return object instanceof klass; + if (typeof klass === "function" && object instanceof klass) { + return true; } var proto = Object.getPrototypeOf(klass); @@ -399,7 +423,10 @@ } if (object.constructor != null) { - return isInheritanceFromTrait(object.constructor.$metadata$, klass); + metadata = object.constructor.$metadata$; + if (metadata != null) { + return isInheritanceFromTrait(metadata, klass); + } } return false; diff --git a/js/js.translator/testData/long.js b/js/js.translator/testData/long.js index d38adbd3d4f..5baaacbac5f 100644 --- a/js/js.translator/testData/long.js +++ b/js/js.translator/testData/long.js @@ -839,6 +839,6 @@ Kotlin.Long.prototype.inv = Kotlin.Long.prototype.not; Kotlin.Long.prototype.rangeTo = function (other) { - return new Kotlin.LongRange(this, other); + return new Kotlin.kotlin.ranges.LongRange(this, other); }; }(Kotlin)); \ No newline at end of file diff --git a/js/js.translator/testData/merge-builtins.js b/js/js.translator/testData/merge-builtins.js new file mode 100644 index 00000000000..5e1428d8a65 --- /dev/null +++ b/js/js.translator/testData/merge-builtins.js @@ -0,0 +1,12 @@ +var require = (function () { + var builtins = module.exports.kotlin; + var propertyNames = Object.getOwnPropertyNames(builtins); + Kotlin.kotlin = Kotlin.kotlin || {}; + for (var i = 0; i < propertyNames.length; ++i) { + var propertyName = propertyNames[i]; + Kotlin.kotlin[propertyName] = builtins[propertyName]; + } + return function() { + return Kotlin; + } +})(); \ No newline at end of file diff --git a/js/js.translator/testData/merge.js b/js/js.translator/testData/merge.js index 91039d5ac8d..d41e5821a92 100644 --- a/js/js.translator/testData/merge.js +++ b/js/js.translator/testData/merge.js @@ -1,6 +1,16 @@ (function () { var stdlib = module.exports; - Object.getOwnPropertyNames(stdlib).forEach(function(propertyName) { - Kotlin[propertyName] = stdlib[propertyName]; - }); + function copyProperties(from, to) { + var propertyNames = Object.getOwnPropertyNames(from); + for (var i = 0; i < propertyNames.length; ++i) { + var propertyName = propertyNames[i]; + if (propertyName in to) { + copyProperties(from[propertyName], to[propertyName]); + } + else { + to[propertyName] = from[propertyName]; + } + } + } + copyProperties(stdlib, Kotlin); })(); diff --git a/jslib_files.xml b/jslib_files.xml index 744a26fa76e..761cd607b8c 100644 --- a/jslib_files.xml +++ b/jslib_files.xml @@ -2,18 +2,24 @@ + + + + + + @@ -30,4 +36,13 @@ + + + + + + + + +