/* 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/. */ function TupleToArray(obj) { var len = TupleLength(obj); var items = std_Array(len); for (var k = 0; k < len; k++) { DefineDataProperty(items, k, obj[k]); } return items; } // proposal-record-tuple // Tuple.prototype.toSorted() function TupleToSorted(comparefn) { /* Step 1. */ if (comparefn !== undefined && !IsCallable(comparefn)) { ThrowTypeError(JSMSG_BAD_SORT_ARG); } /* Step 2. */ var T = ThisTupleValue(this); /* Step 3. */ var items = TupleToArray(T); var sorted = callFunction(ArraySort, items, comparefn); return std_Tuple_unchecked(sorted); } // proposal-record-tuple // Tuple.prototype.toSpliced() function TupleToSpliced(start, deleteCount /*, ...items */) { /* Steps 1-2. */ var list = ThisTupleValue(this); /* Step 3. */ var len = TupleLength(list); /* Step 4. */ var relativeStart = ToInteger(start); /* Step 5. */ var actualStart; if (relativeStart < 0) { actualStart = std_Math_max(len + relativeStart, 0); } else { actualStart = std_Math_min(relativeStart, len); } /* Step 6. */ var insertCount; var actualDeleteCount; if (ArgumentsLength() === 0) { insertCount = 0; actualDeleteCount = 0; } else if (ArgumentsLength() === 1) { /* Step 7. */ insertCount = 0; actualDeleteCount = len - actualStart; } else { /* Step 8a. */ insertCount = ArgumentsLength() - 2; /* Step 8b. */ let dc = ToInteger(deleteCount); /* Step 8c. */ actualDeleteCount = std_Math_min(std_Math_max(dc, 0), len - actualStart); } /* Step 9. */ if (len + insertCount - actualDeleteCount > MAX_NUMERIC_INDEX) { ThrowTypeError(JSMSG_TOO_LONG_ARRAY); } /* Step 10. */ var k = 0; /* Step 11. */ /* Step 12. */ var itemCount = insertCount; /* Step 13. */ var newList = []; /* Step 14. */ while (k < actualStart) { /* Step 14a. */ let E = list[k]; /* Step 14b. */ DefineDataProperty(newList, k, E); /* Step 14c. */ k++; } /* Step 15. */ var itemK = 0; /* Step 16. */ while (itemK < itemCount) { /* Step 16a. */ let E = GetArgument(itemK + 2); /* Step 16b. */ if (IsObject(E)) { ThrowTypeError(JSMSG_RECORD_TUPLE_NO_OBJECT); } /* Step 16c. */ DefineDataProperty(newList, k, E); /* Step 16d. */ k++; itemK++; } /* Step 17. */ itemK = actualStart + actualDeleteCount; /* Step 18. */ while (itemK < len) { /* Step 18a. */ let E = list[itemK]; /* Step 18b. */ DefineDataProperty(newList, k, E); /* Step 18c. */ k++; itemK++; } /* Step 19. */ return std_Tuple_unchecked(newList); } // proposal-record-tuple // Tuple.prototype.toReversed() function TupleToReversed() { /* Step 1. */ var T = ThisTupleValue(this); /* Step 2 not necessary */ /* Step 3. */ var len = TupleLength(T); var newList = []; /* Step 4. */ for (var k = len - 1; k >= 0; k--) { /* Step 5a. */ let E = T[k]; /* Step 5b. */ DefineDataProperty(newList, len - k - 1, E); } /* Step 5. */ return std_Tuple_unchecked(newList); } // ES 2017 draft (April 8, 2016) 22.1.3.1.1 function IsConcatSpreadable(O) { // Step 1. if (!IsObject(O) && !IsTuple(O)) { return false; } // Step 2. var spreadable = O[GetBuiltinSymbol("isConcatSpreadable")]; // Step 3. if (spreadable !== undefined) { return ToBoolean(spreadable); } if (IsTuple(O)) { return true; } // Step 4. return IsArray(O); } // proposal-record-tuple // Tuple.prototype.concat() function TupleConcat() { /* Step 1 */ var T = ThisTupleValue(this); /* Step 2 (changed to include all elements from T). */ var list = TupleToArray(T); /* Step 3 */ var n = list.length; /* Step 4 not necessary due to changed step 2. */ /* Step 5 */ for (var i = 0; i < ArgumentsLength(); i++) { /* Step 5a. */ let E = GetArgument(i); /* Step 5b. */ var spreadable = IsConcatSpreadable(E); /* Step 5c. */ if (spreadable) { /* Step 5c.i. */ var k = 0; /* Step 5c.ii */ var len = ToLength(E.length); /* Step 5c.iii */ if (n + len > MAX_NUMERIC_INDEX) { ThrowTypeError(JSMSG_TOO_LONG_ARRAY); } /* Step 5c.iv */ while (k < len) { /* Step 5c.iv.2 */ var exists = E[k] !== undefined; /* Step 5c.iv.3 */ if (exists) { /* Step 5c.iv.3.a */ var subElement = E[k]; /* Step 5c.iv.3.b */ if (IsObject(subElement)) { ThrowTypeError(JSMSG_RECORD_TUPLE_NO_OBJECT); } /* Step 5c.iv.3.c */ DefineDataProperty(list, n, subElement); /* Step 5c.iv.4 */ n++; } /* Step 5c.iv.5 */ k++; } } else { /* Step 5d. */ /* Step 5d.ii. */ if (n >= MAX_NUMERIC_INDEX) { ThrowTypeError(JSMSG_TOO_LONG_ARRAY); } /* Step 5d.iii. */ if (IsObject(E)) { ThrowTypeError(JSMSG_RECORD_TUPLE_NO_OBJECT); } /* Step 5d.iv. */ DefineDataProperty(list, n, E); /* Step 5d.v. */ n++; } } /* Step 6 */ return std_Tuple_unchecked(list); } // proposal-record-tuple // Tuple.prototype.includes() function TupleIncludes(valueToFind /* , fromIndex */) { var fromIndex = ArgumentsLength() > 1 ? GetArgument(1) : undefined; return callFunction( std_Array_includes, ThisTupleValue(this), valueToFind, fromIndex ); } // proposal-record-tuple // Tuple.prototype.indexOf() function TupleIndexOf(valueToFind /* , fromIndex */) { var fromIndex = ArgumentsLength() > 1 ? GetArgument(1) : undefined; return callFunction( std_Array_indexOf, ThisTupleValue(this), valueToFind, fromIndex ); } // proposal-record-tuple // Tuple.prototype.join() function TupleJoin(separator) { let T = ThisTupleValue(this); // Step 2 let len = TupleLength(T); // Steps 3-4 var sep = ","; if (!IsNullOrUndefined(separator)) { let toString = IsCallable(separator.toString) ? separator.toString : std_Object_toString; sep = callContentFunction(toString, separator); } // Step 5 var R = ""; // Step 6 var k = 0; // Step 7 while (k < len) { // Step 7a if (k > 0) { R += sep; } // Step 7b let element = T[k]; // Step 7c var next = ""; if (!IsNullOrUndefined(element)) { let toString = IsCallable(element.toString) ? element.toString : std_Object_toString; next = callContentFunction(toString, element); } // Step 7d R += next; // Step 7e k++; } // Step 8 return R; } // proposal-record-tuple // Tuple.prototype.lastIndexOf() function TupleLastIndexOf(valueToFind /* , fromIndex */) { if (ArgumentsLength() < 2) { return callFunction( std_Array_lastIndexOf, ThisTupleValue(this), valueToFind ); } return callFunction( std_Array_lastIndexOf, ThisTupleValue(this), valueToFind, GetArgument(1) ); } // proposal-record-tuple // Tuple.prototype.toString() function TupleToString() { /* Step 1. */ var T = ThisTupleValue(this); /* Step 2. */ var func = T.join; if (!IsCallable(func)) { return callFunction(std_Object_toString, T); } /* Step 4. */ return callContentFunction(func, T); } // proposal-record-tuple // Tuple.prototype.toLocaleString() function TupleToLocaleString(locales, options) { var T = ThisTupleValue(this); return callContentFunction( ArrayToLocaleString, TupleToArray(T), locales, options ); } // proposal-record-tuple // Tuple.prototype.entries() function TupleEntries() { return CreateArrayIterator(this, ITEM_KIND_KEY_AND_VALUE); } // proposal-record-tuple // Tuple.prototype.keys() function TupleKeys() { return CreateArrayIterator(this, ITEM_KIND_KEY); } // proposal-record-tuple // Tuple.prototype.values() function $TupleValues() { return CreateArrayIterator(this, ITEM_KIND_VALUE); } SetCanonicalName($TupleValues, "values"); // proposal-record-tuple // Tuple.prototype.every() function TupleEvery(callbackfn) { return callContentFunction(ArrayEvery, ThisTupleValue(this), callbackfn); } // proposal-record-tuple // Tuple.prototype.filter() function TupleFilter(callbackfn) { /* Steps 1-2 */ var list = ThisTupleValue(this); /* Step 3. */ var len = TupleLength(list); /* Step 4. */ if (ArgumentsLength() === 0) { ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Tuple.prototype.filter"); } if (!IsCallable(callbackfn)) { ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn)); } /* Step 5. */ var newList = []; /* Step 6. */ var k = 0; var newK = 0; /* Step 7. */ var T = ArgumentsLength() > 1 ? GetArgument(1) : undefined; while (k < len) { /* Step 7a. */ var kValue = list[k]; /* Step 7b. */ var selected = ToBoolean( callContentFunction(callbackfn, T, kValue, k, list) ); /* Step 7c. */ if (selected) { /* Step 7c.i. */ DefineDataProperty(newList, newK++, kValue); } /* Step 7d. */ k++; } /* Step 8. */ return std_Tuple_unchecked(newList); } // proposal-record-tuple // Tuple.prototype.find() function TupleFind(predicate) { return callContentFunction(ArrayFind, ThisTupleValue(this), predicate); } // proposal-record-tuple // Tuple.prototype.findIndex() function TupleFindIndex(predicate) { return callContentFunction(ArrayFindIndex, ThisTupleValue(this), predicate); } // proposal-record-tuple // Tuple.prototype.forEach() function TupleForEach(callbackfn) { return callContentFunction(ArrayForEach, ThisTupleValue(this), callbackfn); } // proposal-record-tuple // Tuple.prototype.map() function TupleMap(callbackfn) { /* Steps 1-2. */ var list = ThisTupleValue(this); /* Step 3. */ var len = TupleLength(list); /* Step 4. */ if (!IsCallable(callbackfn)) { ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn)); } /* Step 5. */ var newList = []; /* Steps 6-7. */ var thisArg = ArgumentsLength() > 1 ? GetArgument(1) : undefined; for (var k = 0; k < len; k++) { /* Step 7a. */ var kValue = list[k]; /* Step 7b. */ var mappedValue = callContentFunction(callbackfn, thisArg, kValue, k, list); /* Step 7c */ if (IsObject(mappedValue)) { ThrowTypeError(JSMSG_RECORD_TUPLE_NO_OBJECT); } /* Step 7d. */ DefineDataProperty(newList, k, mappedValue); } /* Step 8. */ return std_Tuple_unchecked(newList); } // proposal-record-tuple // Tuple.prototype.reduce() function TupleReduce(callbackfn /*, initialVal */) { if (ArgumentsLength() < 2) { return callContentFunction(ArrayReduce, ThisTupleValue(this), callbackfn); } return callContentFunction( ArrayReduce, ThisTupleValue(this), callbackfn, GetArgument(1) ); } // proposal-record-tuple // Tuple.prototype.reduceRight() function TupleReduceRight(callbackfn /*, initialVal*/) { if (ArgumentsLength() < 2) { return callContentFunction( ArrayReduceRight, ThisTupleValue(this), callbackfn ); } return callContentFunction( ArrayReduceRight, ThisTupleValue(this), callbackfn, GetArgument(1) ); } // proposal-record-tuple // Tuple.prototype.some() function TupleSome(callbackfn) { return callContentFunction(ArraySome, ThisTupleValue(this), callbackfn); } function FlattenIntoTuple(target, source, depth) { /* Step 1. */ assert(IsArray(target), "FlattenIntoTuple: target is not array"); /* Step 2. */ assert(IsTuple(source), "FlattenIntoTuple: source is not tuple"); /* Step 3 not needed. */ /* Step 4. */ var mapperFunction = undefined; var thisArg = undefined; var mapperIsPresent = ArgumentsLength() > 3; if (mapperIsPresent) { mapperFunction = GetArgument(3); assert( IsCallable(mapperFunction) && ArgumentsLength() > 4 && depth === 1, "FlattenIntoTuple: mapper function must be callable, thisArg present, and depth === 1" ); thisArg = GetArgument(4); } /* Step 5. */ var sourceIndex = 0; /* Step 6. */ for (var k = 0; k < source.length; k++) { var element = source[k]; /* Step 6a. */ if (mapperIsPresent) { /* Step 6a.i. */ element = callContentFunction( mapperFunction, thisArg, element, sourceIndex, source ); /* Step 6a.ii. */ if (IsObject(element)) { ThrowTypeError(JSMSG_RECORD_TUPLE_NO_OBJECT); } } /* Step 6b. */ if (depth > 0 && IsTuple(element)) { FlattenIntoTuple(target, element, depth - 1); } else { /* Step 6c.i. */ var len = ToLength(target.length); /* Step 6c.ii. */ if (len > MAX_NUMERIC_INDEX) { ThrowTypeError(JSMSG_TOO_LONG_ARRAY); } /* Step 6c.iii. */ DefineDataProperty(target, len, element); } /* Step 6d. */ sourceIndex++; } } // proposal-record-tuple // Tuple.prototype.flat() function TupleFlat() { /* Steps 1-2. */ var list = ThisTupleValue(this); /* Step 3. */ var depthNum = 1; /* Step 4. */ if (ArgumentsLength() && GetArgument(0) !== undefined) { depthNum = ToInteger(GetArgument(0)); } /* Step 5. */ var flat = []; /* Step 6. */ FlattenIntoTuple(flat, list, depthNum); /* Step 7. */ return std_Tuple_unchecked(flat); } // proposal-record-tuple // Tuple.prototype.flatMap() function TupleFlatMap(mapperFunction /*, thisArg*/) { /* Steps 1-2. */ var list = ThisTupleValue(this); /* Step 3. */ if (ArgumentsLength() === 0) { ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Tuple.prototype.flatMap"); } if (!IsCallable(mapperFunction)) { ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, mapperFunction)); } /* Step 4. */ var flat = []; /* Step 5. */ var thisArg = ArgumentsLength() > 1 ? GetArgument(1) : undefined; FlattenIntoTuple(flat, list, 1, mapperFunction, thisArg); /* Step 6. */ return std_Tuple_unchecked(flat); } function TupleFrom(items /*, mapFn, thisArg */) { /* Step 1 */ var mapping; var mapfn = ArgumentsLength() < 2 ? undefined : GetArgument(1); var thisArg = ArgumentsLength() < 3 ? undefined : GetArgument(2); if (mapfn === undefined) { mapping = false; } else { /* Step 2 */ if (!IsCallable(mapfn)) { ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, GetArgument(1))); } mapping = true; } /* Step 3 */ var list = []; /* Step 4 */ var k = 0; /* Step 5 */ let usingIterator = GetMethod(items, GetBuiltinSymbol("iterator")); /* Step 6 */ if (usingIterator !== undefined) { /* Step 6a. */ let adder = function(value) { var mappedValue; /* Step 6a.i */ if (mapping) { /* Step 6a.i.1. */ mappedValue = callContentFunction(mapfn, thisArg, value, k); } else { /* Step 6a.ii. */ mappedValue = value; } /* Step 6a.iii. */ if (IsObject(mappedValue)) { ThrowTypeError(JSMSG_RECORD_TUPLE_NO_OBJECT); } /* Step 6a.iv. */ DefineDataProperty(list, k, mappedValue); /* Step 6a.v. */ k++; }; /* Step 6b. */ for (var nextValue of allowContentIterWith(items, usingIterator)) { adder(nextValue); } /* Step 6c. */ return std_Tuple_unchecked(list); } /* Step 7 */ /* We assume items is an array-like object */ /* Step 8 */ let arrayLike = ToObject(items); /* Step 9 */ let len = ToLength(arrayLike.length); /* Step 10 */ while (k < len) { /* Step 10a not necessary */ /* Step 10b */ let kValue = arrayLike[k]; /* Step 10c-d */ let mappedValue = mapping ? callContentFunction(mapfn, thisArg, kValue, k) : kValue; /* Step 10e */ if (IsObject(mappedValue)) { ThrowTypeError(JSMSG_RECORD_TUPLE_NO_OBJECT); } /* Step 10f */ DefineDataProperty(list, k, mappedValue); /* Step 10g */ k++; } /* Step 11 */ return std_Tuple_unchecked(list); }