Compare commits

...

7 Commits

Author SHA1 Message Date
Anton Bannykh
053efcc849 Shortened ArrayFIF 2017-03-02 17:48:11 +03:00
Anton Bannykh
9bca7ff783 Fixed types 2017-03-02 16:19:32 +03:00
Anton Bannykh
87252e547f minor js("Array.prototype.foo") -> js("[]").foo 2017-02-28 20:46:08 +03:00
Anton Bannykh
81f424070c test 2017-02-28 20:45:39 +03:00
Anton Bannykh
bbfd058a14 Patch apply to work with TypedArray's if needed 2017-02-28 19:54:25 +03:00
Anton Bannykh
5caade86bf minor 2017-02-28 17:58:18 +03:00
Anton Bannykh
9fd1cefce2 JS: map primitive arrays to TypedArray 2017-02-28 16:15:44 +03:00
27 changed files with 538 additions and 341 deletions

View File

@@ -1,6 +1,3 @@
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
//test [], get and iterator calls
fun test(createIntNotLong: Boolean): String {
val a = if (createIntNotLong) IntArray(5) else LongArray(5)

View File

@@ -1,6 +1,3 @@
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
fun test(b: Boolean): String {
val a = if (b) IntArray(5) else LongArray(5)
if (a is IntArray) {

View File

@@ -0,0 +1,29 @@
fun <T> eq(expected: T, actual: T): Boolean {
return when (expected) {
is ByteArray -> actual is ByteArray && actual.size == expected.size && actual.foldIndexed(true) { i, r, v -> r && expected[i] == v }
is ShortArray -> actual is ShortArray && actual.size == expected.size && actual.foldIndexed(true) { i, r, v -> r && expected[i] == v }
is CharArray -> actual is CharArray && actual.size == expected.size && actual.foldIndexed(true) { i, r, v -> r && expected[i] == v }
is IntArray -> actual is IntArray && actual.size == expected.size && actual.foldIndexed(true) { i, r, v -> r && expected[i] == v }
is LongArray -> actual is LongArray && actual.size == expected.size && actual.foldIndexed(true) { i, r, v -> r && expected[i] == v }
is FloatArray -> actual is FloatArray && actual.size == expected.size && actual.foldIndexed(true) { i, r, v -> r && expected[i] == v }
is DoubleArray -> actual is DoubleArray && actual.size == expected.size && actual.foldIndexed(true) { i, r, v -> r && expected[i] == v }
else -> false
}
}
fun chv(vararg c: Char): CharArray {
return c
}
fun box(): String {
if (!eq(byteArrayOf(0), ByteArray(1))) return "fail 2"
if (!eq(byteArrayOf(1), byteArrayOf(1).copyOf())) return "fail 2"
if (!eq(byteArrayOf(1, 0), byteArrayOf(1).copyOf(2))) return "fail 5"
if (!eq(byteArrayOf(1), byteArrayOf(1, 2).copyOf(1))) return "fail 9"
if (!eq(charArrayOf('a', 'b', 'c'), chv('a', 'b', 'c'))) return "fail vararg"
if (!eq(charArrayOf('a', 'b', 'c'), CharArray(3) { 'a' + it })) return "fail constructor"
return "OK"
}

View File

@@ -1,6 +1,3 @@
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_RUNTIME
import kotlin.test.assertEquals

View File

@@ -611,6 +611,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
doTest(fileName);
}
@TestMetadata("primitiveArrays.kt")
public void testPrimitiveArrays() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/arrays/primitiveArrays.kt");
doTest(fileName);
}
@TestMetadata("stdlib.kt")
public void testStdlib() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/arrays/stdlib.kt");

View File

@@ -611,6 +611,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("primitiveArrays.kt")
public void testPrimitiveArrays() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/arrays/primitiveArrays.kt");
doTest(fileName);
}
@TestMetadata("stdlib.kt")
public void testStdlib() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/arrays/stdlib.kt");

View File

@@ -877,6 +877,20 @@ public abstract class KotlinBuiltIns {
return descriptor != null && getPrimitiveTypeByArrayClassFqName(getFqName(descriptor)) != null;
}
@Nullable
public static PrimitiveType getPrimitiveArrayType(@NotNull KotlinType type) {
ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
if (descriptor == null) return null;
return getPrimitiveTypeByArrayClassFqName(getFqName(descriptor));
}
@Nullable
public static PrimitiveType getPrimitiveType(@NotNull KotlinType type) {
ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
if (type.isMarkedNullable() || !(descriptor instanceof ClassDescriptor)) return null;
return getPrimitiveTypeByFqName(getFqName(descriptor));
}
public static boolean isPrimitiveType(@NotNull KotlinType type) {
ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
return !type.isMarkedNullable() && descriptor instanceof ClassDescriptor && isPrimitiveClass((ClassDescriptor) descriptor);

View File

@@ -38,3 +38,9 @@ fun <T> arrayWithFun(size: Int, init: (Int) -> T): Array<T> {
}
return result
}
@JsName("withType")
fun withType(type: String, array: dynamic): dynamic {
array.`$type$` = type
return array
}

View File

@@ -96,23 +96,54 @@ internal class BoxedChar(val c: Char) : Comparable<Char> {
}
}
/* For future binary compatibility with TypedArrays
* TODO: concat normal Array's and TypedArrays into an Array
internal inline fun <T> concat(args: Array<T>): T {
val untyped = args.map { arr ->
if (arr !is Array<*>) {
js("[]").slice.call(arr)
}
else {
arr
}
}.toTypedArray()
return js("[]").concat.apply(js("[]"), untyped);
}
/** Concat regular Array's and TypedArrays into an Array
*/
@PublishedApi
@JsName("arrayConcat")
internal fun <T> arrayConcat(a: T, b: T): T {
return a.asDynamic().concat.apply(js("[]"), js("arguments"));
val args: Array<T> = js("arguments")
return concat(args)
}
/* For future binary compatibility with TypedArrays
* TODO: concat primitive arrays.
* For Byte-, Short-, Int-, Float-, and DoubleArray concat result into a TypedArray.
* For Boolean-, Char-, and LongArray return an Array with corresponding type property.
* Default to Array.prototype.concat for compatibility.
/** Concat primitive arrays.
*
* For Byte-, Short-, Int-, Float-, and DoubleArray concat result into a TypedArray.
* For Boolean-, Char-, and LongArray return an Array with corresponding type property.
* Default to Array.prototype.concat for compatibility.
*/
@PublishedApi
@JsName("primitiveArrayConcat")
internal fun <T> primitiveArrayConcat(a: T, b: T): T {
return a.asDynamic().concat.apply(js("[]"), js("arguments"));
val args: Array<T> = js("arguments")
if (a is Array<*>) {
return concat(args)
}
else {
var size = 0
for (i in 0..args.size - 1) {
size += args[i].asDynamic().length as Int
}
// TODO losing type information for Boolean-, Char-, LongArray ?
val result = js("new a.constructor(size)")
size = 0
for (i in 0..args.size - 1) {
val arr = args[i].asDynamic()
for (j in 0..arr.length - 1) {
result[size++] = arr[j]
}
}
return result
}
}

