diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /js/src/builtin/Array.js | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/builtin/Array.js')
-rw-r--r-- | js/src/builtin/Array.js | 1173 |
1 files changed, 1173 insertions, 0 deletions
diff --git a/js/src/builtin/Array.js b/js/src/builtin/Array.js new file mode 100644 index 0000000000..4f1f48d3bc --- /dev/null +++ b/js/src/builtin/Array.js @@ -0,0 +1,1173 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9 +// 22.1.3.14 Array.prototype.indexOf ( searchElement [ , fromIndex ] ) +function ArrayIndexOf(searchElement/*, fromIndex*/) { + // Step 1. + var O = ToObject(this); + + // Step 2. + var len = ToLength(O.length); + + // Step 3. + if (len === 0) + return -1; + + // Steps 4-5. + var n = arguments.length > 1 ? ToInteger(arguments[1]) : 0; + + // Step 6. + if (n >= len) + return -1; + + // Steps 7-8. + var k; + if (n >= 0) { + // Step 7.a. + k = n; + } else { + // Step 8.a. + k = len + n; + + // Step 8.b. + if (k < 0) + k = 0; + } + + // Step 9. + for (; k < len; k++) { + if (k in O && O[k] === searchElement) + return k; + } + + // Step 10. + return -1; +} + +// ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9 +// 22.1.3.17 Array.prototype.lastIndexOf ( searchElement [ , fromIndex ] ) +function ArrayLastIndexOf(searchElement/*, fromIndex*/) { + // Step 1. + var O = ToObject(this); + + // Step 2. + var len = ToLength(O.length); + + // Step 3. + if (len === 0) + return -1; + + // Step 4. + var n = arguments.length > 1 ? ToInteger(arguments[1]) : len - 1; + + // Steps 5-6. + var k; + if (n > len - 1) + k = len - 1; + else if (n < 0) + k = len + n; + else + k = n; + + // Step 7. + for (; k >= 0; k--) { + if (k in O && O[k] === searchElement) + return k; + } + + // Step 8. + return -1; +} + +/* ES5 15.4.4.16. */ +function ArrayEvery(callbackfn/*, thisArg*/) { + /* Step 1. */ + var O = ToObject(this); + + /* Steps 2-3. */ + var len = ToLength(O.length); + + /* Step 4. */ + if (arguments.length === 0) + ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.every"); + if (!IsCallable(callbackfn)) + ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn)); + + /* Step 5. */ + var T = arguments.length > 1 ? arguments[1] : void 0; + + /* Steps 6-7. */ + /* Steps a (implicit), and d. */ + for (var k = 0; k < len; k++) { + /* Step b */ + if (k in O) { + /* Step c. */ + if (!callContentFunction(callbackfn, T, O[k], k, O)) + return false; + } + } + + /* Step 8. */ + return true; +} + +/* ES5 15.4.4.17. */ +function ArraySome(callbackfn/*, thisArg*/) { + /* Step 1. */ + var O = ToObject(this); + + /* Steps 2-3. */ + var len = ToLength(O.length); + + /* Step 4. */ + if (arguments.length === 0) + ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.some"); + if (!IsCallable(callbackfn)) + ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn)); + + /* Step 5. */ + var T = arguments.length > 1 ? arguments[1] : void 0; + + /* Steps 6-7. */ + /* Steps a (implicit), and d. */ + for (var k = 0; k < len; k++) { + /* Step b */ + if (k in O) { + /* Step c. */ + if (callContentFunction(callbackfn, T, O[k], k, O)) + return true; + } + } + + /* Step 8. */ + return false; +} + +// ES2018 draft rev 3bbc87cd1b9d3bf64c3e68ca2fe9c5a3f2c304c0 +// 22.1.3.25 Array.prototype.sort ( comparefn ) +function ArraySort(comparefn) { + // Step 1. + if (comparefn !== undefined) { + if (!IsCallable(comparefn)) + ThrowTypeError(JSMSG_BAD_SORT_ARG); + } + + // Step 2. + var O = ToObject(this); + + // First try to sort the array in native code, if that fails, indicated by + // returning |false| from ArrayNativeSort, sort it in self-hosted code. + if (callFunction(ArrayNativeSort, O, comparefn)) + return O; + + // Step 3. + var len = ToLength(O.length); + + if (len <= 1) + return O; + + /* 22.1.3.25.1 Runtime Semantics: SortCompare( x, y ) */ + var wrappedCompareFn = comparefn; + comparefn = function(x, y) { + /* Steps 1-3. */ + if (x === undefined) { + if (y === undefined) + return 0; + return 1; + } + if (y === undefined) + return -1; + + /* Step 4.a. */ + var v = ToNumber(wrappedCompareFn(x, y)); + + /* Step 4.b-c. */ + return v !== v ? 0 : v; + }; + + return MergeSort(O, len, comparefn); +} + +/* ES5 15.4.4.18. */ +function ArrayForEach(callbackfn/*, thisArg*/) { + /* Step 1. */ + var O = ToObject(this); + + /* Steps 2-3. */ + var len = ToLength(O.length); + + /* Step 4. */ + if (arguments.length === 0) + ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.forEach"); + if (!IsCallable(callbackfn)) + ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn)); + + /* Step 5. */ + var T = arguments.length > 1 ? arguments[1] : void 0; + + /* Steps 6-7. */ + /* Steps a (implicit), and d. */ + for (var k = 0; k < len; k++) { + /* Step b */ + if (k in O) { + /* Step c. */ + callContentFunction(callbackfn, T, O[k], k, O); + } + } + + /* Step 8. */ + return void 0; +} + +/* ES 2016 draft Mar 25, 2016 22.1.3.15. */ +function ArrayMap(callbackfn/*, thisArg*/) { + /* Step 1. */ + var O = ToObject(this); + + /* Step 2. */ + var len = ToLength(O.length); + + /* Step 3. */ + if (arguments.length === 0) + ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.map"); + if (!IsCallable(callbackfn)) + ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn)); + + /* Step 4. */ + var T = arguments.length > 1 ? arguments[1] : void 0; + + /* Steps 5. */ + var A = ArraySpeciesCreate(O, len); + + /* Steps 6-7. */ + /* Steps 7.a (implicit), and 7.d. */ + for (var k = 0; k < len; k++) { + /* Steps 7.b-c. */ + if (k in O) { + /* Steps 7.c.i-iii. */ + var mappedValue = callContentFunction(callbackfn, T, O[k], k, O); + _DefineDataProperty(A, k, mappedValue); + } + } + + /* Step 8. */ + return A; +} + +/* ES 2016 draft Mar 25, 2016 22.1.3.7 Array.prototype.filter. */ +function ArrayFilter(callbackfn/*, thisArg*/) { + /* Step 1. */ + var O = ToObject(this); + + /* Step 2. */ + var len = ToLength(O.length); + + /* Step 3. */ + if (arguments.length === 0) + ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.filter"); + if (!IsCallable(callbackfn)) + ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn)); + + /* Step 4. */ + var T = arguments.length > 1 ? arguments[1] : void 0; + + /* Step 5. */ + var A = ArraySpeciesCreate(O, 0); + + /* Steps 6-8. */ + /* Steps 8.a (implicit), and 8.d. */ + for (var k = 0, to = 0; k < len; k++) { + /* Steps 8.b-c. */ + if (k in O) { + /* Step 8.c.i. */ + var kValue = O[k]; + /* Step 8.c.ii. */ + var selected = callContentFunction(callbackfn, T, kValue, k, O); + /* Step 8.c.iii. */ + if (selected) + _DefineDataProperty(A, to++, kValue); + } + } + + /* Step 9. */ + return A; +} + +/* ES5 15.4.4.21. */ +function ArrayReduce(callbackfn/*, initialValue*/) { + /* Step 1. */ + var O = ToObject(this); + + /* Steps 2-3. */ + var len = ToLength(O.length); + + /* Step 4. */ + if (arguments.length === 0) + ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.reduce"); + if (!IsCallable(callbackfn)) + ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn)); + + /* Step 6. */ + var k = 0; + + /* Steps 5, 7-8. */ + var accumulator; + if (arguments.length > 1) { + accumulator = arguments[1]; + } else { + /* Step 5. */ + // Add an explicit |throw| here and below to inform Ion that the + // ThrowTypeError calls exit this function. + if (len === 0) + throw ThrowTypeError(JSMSG_EMPTY_ARRAY_REDUCE); + + // Use a |do-while| loop to let Ion know that the loop will definitely + // be entered at least once. When Ion is then also able to inline the + // |in| operator, it can optimize away the whole loop. + var kPresent = false; + do { + if (k in O) { + kPresent = true; + break; + } + } while (++k < len); + if (!kPresent) + throw ThrowTypeError(JSMSG_EMPTY_ARRAY_REDUCE); + + // Moved outside of the loop to ensure the assignment is non-conditional. + accumulator = O[k++]; + } + + /* Step 9. */ + /* Steps a (implicit), and d. */ + for (; k < len; k++) { + /* Step b */ + if (k in O) { + /* Step c. */ + accumulator = callbackfn(accumulator, O[k], k, O); + } + } + + /* Step 10. */ + return accumulator; +} + +/* ES5 15.4.4.22. */ +function ArrayReduceRight(callbackfn/*, initialValue*/) { + /* Step 1. */ + var O = ToObject(this); + + /* Steps 2-3. */ + var len = ToLength(O.length); + + /* Step 4. */ + if (arguments.length === 0) + ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.reduce"); + if (!IsCallable(callbackfn)) + ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn)); + + /* Step 6. */ + var k = len - 1; + + /* Steps 5, 7-8. */ + var accumulator; + if (arguments.length > 1) { + accumulator = arguments[1]; + } else { + /* Step 5. */ + // Add an explicit |throw| here and below to inform Ion that the + // ThrowTypeError calls exit this function. + if (len === 0) + throw ThrowTypeError(JSMSG_EMPTY_ARRAY_REDUCE); + + // Use a |do-while| loop to let Ion know that the loop will definitely + // be entered at least once. When Ion is then also able to inline the + // |in| operator, it can optimize away the whole loop. + var kPresent = false; + do { + if (k in O) { + kPresent = true; + break; + } + } while (--k >= 0); + if (!kPresent) + throw ThrowTypeError(JSMSG_EMPTY_ARRAY_REDUCE); + + // Moved outside of the loop to ensure the assignment is non-conditional. + accumulator = O[k--]; + } + + /* Step 9. */ + /* Steps a (implicit), and d. */ + for (; k >= 0; k--) { + /* Step b */ + if (k in O) { + /* Step c. */ + accumulator = callbackfn(accumulator, O[k], k, O); + } + } + + /* Step 10. */ + return accumulator; +} + +/* ES6 draft 2013-05-14 15.4.3.23. */ +function ArrayFind(predicate/*, thisArg*/) { + /* Steps 1-2. */ + var O = ToObject(this); + + /* Steps 3-5. */ + var len = ToLength(O.length); + + /* Step 6. */ + if (arguments.length === 0) + ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.find"); + if (!IsCallable(predicate)) + ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, predicate)); + + /* Step 7. */ + var T = arguments.length > 1 ? arguments[1] : undefined; + + /* Steps 8-9. */ + /* Steps a (implicit), and g. */ + for (var k = 0; k < len; k++) { + /* Steps a-c. */ + var kValue = O[k]; + /* Steps d-f. */ + if (callContentFunction(predicate, T, kValue, k, O)) + return kValue; + } + + /* Step 10. */ + return undefined; +} + +/* ES6 draft 2013-05-14 15.4.3.23. */ +function ArrayFindIndex(predicate/*, thisArg*/) { + /* Steps 1-2. */ + var O = ToObject(this); + + /* Steps 3-5. */ + var len = ToLength(O.length); + + /* Step 6. */ + if (arguments.length === 0) + ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.find"); + if (!IsCallable(predicate)) + ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, predicate)); + + /* Step 7. */ + var T = arguments.length > 1 ? arguments[1] : undefined; + + /* Steps 8-9. */ + /* Steps a (implicit), and g. */ + for (var k = 0; k < len; k++) { + /* Steps a-f. */ + if (callContentFunction(predicate, T, O[k], k, O)) + return k; + } + + /* Step 10. */ + return -1; +} + +// ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9 +// 22.1.3.3 Array.prototype.copyWithin ( target, start [ , end ] ) +function ArrayCopyWithin(target, start, end = undefined) { + // Step 1. + var O = ToObject(this); + + // Step 2. + var len = ToLength(O.length); + + // Step 3. + var relativeTarget = ToInteger(target); + + // Step 4. + var to = relativeTarget < 0 ? std_Math_max(len + relativeTarget, 0) + : std_Math_min(relativeTarget, len); + + // Step 5. + var relativeStart = ToInteger(start); + + // Step 6. + var from = relativeStart < 0 ? std_Math_max(len + relativeStart, 0) + : std_Math_min(relativeStart, len); + + // Step 7. + var relativeEnd = end === undefined ? len : ToInteger(end); + + // Step 8. + var final = relativeEnd < 0 ? std_Math_max(len + relativeEnd, 0) + : std_Math_min(relativeEnd, len); + + // Step 9. + var count = std_Math_min(final - from, len - to); + + // Steps 10-12. + if (from < to && to < (from + count)) { + // Steps 10.b-c. + from = from + count - 1; + to = to + count - 1; + + // Step 12. + while (count > 0) { + if (from in O) + O[to] = O[from]; + else + delete O[to]; + + from--; + to--; + count--; + } + } else { + // Step 12. + while (count > 0) { + if (from in O) + O[to] = O[from]; + else + delete O[to]; + + from++; + to++; + count--; + } + } + + // Step 13. + return O; +} + +// ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9 +// 22.1.3.6 Array.prototype.fill ( value [ , start [ , end ] ] ) +function ArrayFill(value, start = 0, end = undefined) { + // Step 1. + var O = ToObject(this); + + // Step 2. + var len = ToLength(O.length); + + // Step 3. + var relativeStart = ToInteger(start); + + // Step 4. + var k = relativeStart < 0 + ? std_Math_max(len + relativeStart, 0) + : std_Math_min(relativeStart, len); + + // Step 5. + var relativeEnd = end === undefined ? len : ToInteger(end); + + // Step 6. + var final = relativeEnd < 0 + ? std_Math_max(len + relativeEnd, 0) + : std_Math_min(relativeEnd, len); + + // Step 7. + for (; k < final; k++) { + O[k] = value; + } + + // Step 8. + return O; +} + +// ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9 +// 22.1.3.13 Array.prototype.includes ( searchElement [ , fromIndex ] ) +function ArrayIncludes(searchElement, fromIndex = 0) { + // Step 1. + var O = ToObject(this); + + // Step 2. + var len = ToLength(O.length); + + // Step 3. + if (len === 0) + return false; + + // Steps 4-5. + var n = ToInteger(fromIndex); + + // Steps 6-7. + var k; + if (n >= 0) { + // Step 6.a. + k = n; + } else { + // Step 7.a. + k = len + n; + + // Step 7.b. + if (k < 0) + k = 0; + } + + // Step 8. + while (k < len) { + // Steps 8.a-c. + if (SameValueZero(searchElement, O[k])) + return true; + + // Step 8.d. + k++; + } + + // Step 9. + return false; +} + +// ES6 draft specification, section 22.1.5.1, version 2013-09-05. +function CreateArrayIterator(obj, kind) { + var iteratedObject = ToObject(obj); + var iterator = NewArrayIterator(); + UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_TARGET, iteratedObject); + UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_NEXT_INDEX, 0); + UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_ITEM_KIND, kind); + return iterator; +} + +// ES6, 22.1.5.2.1 +// http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%arrayiteratorprototype%.next +function ArrayIteratorNext() { + // Step 1-3. + var obj; + if (!IsObject(this) || (obj = GuardToArrayIterator(this)) === null) { + return callFunction(CallArrayIteratorMethodIfWrapped, this, + "ArrayIteratorNext"); + } + + // Step 4. + var a = UnsafeGetReservedSlot(obj, ITERATOR_SLOT_TARGET); + var result = { value: undefined, done: false }; + + // Step 5. + if (a === null) { + result.done = true; + return result; + } + + // Step 6. + // The index might not be an integer, so we have to do a generic get here. + var index = UnsafeGetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX); + + // Step 7. + var itemKind = UnsafeGetInt32FromReservedSlot(obj, ITERATOR_SLOT_ITEM_KIND); + + // Step 8-9. + var len; + if (IsPossiblyWrappedTypedArray(a)) { + len = PossiblyWrappedTypedArrayLength(a); + + // If the length is non-zero, the buffer can't be detached. + if (len === 0) { + if (PossiblyWrappedTypedArrayHasDetachedBuffer(a)) + ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED); + } + } else { + len = ToLength(a.length); + } + + // Step 10. + if (index >= len) { + UnsafeSetReservedSlot(obj, ITERATOR_SLOT_TARGET, null); + result.done = true; + return result; + } + + // Step 11. + UnsafeSetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX, index + 1); + + // Step 16. + if (itemKind === ITEM_KIND_VALUE) { + result.value = a[index]; + return result; + } + + // Step 13. + if (itemKind === ITEM_KIND_KEY_AND_VALUE) { + var pair = [index, a[index]]; + result.value = pair; + return result; + } + + // Step 12. + assert(itemKind === ITEM_KIND_KEY, itemKind); + result.value = index; + return result; +} + +// Uncloned functions with `$` prefix are allocated as extended function +// to store the original name in `_SetCanonicalName`. +function $ArrayValues() { + return CreateArrayIterator(this, ITEM_KIND_VALUE); +} +_SetCanonicalName($ArrayValues, "values"); + +function ArrayEntries() { + return CreateArrayIterator(this, ITEM_KIND_KEY_AND_VALUE); +} + +function ArrayKeys() { + return CreateArrayIterator(this, ITEM_KIND_KEY); +} + +// ES 2017 draft 0f10dba4ad18de92d47d421f378233a2eae8f077 22.1.2.1 +function ArrayFrom(items, mapfn = undefined, thisArg = undefined) { + // Step 1. + var C = this; + + // Steps 2-3. + var mapping = mapfn !== undefined; + if (mapping && !IsCallable(mapfn)) + ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(1, mapfn)); + var T = thisArg; + + // Step 4. + // Inlined: GetMethod, steps 1-2. + var usingIterator = items[std_iterator]; + + // Step 5. + // Inlined: GetMethod, step 3. + if (usingIterator !== undefined && usingIterator !== null) { + // Inlined: GetMethod, step 4. + if (!IsCallable(usingIterator)) + ThrowTypeError(JSMSG_NOT_ITERABLE, DecompileArg(0, items)); + + // Steps 5.a-b. + var A = IsConstructor(C) ? new C() : []; + + // Step 5.c. + var iterator = MakeIteratorWrapper(items, usingIterator); + + // Step 5.d. + var k = 0; + + // Step 5.e + for (var nextValue of allowContentIter(iterator)) { + // Step 5.e.i. + // Disabled for performance reason. We won't hit this case on + // normal array, since _DefineDataProperty will throw before it. + // We could hit this when |A| is a proxy and it ignores + // |_DefineDataProperty|, but it happens only after too long loop. + /* + if (k >= 0x1fffffffffffff) + ThrowTypeError(JSMSG_TOO_LONG_ARRAY); + */ + + // Steps 5.e.vi-vii. + var mappedValue = mapping ? callContentFunction(mapfn, T, nextValue, k) : nextValue; + + // Steps 5.e.ii (reordered), 5.e.viii. + _DefineDataProperty(A, k++, mappedValue); + } + + // Step 5.e.iv. + A.length = k; + return A; + } + + // Step 7 is an assertion: items is not an Iterator. Testing this is + // literally the very last thing we did, so we don't assert here. + + // Steps 8-9. + var arrayLike = ToObject(items); + + // Steps 10-11. + var len = ToLength(arrayLike.length); + + // Steps 12-14. + var A = IsConstructor(C) ? new C(len) : std_Array(len); + + // Steps 15-16. + for (var k = 0; k < len; k++) { + // Steps 16.a-c. + var kValue = items[k]; + + // Steps 16.d-e. + var mappedValue = mapping ? callContentFunction(mapfn, T, kValue, k) : kValue; + + // Steps 16.f-g. + _DefineDataProperty(A, k, mappedValue); + } + + // Steps 17-18. + A.length = len; + + // Step 19. + return A; +} + +function MakeIteratorWrapper(items, method) { + assert(IsCallable(method), "method argument is a function"); + + // This function is not inlined in ArrayFrom, because function default + // parameters combined with nested functions are currently not optimized + // correctly. + return { + // Use a named function expression instead of a method definition, so + // we don't create an inferred name for this function at runtime. + [std_iterator]: function IteratorMethod() { + return callContentFunction(method, items); + }, + }; +} + +// ES2015 22.1.3.27 Array.prototype.toString. +function ArrayToString() { + // Steps 1-2. + var array = ToObject(this); + + // Steps 3-4. + var func = array.join; + + // Steps 5-6. + if (!IsCallable(func)) + return callFunction(std_Object_toString, array); + return callContentFunction(func, array); +} + +// ES2017 draft rev f8a9be8ea4bd97237d176907a1e3080dce20c68f +// 22.1.3.27 Array.prototype.toLocaleString ([ reserved1 [ , reserved2 ] ]) +// ES2017 Intl draft rev 78bbe7d1095f5ff3760ac4017ed366026e4cb276 +// 13.4.1 Array.prototype.toLocaleString ([ locales [ , options ]]) +function ArrayToLocaleString(locales, options) { + // Step 1 (ToObject already performed in native code). + assert(IsObject(this), "|this| should be an object"); + var array = this; + + // Step 2. + var len = ToLength(array.length); + + // Step 4. + if (len === 0) + return ""; + + // Step 5. + var firstElement = array[0]; + + // Steps 6-7. + var R; + if (firstElement === undefined || firstElement === null) { + R = ""; + } else { +#if JS_HAS_INTL_API + R = ToString(callContentFunction(firstElement.toLocaleString, firstElement, locales, options)); +#else + R = ToString(callContentFunction(firstElement.toLocaleString, firstElement)); +#endif + } + + // Step 3 (reordered). + // We don't (yet?) implement locale-dependent separators. + var separator = ","; + + // Steps 8-9. + for (var k = 1; k < len; k++) { + // Step 9.b. + var nextElement = array[k]; + + // Steps 9.a, 9.c-e. + R += separator; + if (!(nextElement === undefined || nextElement === null)) { +#if JS_HAS_INTL_API + R += ToString(callContentFunction(nextElement.toLocaleString, nextElement, locales, options)); +#else + R += ToString(callContentFunction(nextElement.toLocaleString, nextElement)); +#endif + } + } + + // Step 10. + return R; +} + +// ES 2016 draft Mar 25, 2016 22.1.2.5. +function $ArraySpecies() { + // Step 1. + return this; +} +_SetCanonicalName($ArraySpecies, "get [Symbol.species]"); + +// ES 2016 draft Mar 25, 2016 9.4.2.3. +function ArraySpeciesCreate(originalArray, length) { + // Step 1. + assert(typeof length == "number", "length should be a number"); + assert(length >= 0, "length should be a non-negative number"); + + // Step 2. + // eslint-disable-next-line no-compare-neg-zero + if (length === -0) + length = 0; + + // Step 4, 6. + if (!IsArray(originalArray)) + return std_Array(length); + + // Step 5.a. + var C = originalArray.constructor; + + // Step 5.b. + if (IsConstructor(C) && IsCrossRealmArrayConstructor(C)) + return std_Array(length); + + // Step 5.c. + if (IsObject(C)) { + // Step 5.c.i. + C = C[std_species]; + + // Optimized path for an ordinary Array. + if (C === GetBuiltinConstructor("Array")) + return std_Array(length); + + // Step 5.c.ii. + if (C === null) + return std_Array(length); + } + + // Step 6. + if (C === undefined) + return std_Array(length); + + // Step 7. + if (!IsConstructor(C)) + ThrowTypeError(JSMSG_NOT_CONSTRUCTOR, "constructor property"); + + // Step 8. + return new C(length); +} + +// ES 2017 draft (April 8, 2016) 22.1.3.1.1 +function IsConcatSpreadable(O) { + // Step 1. + if (!IsObject(O)) + return false; + + // Step 2. + var spreadable = O[std_isConcatSpreadable]; + + // Step 3. + if (spreadable !== undefined) + return ToBoolean(spreadable); + + // Step 4. + return IsArray(O); +} + +// ES 2016 draft Mar 25, 2016 22.1.3.1. +// Note: Array.prototype.concat.length is 1. +function ArrayConcat(arg1) { + // Step 1. + var O = ToObject(this); + + // Step 2. + var A = ArraySpeciesCreate(O, 0); + + // Step 3. + var n = 0; + + // Step 4 (implicit in |arguments|). + + // Step 5. + var i = 0, argsLen = arguments.length; + + // Step 5.a (first element). + var E = O; + + var k, len; + while (true) { + // Steps 5.b-c. + if (IsConcatSpreadable(E)) { + // Step 5.c.ii. + len = ToLength(E.length); + + // Step 5.c.iii. + if (n + len > MAX_NUMERIC_INDEX) + ThrowTypeError(JSMSG_TOO_LONG_ARRAY); + + if (IsPackedArray(A) && IsPackedArray(E)) { + // Step 5.c.i, 5.c.iv, and 5.c.iv.5. + for (k = 0; k < len; k++) { + // Steps 5.c.iv.1-3. + // IsPackedArray(E) ensures that |k in E| is always true. + _DefineDataProperty(A, n, E[k]); + + // Step 5.c.iv.4. + n++; + } + } else { + // Step 5.c.i, 5.c.iv, and 5.c.iv.5. + for (k = 0; k < len; k++) { + // Steps 5.c.iv.1-3. + if (k in E) + _DefineDataProperty(A, n, E[k]); + + // Step 5.c.iv.4. + n++; + } + } + } else { + // Step 5.d.i. + if (n >= MAX_NUMERIC_INDEX) + ThrowTypeError(JSMSG_TOO_LONG_ARRAY); + + // Step 5.d.ii. + _DefineDataProperty(A, n, E); + + // Step 5.d.iii. + n++; + } + + if (i >= argsLen) + break; + // Step 5.a (subsequent elements). + E = arguments[i]; + i++; + } + + // Step 6. + A.length = n; + + // Step 7. + return A; +} + +// ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9 +// 22.1.3.11 Array.prototype.flatMap ( mapperFunction [ , thisArg ] ) +function ArrayFlatMap(mapperFunction/*, thisArg*/) { + // Step 1. + var O = ToObject(this); + + // Step 2. + var sourceLen = ToLength(O.length); + + // Step 3. + if (!IsCallable(mapperFunction)) + ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, mapperFunction)); + + // Step 4. + var T = arguments.length > 1 ? arguments[1] : undefined; + + // Step 5. + var A = ArraySpeciesCreate(O, 0); + + // Step 6. + FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, T); + + // Step 7. + return A; +} + +// ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9 +// 22.1.3.10 Array.prototype.flat ( [ depth ] ) +function ArrayFlat(/* depth */) { + // Step 1. + var O = ToObject(this); + + // Step 2. + var sourceLen = ToLength(O.length); + + // Step 3. + var depthNum = 1; + + // Step 4. + if (arguments.length > 0 && arguments[0] !== undefined) + depthNum = ToInteger(arguments[0]); + + // Step 5. + var A = ArraySpeciesCreate(O, 0); + + // Step 6. + FlattenIntoArray(A, O, sourceLen, 0, depthNum); + + // Step 7. + return A; +} + +// ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9 +// 22.1.3.10.1 FlattenIntoArray ( target, source, sourceLen, start, depth [ , mapperFunction, thisArg ] ) +function FlattenIntoArray(target, source, sourceLen, start, depth, mapperFunction, thisArg) { + // Step 1. + var targetIndex = start; + + // Steps 2-3. + for (var sourceIndex = 0; sourceIndex < sourceLen; sourceIndex++) { + // Steps 3.a-c. + if (sourceIndex in source) { + // Step 3.c.i. + var element = source[sourceIndex]; + + if (mapperFunction) { + // Step 3.c.ii.1. + assert(arguments.length === 7, "thisArg is present"); + + // Step 3.c.ii.2. + element = callContentFunction(mapperFunction, thisArg, element, sourceIndex, source); + } + + // Step 3.c.iii. + var shouldFlatten = false; + + // Step 3.c.iv. + if (depth > 0) { + // Step 3.c.iv.1. + shouldFlatten = IsArray(element); + } + + // Step 3.c.v. + if (shouldFlatten) { + // Step 3.c.v.1. + var elementLen = ToLength(element.length); + + // Step 3.c.v.2. + targetIndex = FlattenIntoArray(target, element, elementLen, targetIndex, depth - 1); + } else { + // Step 3.c.vi.1. + if (targetIndex >= MAX_NUMERIC_INDEX) + ThrowTypeError(JSMSG_TOO_LONG_ARRAY); + + // Step 3.c.vi.2. + _DefineDataProperty(target, targetIndex, element); + + // Step 3.c.vi.3. + targetIndex++; + } + } + } + + // Step 4. + return targetIndex; +} + +// https://github.com/tc39/proposal-relative-indexing-method +// Array.prototype.at ( index ) +function ArrayAt(index) { + // Step 1. + var O = ToObject(this); + + // Step 2. + var len = ToLength(O.length); + + // Step 3. + var relativeIndex = ToInteger(index); + + // Steps 4-5. + var k; + if (relativeIndex >= 0) { + k = relativeIndex; + } else { + k = len + relativeIndex; + } + + // Step 6. + if (k < 0 || k >= len) { + return undefined; + } + + // Step 7. + return O[k]; +} +// This function is only barely too long for normal inlining. +_SetIsInlinableLargeFunction(ArrayAt); |