summaryrefslogtreecommitdiffstats
path: root/js/src/builtin/Tuple.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/builtin/Tuple.js')
-rw-r--r--js/src/builtin/Tuple.js711
1 files changed, 711 insertions, 0 deletions
diff --git a/js/src/builtin/Tuple.js b/js/src/builtin/Tuple.js
new file mode 100644
index 0000000000..59a09112cd
--- /dev/null
+++ b/js/src/builtin/Tuple.js
@@ -0,0 +1,711 @@
+/* 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);
+}