View File

@@ -46,7 +46,7 @@ public operator fun dynamic.iterator(): Iterator<dynamic> {
return when {
this["iterator"] != null ->
this["iterator"]()
js("Array").isArray(r) ->
js("Kotlin").isArrayish(r) ->
r.unsafeCast<Array<*>>().iterator()
else ->

View File

@@ -13032,21 +13032,21 @@ public inline fun CharArray.copyOf(): CharArray {
* Returns new array which is a copy of the original array, resized to the given [newSize].
*/
public fun ByteArray.copyOf(newSize: Int): ByteArray {
return arrayCopyResize(this, newSize, 0)
return arrayCopy(this, ByteArray(newSize))
}
/**
* Returns new array which is a copy of the original array, resized to the given [newSize].
*/
public fun ShortArray.copyOf(newSize: Int): ShortArray {
return arrayCopyResize(this, newSize, 0)
return arrayCopy(this, ShortArray(newSize))
}
/**
* Returns new array which is a copy of the original array, resized to the given [newSize].
*/
public fun IntArray.copyOf(newSize: Int): IntArray {
return arrayCopyResize(this, newSize, 0)
return arrayCopy(this, IntArray(newSize))
}
/**
@@ -13060,14 +13060,14 @@ public fun LongArray.copyOf(newSize: Int): LongArray {
* Returns new array which is a copy of the original array, resized to the given [newSize].
*/
public fun FloatArray.copyOf(newSize: Int): FloatArray {
return arrayCopyResize(this, newSize, 0.0f)
return arrayCopy(this, FloatArray(newSize))
}
/**
* Returns new array which is a copy of the original array, resized to the given [newSize].
*/
public fun DoubleArray.copyOf(newSize: Int): DoubleArray {
return arrayCopyResize(this, newSize, 0.0)
return arrayCopy(this, DoubleArray(newSize))
}
/**
@@ -13246,21 +13246,21 @@ public operator fun <T> Array<out T>.plus(elements: Collection<T>): Array<T> {
* Returns an array containing all elements of the original array and then all elements of the given [elements] collection.
*/
public operator fun ByteArray.plus(elements: Collection<Byte>): ByteArray {
return arrayPlusCollection(this, elements)
return typedArrayPlusCollection(this, this.copyOf(size + elements.size), elements)
}
/**
* Returns an array containing all elements of the original array and then all elements of the given [elements] collection.
*/
public operator fun ShortArray.plus(elements: Collection<Short>): ShortArray {
return arrayPlusCollection(this, elements)
return typedArrayPlusCollection(this, this.copyOf(size + elements.size), elements)
}
/**
* Returns an array containing all elements of the original array and then all elements of the given [elements] collection.
*/
public operator fun IntArray.plus(elements: Collection<Int>): IntArray {
return arrayPlusCollection(this, elements)
return typedArrayPlusCollection(this, this.copyOf(size + elements.size), elements)
}
/**
@@ -13274,14 +13274,14 @@ public operator fun LongArray.plus(elements: Collection<Long>): LongArray {
* Returns an array containing all elements of the original array and then all elements of the given [elements] collection.
*/
public operator fun FloatArray.plus(elements: Collection<Float>): FloatArray {
return arrayPlusCollection(this, elements)
return typedArrayPlusCollection(this, this.copyOf(size + elements.size), elements)
}
/**
* Returns an array containing all elements of the original array and then all elements of the given [elements] collection.
*/
public operator fun DoubleArray.plus(elements: Collection<Double>): DoubleArray {
return arrayPlusCollection(this, elements)
return typedArrayPlusCollection(this, this.copyOf(size + elements.size), elements)
}
/**
@@ -13454,21 +13454,21 @@ public fun <T> Array<out T>.sortWith(comparator: Comparator<in T>): Unit {
* Returns a *typed* object array containing all of the elements of this primitive array.
*/
public fun ByteArray.toTypedArray(): Array<Byte> {
return copyOf().unsafeCast<Array<Byte>>()
return js("[]").slice.call(this)
}
/**
* Returns a *typed* object array containing all of the elements of this primitive array.
*/
public fun ShortArray.toTypedArray(): Array<Short> {
return copyOf().unsafeCast<Array<Short>>()
return js("[]").slice.call(this)
}
/**
* Returns a *typed* object array containing all of the elements of this primitive array.
*/
public fun IntArray.toTypedArray(): Array<Int> {
return copyOf().unsafeCast<Array<Int>>()
return js("[]").slice.call(this)
}
/**
@@ -13482,14 +13482,14 @@ public fun LongArray.toTypedArray(): Array<Long> {
* Returns a *typed* object array containing all of the elements of this primitive array.
*/
public fun FloatArray.toTypedArray(): Array<Float> {
return copyOf().unsafeCast<Array<Float>>()
return js("[]").slice.call(this)
}
/**
* Returns a *typed* object array containing all of the elements of this primitive array.
*/
public fun DoubleArray.toTypedArray(): Array<Double> {
return copyOf().unsafeCast<Array<Double>>()
return js("[]").slice.call(this)
}
/**

View File

@@ -71,6 +71,15 @@ internal fun <T> arrayOfNulls(reference: Array<out T>, size: Int): Array<T> {
return arrayOfNulls<Any>(size).unsafeCast<Array<T>>()
}
internal fun arrayCopy(source: dynamic, dest: dynamic): dynamic {
val srcLen: Int = source.length
val dstLen: Int = dest.length
var index: Int = 0
while (index < srcLen && index < dstLen) dest[index] = source[index++]
return dest
}
internal fun arrayCopyResize(source: dynamic, newSize: Int, defaultValue: Any?): dynamic {
val result = source.slice(0, newSize)
var index: Int = source.length
@@ -89,6 +98,12 @@ internal fun <T> arrayPlusCollection(array: dynamic, collection: Collection<T>):
return result
}
internal fun <T> typedArrayPlusCollection(array: dynamic, dst: dynamic, collection: Collection<T>): dynamic {
var index: Int = array.length
for (element in collection) dst[index++] = element
return dst
}
// no singleton map implementation in js, return map as is
internal inline fun <K, V> Map<K, V>.toSingletonMapOrSelf(): Map<K, V> = this

View File

@@ -14,21 +14,45 @@
* limitations under the License.
*/
Kotlin.isBooleanArray = function (a) {
return Array.isArray(a) && a.$type$ === "BooleanArray"
};
Kotlin.isCharArray = function (a) {
return Array.isArray(a) && a.$type$ === "CharArray"
};
Kotlin.isLongArray = function (a) {
return Array.isArray(a) && a.$type$ === "LongArray"
};
Kotlin.isArray = function (a) {
return Array.isArray(a) && !a.$type$;
};
Kotlin.isArrayish = function (a) {
return Array.isArray(a) || ArrayBuffer.isView(a)
};
Kotlin.arrayToString = function (a) {
return "[" + a.map(Kotlin.toString).join(", ") + "]";
};
Kotlin.arrayDeepToString = function (a, visited) {
visited = visited || [a];
return "[" + a.map(function(e) {
if (Array.isArray(e) && visited.indexOf(e) < 0) {
var toString = Kotlin.toString;
if (Kotlin.isCharArray(a)) {
toString = String.fromCharCode;
}
return "[" + a.map(function (e) {
if (Kotlin.isArrayish(e) && visited.indexOf(e) < 0) {
visited.push(e);
var result = Kotlin.arrayDeepToString(e, visited);
visited.pop();
return result;
}
else {
return Kotlin.toString(e);
return toString(e);
}
}).join(", ") + "]";
};
@@ -37,7 +61,7 @@ Kotlin.arrayEquals = function (a, b) {
if (a === b) {
return true;
}
if (!Array.isArray(b) || a.length !== b.length) {
if (!Kotlin.isArrayish(b) || a.length !== b.length) {
return false;
}
@@ -53,16 +77,17 @@ Kotlin.arrayDeepEquals = function (a, b) {
if (a === b) {
return true;
}
if (!Array.isArray(b) || a.length !== b.length) {
if (!Kotlin.isArrayish(b) || a.length !== b.length) {
return false;
}
for (var i = 0, n = a.length; i < n; i++) {
if (Array.isArray(a[i])) {
if (Kotlin.isArrayish(a[i])) {
if (!Kotlin.arrayDeepEquals(a[i], b[i])) {
return false;
}
} else if (!Kotlin.equals(a[i], b[i])) {
}
else if (!Kotlin.equals(a[i], b[i])) {
return false;
}
}
@@ -81,11 +106,11 @@ Kotlin.arrayDeepHashCode = function (arr) {
var result = 1;
for (var i = 0, n = arr.length; i < n; i++) {
var e = arr[i];
result = ((31 * result | 0) + (Array.isArray(e) ? Kotlin.arrayDeepHashCode(e) : Kotlin.hashCode(e))) | 0;
result = ((31 * result | 0) + (Kotlin.isArrayish(e) ? Kotlin.arrayDeepHashCode(e) : Kotlin.hashCode(e))) | 0;
}
return result;
};
Kotlin.primitiveArraySort = function(array) {
Kotlin.primitiveArraySort = function (array) {
array.sort(Kotlin.primitiveCompareTo)
};

View File

@@ -55,7 +55,7 @@ Kotlin.toString = function (o) {
if (o == null) {
return "null";
}
else if (Array.isArray(o)) {
else if (Kotlin.isArrayish(o)) {
return "[...]";
}
else {

View File

@@ -31,3 +31,40 @@ if (typeof String.prototype.endsWith === "undefined") {
return lastIndex !== -1 && lastIndex === position;
};
}
// Polyfills for Rhino
(function() {
var normalizeOffset = function(offset, length) {
if (offset < 0) return Math.max(0, offset + length);
return Math.min(offset, length);
};
var typedArraySlice = function(begin, end) {
if (typeof end === "undefined") {
end = this.length;
}
begin = normalizeOffset(begin || 0, this.length);
end = Math.max(begin, normalizeOffset(end, this.length));
return new this.constructor(this.subarray(begin, end));
};
var arrays = [Int8Array, Int16Array, Int32Array, Float32Array, Float64Array];
for (var i = 0; i < arrays.length; ++i) {
var TypedArray = arrays[i];
if (typeof TypedArray.prototype.slice === "undefined") {
Object.defineProperty(TypedArray.prototype, 'slice', {
value: typedArraySlice
});
}
}
// Patch apply to work with TypedArrays if needed.
try {
(function() {}).apply(null, new Int32Array(0))
} catch (e) {
var apply = Function.prototype.apply;
Object.defineProperty(Function.prototype, 'apply', {
value: function(self, array) {
return apply.call(this, self, [].slice.call(array));
}
});
}
})();

View File

@@ -416,13 +416,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
@TestMetadata("arrayInstanceOf.kt")
public void testArrayInstanceOf() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/arrays/arrayInstanceOf.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
doTest(fileName);
}
@TestMetadata("arrayPlusAssign.kt")
@@ -734,13 +728,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
@TestMetadata("kt7288.kt")
public void testKt7288() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/arrays/kt7288.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
doTest(fileName);
}
@TestMetadata("kt7338.kt")
@@ -803,6 +791,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
doTest(fileName);
}
@TestMetadata("primitiveArrays.kt")
public void testPrimitiveArrays() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/arrays/primitiveArrays.kt");
doTest(fileName);
}
@TestMetadata("stdlib.kt")
public void testStdlib() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/arrays/stdlib.kt");
@@ -15119,13 +15113,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
@TestMetadata("kt13241_Array.kt")
public void testKt13241_Array() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInIndices/kt13241_Array.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
doTest(fileName);
}
@TestMetadata("kt13241_CharSequence.kt")

View File

@@ -89,7 +89,6 @@ public final class Namer {
private static final String PROTOTYPE_NAME = "prototype";
private static final String CAPTURED_VAR_FIELD = "v";
public static final JsNameRef IS_ARRAY_FUN_REF = new JsNameRef("isArray", "Array");
public static final String DEFINE_INLINE_FUNCTION = "defineInlineFunction";
public static final String DEFAULT_PARAMETER_IMPLEMENTOR_SUFFIX = "$default";
@@ -283,6 +282,26 @@ public final class Namer {
return kotlin(IS_CHAR_SEQUENCE);
}
@NotNull
public JsExpression isArray() {
return kotlin("isArray");
}
@NotNull
public JsExpression isBooleanArray() {
return kotlin("isBooleanArray");
}
@NotNull
public JsExpression isCharArray() {
return kotlin("isCharArray");
}
@NotNull
public JsExpression isLongArray() {
return kotlin("isLongArray");
}
@NotNull
private JsExpression invokeFunctionAndSetTypeCheckMetadata(
@NotNull String functionName,

View File

@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.general.Translation
import org.jetbrains.kotlin.js.translate.intrinsic.functions.factories.CompositeFIF
import org.jetbrains.kotlin.js.translate.intrinsic.functions.factories.ArrayFIF
import org.jetbrains.kotlin.js.translate.utils.BindingUtils.*
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.*
import org.jetbrains.kotlin.js.translate.utils.PsiUtils.getLoopRange
@@ -166,7 +166,7 @@ fun translateForExpression(expression: KtForExpression, context: TranslationCont
fun translateForOverArray(): JsStatement {
val rangeExpression = context.defineTemporary(Translation.translateAsExpression(loopRange, context))
val length = CompositeFIF.LENGTH_PROPERTY_INTRINSIC.apply(rangeExpression, listOf<JsExpression>(), context)
val length = ArrayFIF.LENGTH_PROPERTY_INTRINSIC.apply(rangeExpression, listOf<JsExpression>(), context)
val end = context.defineTemporary(length)
val index = context.declareTemporary(context.program().getNumberLiteral(0))

View File

@@ -35,8 +35,8 @@ import org.jetbrains.kotlin.js.translate.context.TranslationContext;
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator;
import org.jetbrains.kotlin.js.translate.general.Translation;
import org.jetbrains.kotlin.js.translate.intrinsic.functions.factories.TopLevelFIF;
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils;
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator;
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils;
import org.jetbrains.kotlin.js.translate.utils.BindingUtils;
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
@@ -56,8 +56,7 @@ import static org.jetbrains.kotlin.builtins.FunctionTypesKt.isFunctionTypeOrSubt
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isArray;
import static org.jetbrains.kotlin.js.descriptorUtils.DescriptorUtilsKt.getNameIfStandardType;
import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getTypeByReference;
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.equality;
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.not;
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.*;
import static org.jetbrains.kotlin.psi.KtPsiUtil.findChildByType;
import static org.jetbrains.kotlin.types.TypeUtils.*;
@@ -210,7 +209,7 @@ public final class PatternTranslator extends AbstractTranslator {
return namer().isTypeOf(program().getStringLiteral("function"));
}
if (isArray(type)) return Namer.IS_ARRAY_FUN_REF;
if (isArray(type)) return namer().isArray();
if (TypePredicatesKt.getCHAR_SEQUENCE().apply(type)) return namer().isCharSequence();
@@ -247,6 +246,28 @@ public final class PatternTranslator extends AbstractTranslator {
return namer().isTypeOf(program().getStringLiteral("number"));
}
if (KotlinBuiltIns.isPrimitiveArray(type)) {
PrimitiveType arrayType = KotlinBuiltIns.getPrimitiveArrayType(type);
switch (arrayType) {
case BOOLEAN:
return namer().isBooleanArray();
case CHAR:
return namer().isCharArray();
case BYTE:
return namer().isInstanceOf(pureFqn("Int8Array", null));
case SHORT:
return namer().isInstanceOf(pureFqn("Int16Array", null));
case INT:
return namer().isInstanceOf(pureFqn("Int32Array", null));
case FLOAT:
return namer().isInstanceOf(pureFqn("Float32Array", null));
case LONG:
return namer().isLongArray();
case DOUBLE:
return namer().isInstanceOf(pureFqn("Float64Array", null));
}
}
return null;
}

View File

@@ -1,139 +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 com.google.common.collect.Lists;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.builtins.PrimitiveType;
import org.jetbrains.kotlin.js.backend.ast.*;
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.FunctionIntrinsic;
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsicWithReceiverComputed;
import org.jetbrains.kotlin.name.Name;
import java.util.List;
import static com.intellij.openapi.util.text.StringUtil.decapitalize;
import static org.jetbrains.kotlin.js.patterns.PatternBuilder.pattern;
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.assignment;
public final class ArrayFIF extends CompositeFIF {
private static final NamePredicate NUMBER_ARRAY;
private static final NamePredicate CHAR_ARRAY;
private static final NamePredicate BOOLEAN_ARRAY;
private static final NamePredicate LONG_ARRAY;
private static final NamePredicate ARRAYS;
private static final DescriptorPredicate ARRAY_FACTORY_METHODS;
static {
List<Name> arrayTypeNames = Lists.newArrayList();
List<Name> arrayFactoryMethodNames = Lists.newArrayList(Name.identifier("arrayOf"));
for (PrimitiveType type : PrimitiveType.values()) {
Name arrayTypeName = type.getArrayTypeName();
if (type != PrimitiveType.CHAR && type != PrimitiveType.BOOLEAN && type != PrimitiveType.LONG) {
arrayTypeNames.add(arrayTypeName);
}
arrayFactoryMethodNames.add(Name.identifier(decapitalize(arrayTypeName.asString() + "Of")));
}
Name arrayName = KotlinBuiltIns.FQ_NAMES.array.shortName();
Name booleanArrayName = PrimitiveType.BOOLEAN.getArrayTypeName();
Name charArrayName = PrimitiveType.CHAR.getArrayTypeName();
Name longArrayName = PrimitiveType.LONG.getArrayTypeName();
NUMBER_ARRAY = new NamePredicate(arrayTypeNames);
CHAR_ARRAY = new NamePredicate(charArrayName);
BOOLEAN_ARRAY = new NamePredicate(booleanArrayName);
LONG_ARRAY = new NamePredicate(longArrayName);
arrayTypeNames.add(charArrayName);
arrayTypeNames.add(booleanArrayName);
arrayTypeNames.add(longArrayName);
arrayTypeNames.add(arrayName);
ARRAYS = new NamePredicate(arrayTypeNames);
ARRAY_FACTORY_METHODS = pattern(Namer.KOTLIN_LOWER_NAME, new NamePredicate(arrayFactoryMethodNames));
}
private static final FunctionIntrinsic ARRAY_INTRINSIC = new FunctionIntrinsicWithReceiverComputed() {
@NotNull
@Override
public JsExpression apply(
@Nullable JsExpression receiver,
@NotNull List<? extends JsExpression> arguments,
@NotNull TranslationContext context
) {
assert arguments.size() == 1;
return arguments.get(0);
}
};
@NotNull
public static final FunctionIntrinsic GET_INTRINSIC = new FunctionIntrinsicWithReceiverComputed() {
@NotNull
@Override
public JsExpression apply(@Nullable JsExpression receiver,
@NotNull List<? extends JsExpression> arguments,
@NotNull TranslationContext context) {
assert receiver != null;
assert arguments.size() == 1 : "Array get expression must have one argument.";
JsExpression indexExpression = arguments.get(0);
return new JsArrayAccess(receiver, indexExpression);
}
};
@NotNull
public static final FunctionIntrinsic SET_INTRINSIC = new FunctionIntrinsicWithReceiverComputed() {
@NotNull
@Override
public JsExpression apply(@Nullable JsExpression receiver,
@NotNull List<? extends JsExpression> arguments,
@NotNull TranslationContext context) {
assert receiver != null;
assert arguments.size() == 2 : "Array set expression must have two arguments.";
JsExpression indexExpression = arguments.get(0);
JsExpression value = arguments.get(1);
JsArrayAccess arrayAccess = new JsArrayAccess(receiver, indexExpression);
return assignment(arrayAccess, value);
}
};
@NotNull
public static final FunctionIntrinsicFactory INSTANCE = new ArrayFIF();
private ArrayFIF() {
add(pattern(ARRAYS, "get"), GET_INTRINSIC);
add(pattern(ARRAYS, "set"), SET_INTRINSIC);
add(pattern(ARRAYS, "<get-size>"), LENGTH_PROPERTY_INTRINSIC);
add(pattern(ARRAYS, "iterator"), new KotlinFunctionIntrinsic("arrayIterator"));
add(pattern(NUMBER_ARRAY, "<init>(Int)"), new KotlinFunctionIntrinsic("newArray", JsNumberLiteral.ZERO));
add(pattern(CHAR_ARRAY, "<init>(Int)"), new KotlinFunctionIntrinsic("newArray", JsNumberLiteral.ZERO));
add(pattern(BOOLEAN_ARRAY, "<init>(Int)"), new KotlinFunctionIntrinsic("newArray", JsLiteral.FALSE));
add(pattern(LONG_ARRAY, "<init>(Int)"), new KotlinFunctionIntrinsic("newArray", new JsNameRef(Namer.LONG_ZERO, Namer.kotlinLong())));
add(pattern(ARRAYS, "<init>(Int,Function1)"), new KotlinFunctionIntrinsic("newArrayF"));
add(pattern("kotlin", "arrayOfNulls"), new KotlinFunctionIntrinsic("newArray", JsLiteral.NULL));
add(ARRAY_FACTORY_METHODS, ARRAY_INTRINSIC);
}
}

View File

@@ -0,0 +1,109 @@
/*
* 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 com.intellij.openapi.util.text.StringUtil.decapitalize
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.builtins.PrimitiveType.*
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.patterns.NamePredicate
import org.jetbrains.kotlin.js.patterns.PatternBuilder.pattern
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.BuiltInPropertyIntrinsic
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsicWithReceiverComputed
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.name.Name
import java.util.*
object ArrayFIF : CompositeFIF() {
@JvmField
val GET_INTRINSIC = intrinsify { receiver, arguments, _ ->
assert(arguments.size == 1) { "Array get expression must have one argument." }
val (indexExpression) = arguments
JsArrayAccess(receiver!!, indexExpression)
}
@JvmField
val SET_INTRINSIC = intrinsify { receiver, arguments, _ ->
assert(arguments.size == 2) { "Array set expression must have two arguments." }
val (indexExpression, value) = arguments
val arrayAccess = JsArrayAccess(receiver!!, indexExpression)
JsAstUtils.assignment(arrayAccess, value)
}
@JvmField
val LENGTH_PROPERTY_INTRINSIC = BuiltInPropertyIntrinsic("length")
private val TYPED_MAP = EnumMap(mapOf(BYTE to "Int8", SHORT to "Int16", INT to "Int32", FLOAT to "Float32", DOUBLE to "Float64"))
fun castToTypedArray(p: JsProgram, type: PrimitiveType?, arg: JsExpression): JsExpression {
return when (type) {
null -> arg
in TYPED_MAP -> JsNew(JsNameRef(TYPED_MAP[type] + "Array"), listOf(arg))
else -> JsAstUtils.invokeKotlinFunction("withType", p.getStringLiteral(type.arrayTypeName.asString()), arg)
}
}
init {
val arrayName = KotlinBuiltIns.FQ_NAMES.array.shortName()
val arrayTypeNames = mutableListOf(arrayName)
PrimitiveType.values().mapTo(arrayTypeNames) { it.arrayTypeName }
val arrays = NamePredicate(arrayTypeNames)
add(pattern(arrays, "get"), GET_INTRINSIC)
add(pattern(arrays, "set"), SET_INTRINSIC)
add(pattern(arrays, "<get-size>"), LENGTH_PROPERTY_INTRINSIC)
add(pattern(arrays, "iterator"), KotlinFunctionIntrinsic("arrayIterator"))
for (type in PrimitiveType.values()) {
add(pattern(NamePredicate(type.arrayTypeName), "<init>(Int)"), intrinsify { _, arguments, context ->
assert(arguments.size == 1) { "Array <init>(Int) expression must have one argument." }
val (size) = arguments
val arg = if (type in TYPED_MAP) size else JsAstUtils.invokeKotlinFunction("newArray", size, when (type) {
BOOLEAN -> JsLiteral.FALSE
LONG -> JsNameRef(Namer.LONG_ZERO, Namer.kotlinLong())
else -> JsNumberLiteral.ZERO
})
castToTypedArray(context.program(), type, arg)
})
add(pattern(NamePredicate(type.arrayTypeName), "<init>(Int,Function1)"), intrinsify { _, arguments, context ->
assert(arguments.size == 2) { "Array <init>(Int,Function1) expression must have two arguments." }
val (size, fn) = arguments
castToTypedArray(context.program(), type, JsAstUtils.invokeKotlinFunction("newArrayF", size, fn))
})
}
add(pattern(NamePredicate(arrayName), "<init>(Int,Function1)"), KotlinFunctionIntrinsic("newArrayF"))
add(pattern(Namer.KOTLIN_LOWER_NAME, "arrayOfNulls"), KotlinFunctionIntrinsic("newArray", JsLiteral.NULL))
val arrayFactoryMethodNames = arrayTypeNames.map { Name.identifier(decapitalize(it.asString() + "Of")) }
val arrayFactoryMethods = pattern(Namer.KOTLIN_LOWER_NAME, NamePredicate(arrayFactoryMethodNames))
add(arrayFactoryMethods, intrinsify { _, arguments, _ -> arguments[0] })
}
private fun intrinsify(f: (receiver: JsExpression?, arguments: List<JsExpression>, context: TranslationContext) -> JsExpression)
= object : FunctionIntrinsicWithReceiverComputed() {
override fun apply(receiver: JsExpression?, arguments: List<JsExpression>, context: TranslationContext): JsExpression {
return f(receiver, arguments, context)
}
}
}

View File

@@ -22,15 +22,11 @@ import com.intellij.openapi.util.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.BuiltInPropertyIntrinsic;
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsic;
import java.util.List;
public abstract class CompositeFIF implements FunctionIntrinsicFactory {
@NotNull
public static final BuiltInPropertyIntrinsic LENGTH_PROPERTY_INTRINSIC = new BuiltInPropertyIntrinsic("length");
@NotNull
private final List<Pair<Predicate<FunctionDescriptor>, FunctionIntrinsic>> patternsAndIntrinsics = Lists.newArrayList();

View File

@@ -16,12 +16,14 @@
package org.jetbrains.kotlin.js.translate.intrinsic.functions.factories;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
import org.jetbrains.kotlin.js.backend.ast.JsExpression;
import org.jetbrains.kotlin.js.backend.ast.JsInvocation;
import org.jetbrains.kotlin.js.backend.ast.JsNameRef;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.js.patterns.DescriptorPredicate;
import org.jetbrains.kotlin.js.patterns.NamePredicate;
import org.jetbrains.kotlin.js.translate.callTranslator.CallInfo;
@@ -164,13 +166,14 @@ public final class TopLevelFIF extends CompositeFIF {
public static final KotlinFunctionIntrinsic TO_STRING = new KotlinFunctionIntrinsic("toString");
@NotNull
public static final FunctionIntrinsic CHAR_TO_STRING = new FunctionIntrinsic() {
public static final FunctionIntrinsic CHAR_TO_STRING = new FunctionIntrinsicWithReceiverComputed() {
@NotNull
@Override
public JsExpression apply(
@NotNull CallInfo callInfo, @NotNull List<? extends JsExpression> arguments, @NotNull TranslationContext context
@Nullable JsExpression receiver, @NotNull List<? extends JsExpression> arguments, @NotNull TranslationContext context
) {
return JsAstUtils.charToString(callInfo.getDispatchReceiver());
assert receiver != null;
return JsAstUtils.charToString(receiver);
}
};

View File

@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.js.translate.reference
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.js.backend.ast.*
@@ -28,6 +29,7 @@ import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.expression.PatternTranslator
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator
import org.jetbrains.kotlin.js.translate.general.Translation
import org.jetbrains.kotlin.js.translate.intrinsic.functions.factories.ArrayFIF
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
@@ -83,7 +85,7 @@ class CallArgumentTranslator private constructor(
var argsBeforeVararg: List<JsExpression>? = null
var concatArguments: MutableList<JsExpression>? = null
val argsToJsExpr = translateUnresolvedArguments(context(), resolvedCall)
var isVarargTypePrimitive: Boolean? = null
var varargPrimitiveType: PrimitiveType? = null
for (parameterDescriptor in valueParameters) {
val actualArgument = valueArgumentsByIndex[parameterDescriptor.index]
@@ -96,19 +98,21 @@ class CallArgumentTranslator private constructor(
hasSpreadOperator = arguments.any { it.getSpreadElement() != null }
}
isVarargTypePrimitive = KotlinBuiltIns.isPrimitiveType(parameterDescriptor.original.varargElementType!!)
varargPrimitiveType = KotlinBuiltIns.getPrimitiveType(parameterDescriptor.original.varargElementType!!)
if (hasSpreadOperator) {
if (isNativeFunctionCall) {
argsBeforeVararg = result
result = mutableListOf<JsExpression>()
concatArguments = prepareConcatArguments(arguments, translateResolvedArgument(actualArgument, argsToJsExpr))
concatArguments = prepareConcatArguments(arguments,
translateResolvedArgument(actualArgument, argsToJsExpr),
null)
}
else {
result.addAll(translateVarargArgument(actualArgument,
argsToJsExpr,
actualArgument.arguments.size > 1,
isVarargTypePrimitive))
varargPrimitiveType))
}
}
else {
@@ -116,7 +120,7 @@ class CallArgumentTranslator private constructor(
result.addAll(translateResolvedArgument(actualArgument, argsToJsExpr))
}
else {
result.addAll(translateVarargArgument(actualArgument, argsToJsExpr, true, isVarargTypePrimitive))
result.addAll(translateVarargArgument(actualArgument, argsToJsExpr, true, varargPrimitiveType))
}
}
}
@@ -130,14 +134,14 @@ class CallArgumentTranslator private constructor(
assert(concatArguments != null) { "concatArguments should not be null" }
if (!result.isEmpty()) {
concatArguments!!.add(JsArrayLiteral(result).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE })
concatArguments!!.add(toArray(null, result))
}
if (!argsBeforeVararg!!.isEmpty()) {
concatArguments!!.add(0, JsArrayLiteral(argsBeforeVararg).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE })
concatArguments!!.add(0, toArray(null, argsBeforeVararg))
}
result = mutableListOf(concatArgumentsIfNeeded(concatArguments!!, isVarargTypePrimitive!!, true))
result = mutableListOf(concatArgumentsIfNeeded(concatArguments!!, varargPrimitiveType, true))
if (receiver != null) {
cachedReceiver = context().getOrDeclareTemporaryConstVariable(receiver)
@@ -210,6 +214,74 @@ class CallArgumentTranslator private constructor(
return result
}
private fun translateVarargArgument(
resolvedArgument: ResolvedValueArgument,
translatedArgs: Map<ValueArgument, JsExpression>,
shouldWrapVarargInArray: Boolean,
varargPrimitiveType: PrimitiveType?
): List<JsExpression> {
val arguments = resolvedArgument.arguments
if (arguments.isEmpty()) {
return if (shouldWrapVarargInArray) {
return listOf(toArray(varargPrimitiveType, listOf<JsExpression>()))
}
else {
listOf()
}
}
val list = translateResolvedArgument(resolvedArgument, translatedArgs)
return if (shouldWrapVarargInArray) {
val concatArguments = prepareConcatArguments(arguments, list, varargPrimitiveType)
val concatExpression = concatArgumentsIfNeeded(concatArguments, varargPrimitiveType, false)
listOf(concatExpression)
}
else {
listOf(JsAstUtils.invokeMethod(list[0], "slice"))
}
}
private fun toArray(varargPrimitiveType: PrimitiveType?, elements: List<JsExpression>): JsExpression {
return ArrayFIF.castToTypedArray(program(),
varargPrimitiveType,
JsArrayLiteral(elements).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE })
}
private fun prepareConcatArguments(
arguments: List<ValueArgument>,
list: List<JsExpression>,
varargPrimitiveType: PrimitiveType?
): MutableList<JsExpression> {
assert(arguments.isNotEmpty()) { "arguments.size should not be 0" }
assert(arguments.size == list.size) { "arguments.size: " + arguments.size + " != list.size: " + list.size }
val concatArguments = mutableListOf<JsExpression>()
var lastArrayContent = mutableListOf<JsExpression>()
val size = arguments.size
for (index in 0..size - 1) {
val valueArgument = arguments[index]
val expressionArgument = list[index]
if (valueArgument.getSpreadElement() != null) {
if (lastArrayContent.size > 0) {
concatArguments.add(toArray(varargPrimitiveType, lastArrayContent))
lastArrayContent = mutableListOf<JsExpression>()
}
concatArguments.add(expressionArgument)
}
else {
lastArrayContent.add(expressionArgument)
}
}
if (lastArrayContent.size > 0) {
concatArguments.add(toArray(varargPrimitiveType, lastArrayContent))
}
return concatArguments
}
companion object {
@JvmStatic fun translate(resolvedCall: ResolvedCall<*>, receiver: JsExpression?, context: TranslationContext): ArgumentsInfo {
@@ -240,43 +312,15 @@ class CallArgumentTranslator private constructor(
return resolvedArgument.arguments.map { translatedArgs[it]!! }
}
private fun translateVarargArgument(
resolvedArgument: ResolvedValueArgument,
translatedArgs: Map<ValueArgument, JsExpression>,
shouldWrapVarargInArray: Boolean,
isVarargTypePrimitive: Boolean
): List<JsExpression> {
val arguments = resolvedArgument.arguments
if (arguments.isEmpty()) {
return if (shouldWrapVarargInArray) {
return listOf(JsArrayLiteral(listOf<JsExpression>()).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE })
}
else {
listOf()
}
}
val list = translateResolvedArgument(resolvedArgument, translatedArgs)
return if (shouldWrapVarargInArray) {
val concatArguments = prepareConcatArguments(arguments, list)
val concatExpression = concatArgumentsIfNeeded(concatArguments, isVarargTypePrimitive, false)
listOf(concatExpression)
}
else {
listOf(JsAstUtils.invokeMethod(list[0], "slice"))
}
}
private fun concatArgumentsIfNeeded(
concatArguments: List<JsExpression>,
isVarargTypePrimitive: Boolean,
varargPrimitiveType: PrimitiveType?,
isMixed: Boolean
): JsExpression {
assert(concatArguments.isNotEmpty()) { "concatArguments.size should not be 0" }
if (concatArguments.size > 1) {
if (isVarargTypePrimitive) {
if (varargPrimitiveType != null) {
val method = if (isMixed) "arrayConcat" else "primitiveArrayConcat"
return JsAstUtils.invokeKotlinFunction(method, concatArguments[0],
*concatArguments.subList(1, concatArguments.size).toTypedArray())
@@ -289,39 +333,6 @@ class CallArgumentTranslator private constructor(
return concatArguments[0]
}
}
private fun prepareConcatArguments(arguments: List<ValueArgument>, list: List<JsExpression>): MutableList<JsExpression> {
assert(arguments.isNotEmpty()) { "arguments.size should not be 0" }
assert(arguments.size == list.size) { "arguments.size: " + arguments.size + " != list.size: " + list.size }
val concatArguments = mutableListOf<JsExpression>()
var lastArrayContent = mutableListOf<JsExpression>()
val size = arguments.size
for (index in 0..size - 1) {
val valueArgument = arguments[index]
val expressionArgument = list[index]
if (valueArgument.getSpreadElement() != null) {
if (lastArrayContent.size > 0) {
concatArguments.add(JsArrayLiteral(lastArrayContent).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE })
concatArguments.add(expressionArgument)
lastArrayContent = mutableListOf<JsExpression>()
}
else {
concatArguments.add(expressionArgument)
}
}
else {
lastArrayContent.add(expressionArgument)
}
}
if (lastArrayContent.size > 0) {
concatArguments.add(JsArrayLiteral(lastArrayContent).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE })
}
return concatArguments
}
}
}

View File

@@ -0,0 +1,14 @@
<!-- for benchmarking in browser -->
<html>
<head>
<script type="application/javascript" src="../../../dist/js/kotlin.js"></script>
<script type="application/javascript" src="../../../dist/classes/kotlin-test-js/kotlin-test.js"></script>
<script type="application/javascript" src="../../../js/js.translator/testData/out/box/standardClasses/stringBuilder_v5.js"></script>
<script type="application/javascript" src="https://rawgit.com/lodash/lodash/4.17.4/dist/lodash.js"></script>
<script type="application/javascript" src="https://rawgit.com/bestiejs/benchmark.js/2.1.2/benchmark.js"></script>
</head>
<a href="#" onclick="console.log(new Benchmark('box', JS_TESTS.foo.box).run().toString());">benchmark</a>
<body>
</body>
</html>

View File

@@ -228,11 +228,10 @@ class ArraysTest {
assertEquals(arr.asList().toString(), arr.contentToString())
}
// @Ignore("KT-16056")
// @Test fun contentDeepToString() {
// val arr = arrayOf("aa", 1, null, charArrayOf('d'))
// assertEquals("[aa, 1, null, [d]]", arr.contentDeepToString())
// }
@Test fun contentDeepToString() {
val arr = arrayOf("aa", 1, null, charArrayOf('d'))
assertEquals("[aa, 1, null, [d]]", arr.contentDeepToString())
}
@Test fun contentDeepToStringNoRecursion() {
// a[b[a, b]]

View File

@@ -211,33 +211,43 @@ object CommonArrays {
}
}
fun f_plusCollection() = f("plus(elements: Collection<T>)") {
operator(true)
fun f_plusCollection() =
(listOf(InvariantArraysOfObjects to null) + PrimitiveType.defaultPrimitives.map { ArraysOfPrimitives to it }).map {
val (family, primitive) = it
f("plus(elements: Collection<T>)") {
operator(true)
// TODO: inline arrayPlusCollection when @PublishedAPI is available
// inline(Platform.JS, Inline.Yes)
// annotations(Platform.JS, """@Suppress("NOTHING_TO_INLINE")""")
only(family)
if (family == InvariantArraysOfObjects) {
only(Platform.JS, ArraysOfObjects)
}
only(InvariantArraysOfObjects, ArraysOfPrimitives)
only(Platform.JS, ArraysOfObjects, ArraysOfPrimitives)
// TODO: inline arrayPlusCollection when @PublishedAPI is available
// inline(Platform.JS, Inline.Yes)
// annotations(Platform.JS, """@Suppress("NOTHING_TO_INLINE")""")
returns("SELF")
returns(Platform.JS, ArraysOfObjects) { "Array<T>" }
doc { "Returns an array containing all elements of the original array and then all elements of the given [elements] collection." }
body(Platform.JVM) {
"""
var index = size
val result = java.util.Arrays.copyOf(this, index + elements.size)
for (element in elements) result[index++] = element
return result
"""
}
body(Platform.JS) {
"""
return arrayPlusCollection(this, elements)
"""
}
}
returns("SELF")
returns(Platform.JS, ArraysOfObjects) { "Array<T>" }
doc { "Returns an array containing all elements of the original array and then all elements of the given [elements] collection." }
body(Platform.JVM) {
"""
var index = size
val result = java.util.Arrays.copyOf(this, index + elements.size)
for (element in elements) result[index++] = element
return result
"""
}
if (primitive != null) {
only(primitive)
}
when (primitive) {
null, PrimitiveType.Char, PrimitiveType.Boolean, PrimitiveType.Long ->
body(Platform.JS) { "return arrayPlusCollection(this, elements)" }
else ->
body(Platform.JS) { "return typedArrayPlusCollection(this, this.copyOf(size + elements.size), elements)" }
}
}
}
fun f_plusArray() = f("plus(elements: SELF)") {
operator(true)
@@ -327,27 +337,29 @@ object CommonArrays {
inline(Platform.JVM, Inline.Only)
doc { "Returns new array which is a copy of the original array, resized to the given [newSize]." }
val defaultValue: String
if (primitive != null) {
only(primitive)
returns("SELF")
defaultValue = when (primitive) {
PrimitiveType.Boolean -> false.toString()
PrimitiveType.Char -> "0"
else -> "ZERO"
when (primitive) {
PrimitiveType.Boolean ->
body(Platform.JS) { "return arrayCopyResize(this, newSize, false)" }
PrimitiveType.Char ->
body(Platform.JS) { "return arrayCopyResize(this, newSize, 0)" }
PrimitiveType.Long ->
body(Platform.JS) { "return arrayCopyResize(this, newSize, ZERO)" }
else ->
body(Platform.JS) { "return arrayCopy(this, ${primitive}Array(newSize))" }
}
} else {
returns { "Array<T?>" }
defaultValue = "null"
}
else {
returns { "Array<T?>" }
body(Platform.JS) { "return arrayCopyResize(this, newSize, null)" }
}
body(Platform.JVM) {
"return java.util.Arrays.copyOf(this, newSize)"
}
body(Platform.JS) {
"""
return arrayCopyResize(this, newSize, $defaultValue)
"""
}
}
}
@@ -481,12 +493,13 @@ object CommonArrays {
return result as Array<T>
"""
}
if (primitive == PrimitiveType.Char) {
body(Platform.JS) { "return Array<Char>(size, { i -> this[i] })" }
}
else {
body(Platform.JS) { "return copyOf().unsafeCast<Array<T>>()" }
when (primitive) {
PrimitiveType.Char ->
body(Platform.JS) { "return Array<Char>(size, { i -> this[i] })" }
PrimitiveType.Boolean, PrimitiveType.Long ->
body(Platform.JS) { "return copyOf().unsafeCast<Array<T>>()" }
else ->
body(Platform.JS) { "return js(\"Array.prototype.slice.call\")(this)" }
}
}
}
@@ -496,7 +509,10 @@ object CommonArrays {
fun templates() =
listOf(f_plusElement()) +
f_plusElementOperator() +
listOf(f_plusCollection(), f_plusArray(), f_copyOf(), f_copyOfRange()) +
f_plusCollection() +
listOf(f_plusArray()) +
f_copyOf() +
listOf(f_copyOfRange()) +
f_copyOfResized() +
f_sortPrimitives() +
listOf(f_sort(), f_sortWith(), f_asList()) +