зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1566146 - Implement Set methods union, intersection, difference, symmetricDifference, isSubsetOf, isSuperSetOf, isDisjointFrom as per https://tc39.es/proposal-set-methods/ r=arai
Differential Revision: https://phabricator.services.mozilla.com/D131799
This commit is contained in:
Родитель
48a5fa5e43
Коммит
6f9c143d3d
|
@ -1148,3 +1148,25 @@ def enable_change_array_by_copy(value):
|
|||
|
||||
set_config("ENABLE_CHANGE_ARRAY_BY_COPY", enable_change_array_by_copy)
|
||||
set_define("ENABLE_CHANGE_ARRAY_BY_COPY", enable_change_array_by_copy)
|
||||
|
||||
# Enable New Set methods
|
||||
# ===================================================
|
||||
def use_new_set_methods():
|
||||
return False
|
||||
|
||||
|
||||
option(
|
||||
"--enable-new-set-methods",
|
||||
default=use_new_set_methods(),
|
||||
help="{Enable|Disable} New Set methods pref/command-line option (disabled by default)",
|
||||
)
|
||||
|
||||
|
||||
@depends("--enable-new-set-methods")
|
||||
def enable_new_set_methods(value):
|
||||
if value:
|
||||
return True
|
||||
|
||||
|
||||
set_config("ENABLE_NEW_SET_METHODS", enable_new_set_methods)
|
||||
set_define("ENABLE_NEW_SET_METHODS", enable_new_set_methods)
|
||||
|
|
|
@ -232,6 +232,14 @@ class JS_PUBLIC_API RealmCreationOptions {
|
|||
return *this;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_NEW_SET_METHODS
|
||||
bool getNewSetMethodsEnabled() const { return newSetMethods_; }
|
||||
RealmCreationOptions& setNewSetMethodsEnabled(bool flag) {
|
||||
newSetMethods_ = flag;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
// This flag doesn't affect JS engine behavior. It is used by Gecko to
|
||||
// mark whether content windows and workers are "Secure Context"s. See
|
||||
// https://w3c.github.io/webappsec-secure-contexts/
|
||||
|
@ -270,6 +278,9 @@ class JS_PUBLIC_API RealmCreationOptions {
|
|||
bool toSource_ = false;
|
||||
bool propertyErrorMessageFix_ = false;
|
||||
bool iteratorHelpers_ = false;
|
||||
#ifdef ENABLE_NEW_SET_METHODS
|
||||
bool newSetMethods_ = false;
|
||||
#endif
|
||||
bool secureContext_ = false;
|
||||
};
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ MSG_DEF(JSMSG_READ_ONLY, 1, JSEXN_TYPEERR, "{0} is read-only")
|
|||
MSG_DEF(JSMSG_CANT_DELETE, 1, JSEXN_TYPEERR, "property {0} is non-configurable and can't be deleted")
|
||||
MSG_DEF(JSMSG_CANT_TRUNCATE_ARRAY, 0, JSEXN_TYPEERR, "can't delete non-configurable array element")
|
||||
MSG_DEF(JSMSG_NOT_FUNCTION, 1, JSEXN_TYPEERR, "{0} is not a function")
|
||||
MSG_DEF(JSMSG_PROPERTY_NOT_CALLABLE, 1, JSEXN_TYPEERR, "{0} property is not callable")
|
||||
MSG_DEF(JSMSG_NOT_CONSTRUCTOR, 1, JSEXN_TYPEERR, "{0} is not a constructor")
|
||||
MSG_DEF(JSMSG_BOGUS_CONSTRUCTOR, 1, JSEXN_TYPEERR, "{0} constructor can't be used directly")
|
||||
MSG_DEF(JSMSG_CANT_CONVERT_TO, 2, JSEXN_TYPEERR, "can't convert {0} to {1}")
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* 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 IteratorIdentity() {
|
||||
function IteratorIdentity() {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,40 @@ function IteratorClose(iteratorRecord, value) {
|
|||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* ES2022 draft rev c5f683e61d5dce703650f1c90d2309c46f8c157a
|
||||
*
|
||||
* GetIterator ( obj [ , hint [ , method ] ] )
|
||||
* https://tc39.es/ecma262/#sec-getiterator
|
||||
*
|
||||
* Optimized for single argument
|
||||
*/
|
||||
function GetIteratorSync(obj) {
|
||||
// Steps 1 & 2 skipped as we know we want the sync iterator method
|
||||
var method = GetMethod(obj, GetBuiltinSymbol("iterator"))
|
||||
|
||||
// Step 3. Let iterator be ? Call(method, obj).
|
||||
var iterator = callContentFunction(method, obj);
|
||||
|
||||
// Step 4. If Type(iterator) is not Object, throw a TypeError exception.
|
||||
if (!IsObject(iterator)) {
|
||||
ThrowTypeError(JSMSG_NOT_ITERABLE, obj === null ? "null" : typeof obj);
|
||||
}
|
||||
|
||||
// Step 5. Let nextMethod be ? GetV(iterator, "next").
|
||||
var nextMethod = iterator.next;
|
||||
|
||||
// Step 6. Let iteratorRecord be the Record { [[Iterator]]: iterator, [[NextMethod]]: nextMethod, [[Done]]: false }.
|
||||
var iteratorRecord = {
|
||||
iterator,
|
||||
nextMethod,
|
||||
done: false
|
||||
};
|
||||
|
||||
// Step 7. Return iteratorRecord.
|
||||
return iteratorRecord;
|
||||
}
|
||||
|
||||
/* Iterator Helpers proposal 1.1.1 */
|
||||
function GetIteratorDirect(obj) {
|
||||
// Step 1.
|
||||
|
|
|
@ -1201,6 +1201,15 @@ const JSFunctionSpec SetObject::methods[] = {
|
|||
JS_FN("entries", entries, 0, 0),
|
||||
JS_FN("clear", clear, 0, 0),
|
||||
JS_SELF_HOSTED_FN("forEach", "SetForEach", 2, 0),
|
||||
#ifdef ENABLE_NEW_SET_METHODS
|
||||
JS_SELF_HOSTED_FN("union", "SetUnion", 1, 0),
|
||||
JS_SELF_HOSTED_FN("difference", "SetDifference", 1, 0),
|
||||
JS_SELF_HOSTED_FN("intersection", "SetIntersection", 1, 0),
|
||||
JS_SELF_HOSTED_FN("symmetricDifference", "SetSymmetricDifference", 1, 0),
|
||||
JS_SELF_HOSTED_FN("isSubsetOf", "SetIsSubsetOf", 1, 0),
|
||||
JS_SELF_HOSTED_FN("isSupersetOf", "SetIsSupersetOf", 1, 0),
|
||||
JS_SELF_HOSTED_FN("isDisjointFrom", "SetIsDisjointFrom", 1, 0),
|
||||
#endif
|
||||
JS_FN("values", values, 0, 0),
|
||||
// @@iterator and |keys| re-defined in finishInit so that they have the
|
||||
// same identity as |values|.
|
||||
|
|
|
@ -261,6 +261,8 @@ class SetObject : public NativeObject {
|
|||
// interfaces, etc.)
|
||||
static SetObject* create(JSContext* cx, HandleObject proto = nullptr);
|
||||
static uint32_t size(JSContext* cx, HandleObject obj);
|
||||
[[nodiscard]] static bool add(JSContext* cx, unsigned argc, Value* vp);
|
||||
[[nodiscard]] static bool has(JSContext* cx, unsigned argc, Value* vp);
|
||||
[[nodiscard]] static bool has(JSContext* cx, HandleObject obj,
|
||||
HandleValue key, bool* rval);
|
||||
[[nodiscard]] static bool clear(JSContext* cx, HandleObject obj);
|
||||
|
@ -310,9 +312,7 @@ class SetObject : public NativeObject {
|
|||
[[nodiscard]] static bool size_impl(JSContext* cx, const CallArgs& args);
|
||||
[[nodiscard]] static bool size(JSContext* cx, unsigned argc, Value* vp);
|
||||
[[nodiscard]] static bool has_impl(JSContext* cx, const CallArgs& args);
|
||||
[[nodiscard]] static bool has(JSContext* cx, unsigned argc, Value* vp);
|
||||
[[nodiscard]] static bool add_impl(JSContext* cx, const CallArgs& args);
|
||||
[[nodiscard]] static bool add(JSContext* cx, unsigned argc, Value* vp);
|
||||
[[nodiscard]] static bool delete_impl(JSContext* cx, const CallArgs& args);
|
||||
[[nodiscard]] static bool delete_(JSContext* cx, unsigned argc, Value* vp);
|
||||
[[nodiscard]] static bool values_impl(JSContext* cx, const CallArgs& args);
|
||||
|
|
|
@ -19,6 +19,503 @@ function SetConstructorInit(iterable) {
|
|||
callContentFunction(adder, set, nextValue);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_NEW_SET_METHODS
|
||||
// New Set methods proposal
|
||||
//
|
||||
// Set.prototype.union(iterable)
|
||||
// https://tc39.es/proposal-set-methods/#Set.prototype.union
|
||||
function SetUnion(iterable) {
|
||||
// Step 1. Let set be the this value.
|
||||
var set = this;
|
||||
|
||||
// Step 2. If Type(set) is not Object, throw a TypeError exception.
|
||||
if (!IsObject(set)) {
|
||||
ThrowTypeError(
|
||||
JSMSG_OBJECT_REQUIRED,
|
||||
set === null ? "null" : typeof set
|
||||
);
|
||||
}
|
||||
|
||||
// Step 3. Let Ctr be ? SpeciesConstructor(set, %Set%).
|
||||
var Ctr = SpeciesConstructor(set, GetBuiltinConstructor("Set"));
|
||||
|
||||
// Step 4. Let newSet be ? Construct(Ctr, set).
|
||||
var newSet = new Ctr(set);
|
||||
|
||||
// Step 5. Let adder be ? Get(newSet, "add").
|
||||
var adder = newSet.add;
|
||||
|
||||
// Inlined AddEntryFromIterable Step 1. If IsCallable(adder) is false,
|
||||
// throw a TypeError exception.
|
||||
if (!IsCallable(adder)) {
|
||||
ThrowTypeError(JSMSG_PROPERTY_NOT_CALLABLE, "add");
|
||||
}
|
||||
|
||||
// Step 6. Return ? AddEntryFromIterable(newSet, iterable, adder).
|
||||
return AddEntryFromIterable(newSet, iterable, adder);
|
||||
}
|
||||
|
||||
// New Set methods proposal
|
||||
//
|
||||
// Set.prototype.intersection(iterable)
|
||||
// https://tc39.es/proposal-set-methods/#Set.prototype.intersection
|
||||
function SetIntersection(iterable) {
|
||||
// Step 1. Let set be the this value.
|
||||
var set = this;
|
||||
|
||||
// Step 2. If Type(set) is not Object, throw a TypeError exception.
|
||||
if (!IsObject(set)) {
|
||||
ThrowTypeError(
|
||||
JSMSG_OBJECT_REQUIRED,
|
||||
set === null ? "null" : typeof set
|
||||
);
|
||||
}
|
||||
|
||||
// Step 3. Let Ctr be ? SpeciesConstructor(set, %Set%).
|
||||
var Ctr = SpeciesConstructor(set, GetBuiltinConstructor("Set"));
|
||||
|
||||
// Step 4. Let newSet be ? Construct(Ctr).
|
||||
var newSet = new Ctr();
|
||||
|
||||
// Step 5. Let hasCheck be ? Get(set, "has").
|
||||
var hasCheck = set.has;
|
||||
|
||||
// Step 6. If IsCallable(hasCheck) is false, throw a TypeError exception.
|
||||
if (!IsCallable(hasCheck)) {
|
||||
ThrowTypeError(JSMSG_PROPERTY_NOT_CALLABLE, "has");
|
||||
}
|
||||
|
||||
// Step 7. Let adder be ? Get(newSet, "add").
|
||||
var adder = newSet.add;
|
||||
|
||||
// Step 8. If IsCallable(adder) is false, throw a TypeError exception.
|
||||
if (!IsCallable(adder)) {
|
||||
ThrowTypeError(JSMSG_PROPERTY_NOT_CALLABLE, "add");
|
||||
}
|
||||
|
||||
// Step 9. Let iteratorRecord be ? GetIterator(iterable).
|
||||
var iteratorRecord = GetIteratorSync(iterable);
|
||||
|
||||
// Step 10. Repeat,
|
||||
while (true) {
|
||||
// Step a. Let next be ? IteratorStep(iteratorRecord).
|
||||
var next = IteratorStep(iteratorRecord);
|
||||
|
||||
// Step b. If next is false, return newSet.
|
||||
if (!next) {
|
||||
return newSet;
|
||||
}
|
||||
|
||||
// Step c. Let nextValue be ? IteratorValue(next).
|
||||
var nextValue = next.value;
|
||||
var needClose = true;
|
||||
var has;
|
||||
try {
|
||||
// Step d. Let has be Call(hasCheck, set, « nextValue »).
|
||||
has = callContentFunction(hasCheck, set, nextValue);
|
||||
needClose = false;
|
||||
} finally {
|
||||
if (needClose) {
|
||||
// Step e. If has is an abrupt completion,
|
||||
// return ? IteratorClose(iteratorRecord, has).
|
||||
IteratorClose(iteratorRecord);
|
||||
}
|
||||
}
|
||||
|
||||
// Step f. If has.[[Value]] is true,
|
||||
if (has) {
|
||||
needClose = true;
|
||||
try {
|
||||
// Step i. Let status be Call(adder, newSet, « nextValue »).
|
||||
callContentFunction(adder, newSet, nextValue);
|
||||
needClose = false;
|
||||
} finally {
|
||||
if (needClose) {
|
||||
// Step ii. If status is an abrupt completion, return ?
|
||||
// IteratorClose(iteratorRecord, status).
|
||||
IteratorClose(iteratorRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// New Set methods proposal
|
||||
//
|
||||
// Set.prototype.difference(iterable)
|
||||
// https://tc39.es/proposal-set-methods/#Set.prototype.difference
|
||||
function SetDifference(iterable) {
|
||||
// Step 1. Let set be the this value.
|
||||
var set = this;
|
||||
|
||||
// Step 2. If Type(set) is not Object, throw a TypeError exception.
|
||||
if (!IsObject(set)) {
|
||||
ThrowTypeError(
|
||||
JSMSG_OBJECT_REQUIRED,
|
||||
set === null ? "null" : typeof set
|
||||
);
|
||||
}
|
||||
|
||||
// Step 3. Let Ctr be ? SpeciesConstructor(set, %Set%).
|
||||
var Ctr = SpeciesConstructor(set, GetBuiltinConstructor("Set"));
|
||||
|
||||
// Step 4. Let newSet be ? Construct(Ctr, set).
|
||||
var newSet = new Ctr(set);
|
||||
|
||||
// Step 5. Let remover be ? Get(newSet, "delete").
|
||||
var remover = newSet.delete;
|
||||
|
||||
// Step 6. If IsCallable(remover) is false, throw a TypeError exception.
|
||||
if (!IsCallable(remover)) {
|
||||
ThrowTypeError(JSMSG_PROPERTY_NOT_CALLABLE, "delete");
|
||||
}
|
||||
|
||||
// Step 7. Let iteratorRecord be ? GetIterator(iterable).
|
||||
var iteratorRecord = GetIteratorSync(iterable);
|
||||
|
||||
// Step 8. Repeat,
|
||||
while (true) {
|
||||
// Step a. Let next be ? IteratorStep(iteratorRecord).
|
||||
var next = IteratorStep(iteratorRecord);
|
||||
|
||||
// Step b. If next is false, return newSet.
|
||||
if (!next) {
|
||||
return newSet;
|
||||
}
|
||||
|
||||
// Step c. Let nextValue be ? IteratorValue(next).
|
||||
var nextValue = next.value;
|
||||
var needClose = true;
|
||||
try {
|
||||
// Step d. Let status be Call(remover, newSet, « nextValue »).
|
||||
callContentFunction(remover, newSet, nextValue);
|
||||
needClose = false;
|
||||
} finally {
|
||||
if (needClose) {
|
||||
// Step e. If status is an abrupt completion,
|
||||
// return ? IteratorClose(iteratorRecord, status).
|
||||
IteratorClose(iteratorRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// New Set methods proposal
|
||||
//
|
||||
// Set.prototype.symmetricDifference(iterable)
|
||||
// https://tc39.es/proposal-set-methods/#Set.prototype.symmetricDifference
|
||||
function SetSymmetricDifference(iterable) {
|
||||
// Step 1. Let set be the this value.
|
||||
var set = this;
|
||||
|
||||
// Step 2. If Type(set) is not Object, throw a TypeError exception.
|
||||
if (!IsObject(set)) {
|
||||
ThrowTypeError(
|
||||
JSMSG_OBJECT_REQUIRED,
|
||||
set === null ? "null" : typeof set
|
||||
);
|
||||
}
|
||||
|
||||
// Step 3. Let Ctr be ? SpeciesConstructor(set, %Set%).
|
||||
var Ctr = SpeciesConstructor(set, GetBuiltinConstructor("Set"));
|
||||
|
||||
// Step 4. Let newSet be ? Construct(Ctr, set).
|
||||
var newSet = new Ctr(set);
|
||||
|
||||
// Step 5. Let remover be ? Get(newSet, "delete").
|
||||
var remover = newSet.delete;
|
||||
|
||||
// Step 6. If IsCallable(remover) is false, throw a TypeError exception.
|
||||
if (!IsCallable(remover)) {
|
||||
ThrowTypeError(JSMSG_PROPERTY_NOT_CALLABLE, "delete");
|
||||
}
|
||||
|
||||
// Step 7. Let adder be ? Get(newSet, "add").
|
||||
var adder = newSet.add;
|
||||
|
||||
// Step 8. If IsCallable(adder) is false, throw a TypeError exception.
|
||||
if (!IsCallable(adder)) {
|
||||
ThrowTypeError(JSMSG_PROPERTY_NOT_CALLABLE, "add");
|
||||
}
|
||||
|
||||
// Step 9. Let iteratorRecord be ? GetIterator(iterable).
|
||||
var iteratorRecord = GetIteratorSync(iterable);
|
||||
|
||||
// Step 10. Repeat,
|
||||
while (true) {
|
||||
// Step a. Let next be ? IteratorStep(iteratorRecord).
|
||||
var next = IteratorStep(iteratorRecord);
|
||||
|
||||
// Step b. If next is false, return newSet.
|
||||
if (!next) {
|
||||
return newSet;
|
||||
}
|
||||
|
||||
// Step c. Let nextValue be ? IteratorValue(next).
|
||||
var nextValue = next.value;
|
||||
var needClose = true;
|
||||
var removed;
|
||||
try {
|
||||
// Step d. Let removed be Call(remover, newSet, « nextValue »).
|
||||
removed = callContentFunction(remover, newSet, nextValue);
|
||||
needClose = false;
|
||||
} finally {
|
||||
if (needClose) {
|
||||
// Step e. If removed is an abrupt completion,
|
||||
// return ? IteratorClose(iteratorRecord, removed).
|
||||
IteratorClose(iteratorRecord);
|
||||
}
|
||||
}
|
||||
|
||||
// Step f. If removed.[[Value]] is false,
|
||||
if (!removed) {
|
||||
needClose = true;
|
||||
try {
|
||||
// Step i. Let status be Call(adder, newSet, « nextValue »).
|
||||
callContentFunction(adder, newSet, nextValue);
|
||||
needClose = false;
|
||||
} finally {
|
||||
if (needClose) {
|
||||
// Step ii. If status is an abrupt completion,
|
||||
// return ? IteratorClose(iteratorRecord, status).
|
||||
IteratorClose(iteratorRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// New Set methods proposal
|
||||
//
|
||||
// Set.prototype.isSubsetOf(iterable)
|
||||
// https://tc39.es/proposal-set-methods/#Set.prototype.isSubsetOf
|
||||
function SetIsSubsetOf(iterable) {
|
||||
// Step 1. Let set be the this value.
|
||||
var set = this;
|
||||
|
||||
// Step 2. Let iteratorRecord be ? GetIterator(set).
|
||||
var iteratorRecord = GetIteratorSync(set);
|
||||
|
||||
// Step 3. If Type(iterable) is not Object, throw a TypeError exception.
|
||||
if (!IsObject(iterable)) {
|
||||
ThrowTypeError(
|
||||
JSMSG_OBJECT_REQUIRED,
|
||||
set === null ? "null" : typeof set
|
||||
);
|
||||
}
|
||||
|
||||
// Step 4. Let otherSet be iterable.
|
||||
var otherSet = iterable;
|
||||
|
||||
// Step 5. Let hasCheck be ? Get(otherSet, "has").
|
||||
var hasCheck = otherSet.has;
|
||||
|
||||
// Step 6. If IsCallable(hasCheck) is false,
|
||||
if (!IsCallable(hasCheck)) {
|
||||
// Step a. Let otherSet be ? Construct(%Set%).
|
||||
let set = GetBuiltinConstructor("Set");
|
||||
otherSet = new set();
|
||||
|
||||
// We are not inlining AddEntryFromIterable Step 1 here because we know
|
||||
// std_Set_add is callable Step b. Perform ?
|
||||
// AddEntryFromIterable(otherSet, iterable, %SetProto_add%).
|
||||
AddEntryFromIterable(otherSet, iterable, std_Set_add);
|
||||
|
||||
// Step c. Let hasCheck be %SetProto_has%.
|
||||
hasCheck = std_Set_has;
|
||||
}
|
||||
|
||||
// Step 7. Repeat,
|
||||
while (true) {
|
||||
// Step a. Let next be ? IteratorStep(iteratorRecord).
|
||||
var next = IteratorStep(iteratorRecord);
|
||||
|
||||
// Step b. If next is false, return true.
|
||||
if (!next) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Step c. Let nextValue be ? IteratorValue(next).
|
||||
var nextValue = next.value;
|
||||
var needClose = true;
|
||||
var has;
|
||||
try {
|
||||
// Step d. Let has be Call(hasCheck, otherSet, « nextValue »).
|
||||
has = callContentFunction(hasCheck, otherSet, nextValue);
|
||||
needClose = false;
|
||||
} finally {
|
||||
if (needClose) {
|
||||
// Step e. If has is an abrupt completion,
|
||||
// return ? IteratorClose(iteratorRecord, has).
|
||||
IteratorClose(iteratorRecord);
|
||||
}
|
||||
}
|
||||
|
||||
// Step f. If has.[[Value]] is false, return false.
|
||||
if (!has) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// New Set methods proposal
|
||||
//
|
||||
// Set.prototype.isSupersetOf(iterable)
|
||||
// https://tc39.es/proposal-set-methods/#Set.prototype.isSupersetOf
|
||||
function SetIsSupersetOf(iterable) {
|
||||
// Step 1. Let set be the this value.
|
||||
var set = this;
|
||||
|
||||
// Step 2. If Type(set) is not Object, throw a TypeError exception.
|
||||
if (!IsObject(set)) {
|
||||
ThrowTypeError(
|
||||
JSMSG_OBJECT_REQUIRED,
|
||||
set === null ? "null" : typeof set
|
||||
);
|
||||
}
|
||||
|
||||
// Step 3. Let hasCheck be ? Get(set, "has").
|
||||
var hasCheck = set.has;
|
||||
|
||||
// Step 4. If IsCallable(hasCheck) is false, throw a TypeError exception.
|
||||
if (!IsCallable(hasCheck)) {
|
||||
ThrowTypeError(JSMSG_PROPERTY_NOT_CALLABLE, "has");
|
||||
}
|
||||
|
||||
// Step 5. Let iteratorRecord be ? GetIterator(iterable).
|
||||
var iteratorRecord = GetIteratorSync(iterable);
|
||||
|
||||
// Step 6. Repeat,
|
||||
while (true) {
|
||||
// Step a. Let next be ? IteratorStep(iteratorRecord).
|
||||
var next = IteratorStep(iteratorRecord);
|
||||
|
||||
// Step b. If next is false, return true.
|
||||
if (!next) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Step c. Let nextValue be ? IteratorValue(next).
|
||||
var nextValue = next.value;
|
||||
var needClose = true;
|
||||
var has;
|
||||
try {
|
||||
// Step d. Let has be Call(hasCheck, set, « nextValue »).
|
||||
has = callContentFunction(hasCheck, set, nextValue);
|
||||
needClose = false;
|
||||
} finally {
|
||||
if (needClose) {
|
||||
// Step e. If has is an abrupt completion,
|
||||
// return ? IteratorClose(iteratorRecord, has).
|
||||
IteratorClose(iteratorRecord);
|
||||
}
|
||||
}
|
||||
|
||||
// Step f. If has.[[Value]] is false, return false.
|
||||
if (!has) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// New Set methods proposal
|
||||
//
|
||||
// Set.prototype.isDisjointFrom(iterable)
|
||||
// https://tc39.es/proposal-set-methods/#Set.prototype.isDisjointFrom
|
||||
function SetIsDisjointFrom(iterable) {
|
||||
// Step 1. Let set be the this value.
|
||||
var set = this;
|
||||
|
||||
// Step 2. If Type(set) is not Object, throw a TypeError exception.
|
||||
if (!IsObject(set)) {
|
||||
ThrowTypeError(
|
||||
JSMSG_OBJECT_REQUIRED,
|
||||
set === null ? "null" : typeof set
|
||||
);
|
||||
}
|
||||
|
||||
// Step 3. Let hasCheck be ? Get(set, "has").
|
||||
var hasCheck = set.has;
|
||||
|
||||
// Step 4. If IsCallable(hasCheck) is false, throw a TypeError exception.
|
||||
if (!IsCallable(hasCheck)) {
|
||||
ThrowTypeError(JSMSG_PROPERTY_NOT_CALLABLE, "has");
|
||||
}
|
||||
|
||||
// Step 5. Let iteratorRecord be ? GetIterator(iterable).
|
||||
var iteratorRecord = GetIteratorSync(iterable);
|
||||
|
||||
// Step 6. Repeat,
|
||||
while (true) {
|
||||
// Step a. Let next be ? IteratorStep(iteratorRecord).
|
||||
var next = IteratorStep(iteratorRecord);
|
||||
|
||||
// Step b. If next is false, return true.
|
||||
if (!next) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Step c. Let nextValue be ? IteratorValue(next).
|
||||
var nextValue = next.value;
|
||||
var needClose = true;
|
||||
var has;
|
||||
try {
|
||||
// Step d. Let has be Call(hasCheck, set, « nextValue »).
|
||||
has = callContentFunction(hasCheck, set, nextValue);
|
||||
needClose = false;
|
||||
} finally {
|
||||
if (needClose) {
|
||||
// Step e. If has is an abrupt completion,
|
||||
// return ? IteratorClose(iteratorRecord, has).
|
||||
IteratorClose(iteratorRecord);
|
||||
}
|
||||
}
|
||||
|
||||
// Step f. If has.[[Value]] is true, return false.
|
||||
if (has) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// New Set methods proposal
|
||||
//
|
||||
// AddEntryFromIterable ( target, iterable, adder )
|
||||
// https://tc39.es/proposal-set-methods/#AddEntryFromIterable
|
||||
function AddEntryFromIterable(target, iterable, adder) {
|
||||
assert(IsCallable(adder), "adder argument is callable");
|
||||
|
||||
// Step 2. Let iteratorRecord be ? GetIterator(iterable).
|
||||
var iteratorRecord = GetIteratorSync(iterable);
|
||||
|
||||
// Step 3. Repeat,
|
||||
while (true) {
|
||||
// Step a. Let next be ? IteratorStep(iteratorRecord).
|
||||
var next = IteratorStep(iteratorRecord);
|
||||
|
||||
// Step b. If next is false, return target.
|
||||
if (!next) {
|
||||
return target;
|
||||
}
|
||||
|
||||
// Step c. Let nextValue be ? IteratorValue(next).
|
||||
var nextValue = next.value;
|
||||
var needClose = true;
|
||||
try {
|
||||
// Step d. Let status be Call(adder, target, « nextValue »).
|
||||
callContentFunction(adder, target, nextValue);
|
||||
needClose = false;
|
||||
} finally {
|
||||
if (needClose) {
|
||||
// Step e. If status is an abrupt completion,
|
||||
// return ? IteratorClose(iteratorRecord, status).
|
||||
IteratorClose(iteratorRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// ES2018 draft rev f83aa38282c2a60c6916ebc410bfdf105a0f6a54
|
||||
// 23.2.3.6 Set.prototype.forEach ( callbackfn [ , thisArg ] )
|
||||
function SetForEach(callbackfn, thisArg = undefined) {
|
||||
|
|
|
@ -211,6 +211,14 @@ static bool GetRealmConfiguration(JSContext* cx, unsigned argc, Value* vp) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_NEW_SET_METHODS
|
||||
bool newSetMethods = cx->realm()->creationOptions().getNewSetMethodsEnabled();
|
||||
if (!JS_SetProperty(cx, info, "enableNewSetMethods",
|
||||
newSetMethods ? TrueHandleValue : FalseHandleValue)) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
args.rval().setObject(*info);
|
||||
return true;
|
||||
}
|
||||
|
@ -531,6 +539,15 @@ static bool GetBuildConfiguration(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return false;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_NEW_SET_METHODS
|
||||
value = BooleanValue(true);
|
||||
#else
|
||||
value = BooleanValue(false);
|
||||
#endif
|
||||
if (!JS_SetProperty(cx, info, "new-set-methods", value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
args.rval().setObject(*info);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -628,6 +628,9 @@ bool shell::enableErgonomicBrandChecks = true;
|
|||
#ifdef ENABLE_CHANGE_ARRAY_BY_COPY
|
||||
bool shell::enableChangeArrayByCopy = false;
|
||||
#endif
|
||||
#ifdef ENABLE_NEW_SET_METHODS
|
||||
bool shell::enableNewSetMethods = true;
|
||||
#endif
|
||||
bool shell::enableClassStaticBlocks = true;
|
||||
#ifdef JS_GC_ZEAL
|
||||
uint32_t shell::gZealBits = 0;
|
||||
|
@ -4316,7 +4319,11 @@ static void SetStandardRealmOptions(JS::RealmOptions& options) {
|
|||
: JS::WeakRefSpecifier::Disabled)
|
||||
.setToSourceEnabled(enableToSource)
|
||||
.setPropertyErrorMessageFixEnabled(enablePropertyErrorMessageFix)
|
||||
.setIteratorHelpersEnabled(enableIteratorHelpers);
|
||||
.setIteratorHelpersEnabled(enableIteratorHelpers)
|
||||
#ifdef ENABLE_NEW_SET_METHODS
|
||||
.setNewSetMethodsEnabled(enableNewSetMethods)
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool CheckRealmOptions(JSContext* cx,
|
||||
|
@ -11287,6 +11294,9 @@ static bool SetContextOptions(JSContext* cx, const OptionParser& op) {
|
|||
!op.getBoolOption("disable-ergonomic-brand-checks");
|
||||
#ifdef ENABLE_CHANGE_ARRAY_BY_COPY
|
||||
enableChangeArrayByCopy = op.getBoolOption("enable-change-array-by-copy");
|
||||
#endif
|
||||
#ifdef ENABLE_NEW_SET_METHODS
|
||||
enableNewSetMethods = op.getBoolOption("enable-new-set-methods");
|
||||
#endif
|
||||
enableClassStaticBlocks = !op.getBoolOption("disable-class-static-blocks");
|
||||
useFdlibmForSinCosTan = op.getBoolOption("use-fdlibm-for-sin-cos-tan");
|
||||
|
@ -12294,6 +12304,15 @@ int main(int argc, char** argv) {
|
|||
#else
|
||||
!op.addBoolOption('\0', "enable-change-array-by-copy", "no-op") ||
|
||||
!op.addBoolOption('\0', "disable-change-array-by-copy", "no-op") ||
|
||||
#endif
|
||||
#ifdef ENABLE_NEW_SET_METHODS
|
||||
!op.addBoolOption('\0', "enable-new-set-methods",
|
||||
"Enable New Set methods") ||
|
||||
!op.addBoolOption('\0', "disable-new-set-methods",
|
||||
"Disable New Set methods") ||
|
||||
#else
|
||||
!op.addBoolOption('\0', "enable-new-set-methods", "no-op") ||
|
||||
!op.addBoolOption('\0', "disable-new-set-methods", "no-op") ||
|
||||
#endif
|
||||
!op.addBoolOption('\0', "enable-top-level-await",
|
||||
"Enable top-level await") ||
|
||||
|
|
|
@ -138,6 +138,9 @@ extern bool enableErgonomicBrandChecks;
|
|||
#ifdef ENABLE_CHANGE_ARRAY_BY_COPY
|
||||
extern bool enableChangeArrayByCopy;
|
||||
#endif
|
||||
#ifdef ENABLE_NEW_SET_METHODS
|
||||
extern bool enableNewSetMethods;
|
||||
#endif
|
||||
extern bool enableClassStaticBlocks;
|
||||
#ifdef JS_GC_ZEAL
|
||||
extern uint32_t gZealBits;
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* https://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
if (typeof getBuildConfiguration === "undefined") {
|
||||
var getBuildConfiguration = SpecialPowers.Cu.getJSTestingFunctions().getBuildConfiguration;
|
||||
}
|
||||
|
||||
if (typeof getRealmConfiguration === "undefined") {
|
||||
var getRealmConfiguration = SpecialPowers.Cu.getJSTestingFunctions().getRealmConfiguration;
|
||||
}
|
||||
|
||||
if (getBuildConfiguration()['new-set-methods'] && getRealmConfiguration().enableNewSetMethods) {
|
||||
|
||||
assertEq(typeof Set.prototype.difference, 'function');
|
||||
assertEq(Set.prototype.difference.length, 1);
|
||||
assertEq(Set.prototype.difference.name, 'difference');
|
||||
|
||||
assertSetContainsExactOrderedItems(new Set([1, true, null]).difference(new Set()), [1, true, null]);
|
||||
assertSetContainsExactOrderedItems(new Set([1, true, null]).difference([1, true, null]), []);
|
||||
assertSetContainsExactOrderedItems(new Set([1, 2, 3]).difference([2, 3, 4]), [1]);
|
||||
assertSetContainsExactOrderedItems(new Set([1, 2, 3]).difference([4]), [1, 2, 3]);
|
||||
// Works when the argument is a custom iterable which follows the Symbol.iterator protocol
|
||||
assertSetContainsExactOrderedItems(new Set([1, 2, 3]).difference(makeArrayIterator([3, 4])), [1, 2]);
|
||||
assertSetContainsExactOrderedItems(new Set(['a','d']).difference('abc'), ['d']);
|
||||
|
||||
// Works when the `this` is a custom iterable which follows the Symbol.iterator protocol
|
||||
assertSetContainsExactOrderedItems(Set.prototype.difference.call(makeArrayIterator([1, 2, 3, 3, 2]), [4, 5, 6]), [1, 2, 3]);
|
||||
|
||||
// Does not modify the original set object
|
||||
const set = new Set([1]);
|
||||
assertEq(set.difference([1]) !== set, true);
|
||||
|
||||
// Argument must be iterable
|
||||
assertThrowsInstanceOf(function () {
|
||||
const set = new Set();
|
||||
set.difference();
|
||||
}, TypeError);
|
||||
for (const arg of [null, {}, true, 1, undefined, NaN, Symbol()]) {
|
||||
assertThrowsInstanceOf(function () {
|
||||
const set = new Set();
|
||||
set.difference(arg);
|
||||
}, TypeError);
|
||||
}
|
||||
|
||||
// `this` must be an Object
|
||||
for (const arg of [null, undefined, Symbol()]) {
|
||||
assertThrowsInstanceOf(function () {
|
||||
Set.prototype.difference.call(arg, []);
|
||||
}, TypeError);
|
||||
}
|
||||
|
||||
// `this` must be iterable
|
||||
assertThrowsInstanceOf(function () {
|
||||
Set.prototype.difference.call({}, []);
|
||||
}, TypeError);
|
||||
} else {
|
||||
assertEq(typeof Set.prototype.difference, 'undefined');
|
||||
}
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* https://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
if (typeof getBuildConfiguration === "undefined") {
|
||||
var getBuildConfiguration = SpecialPowers.Cu.getJSTestingFunctions().getBuildConfiguration;
|
||||
}
|
||||
|
||||
if (typeof getRealmConfiguration === "undefined") {
|
||||
var getRealmConfiguration = SpecialPowers.Cu.getJSTestingFunctions().getRealmConfiguration;
|
||||
}
|
||||
|
||||
if (getBuildConfiguration()['new-set-methods'] && getRealmConfiguration().enableNewSetMethods) {
|
||||
|
||||
assertEq(typeof Set.prototype.intersection, 'function');
|
||||
assertEq(Set.prototype.intersection.length, 1);
|
||||
assertEq(Set.prototype.intersection.name, 'intersection');
|
||||
|
||||
assertSetContainsExactOrderedItems(new Set([1, true, null]).intersection(new Set()), []);
|
||||
assertSetContainsExactOrderedItems(new Set([1, true, null]).intersection([1, true, null]), [1, true, null]);
|
||||
assertSetContainsExactOrderedItems(new Set([1, 2, 3]).intersection([2, 3, 4]), [2, 3]);
|
||||
assertSetContainsExactOrderedItems(new Set([1, 2, 3]).intersection([4]), []);
|
||||
// Works when the argument is a custom iterable which follows the Symbol.iterator protocol
|
||||
assertSetContainsExactOrderedItems(new Set([1, 2, 3]).intersection(makeArrayIteratorWithHasMethod([3, 4])), [3]);
|
||||
assertSetContainsExactOrderedItems(new Set(['a']).intersection('abc'), ['a']);
|
||||
|
||||
// Works when the `this` is a custom iterable which follows the Symbol.iterator protocol and has a `has` method
|
||||
assertSetContainsExactOrderedItems(Set.prototype.intersection.call(makeArrayIteratorWithHasMethod([1, 2, 3, 3, 2]), [3, 4, 5, 6]), [3]);
|
||||
|
||||
// Does not modify the original set object
|
||||
const set = new Set([1]);
|
||||
assertEq(set.intersection([2]) !== set, true);
|
||||
|
||||
// Argument must be iterable
|
||||
assertThrowsInstanceOf(function () {
|
||||
const set = new Set();
|
||||
set.intersection();
|
||||
}, TypeError);
|
||||
for (const arg of [null, {}, true, 1, undefined, NaN, Symbol()]) {
|
||||
assertThrowsInstanceOf(function () {
|
||||
const set = new Set();
|
||||
set.intersection(arg);
|
||||
}, TypeError);
|
||||
}
|
||||
|
||||
// `this` must be an Object
|
||||
for (const arg of [null, undefined, Symbol()]) {
|
||||
assertThrowsInstanceOf(function () {
|
||||
Set.prototype.intersection.call(arg, []);
|
||||
}, TypeError);
|
||||
}
|
||||
|
||||
// `this` must be iterable
|
||||
assertThrowsInstanceOf(function () {
|
||||
Set.prototype.intersection.call({}, []);
|
||||
}, TypeError);
|
||||
} else {
|
||||
assertEq(typeof Set.prototype.intersection, 'undefined');
|
||||
}
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* https://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
if (typeof getBuildConfiguration === "undefined") {
|
||||
var getBuildConfiguration = SpecialPowers.Cu.getJSTestingFunctions().getBuildConfiguration;
|
||||
}
|
||||
|
||||
if (typeof getRealmConfiguration === "undefined") {
|
||||
var getRealmConfiguration = SpecialPowers.Cu.getJSTestingFunctions().getRealmConfiguration;
|
||||
}
|
||||
|
||||
if (getBuildConfiguration()['new-set-methods'] && getRealmConfiguration().enableNewSetMethods) {
|
||||
|
||||
assertEq(typeof Set.prototype.isDisjointFrom, 'function');
|
||||
assertEq(Set.prototype.isDisjointFrom.length, 1);
|
||||
assertEq(Set.prototype.isDisjointFrom.name, 'isDisjointFrom');
|
||||
|
||||
assertEq(new Set([1, true, null]).isDisjointFrom(new Set()), true);
|
||||
assertEq(new Set([1, true, null]).isDisjointFrom([1, true, null]), false);
|
||||
assertEq(new Set([1, 2, 3]).isDisjointFrom([2, 3, 4]), false);
|
||||
assertEq(new Set([1, 2, 3]).isDisjointFrom([4]), true);
|
||||
// Works when the argument is a custom iterable which follows the Symbol.iterator protocol
|
||||
assertEq(new Set([1, 2, 3]).isDisjointFrom(makeArrayIteratorWithHasMethod([3, 4])), false);
|
||||
assertEq(new Set(['a']).isDisjointFrom('abc'), false);
|
||||
|
||||
// Works when the `this` is a custom iterable which follows the Symbol.iterator protocol
|
||||
assertEq(Set.prototype.isDisjointFrom.call(makeArrayIteratorWithHasMethod([1, 2, 3, 3, 2]), [4, 5, 6]), true);
|
||||
|
||||
// Does not modify the original set object
|
||||
const set = new Set([1]);
|
||||
assertEq(set.isDisjointFrom([2]) !== set, true);
|
||||
|
||||
// Argument must be iterable
|
||||
assertThrowsInstanceOf(function () {
|
||||
const set = new Set();
|
||||
set.isDisjointFrom();
|
||||
}, TypeError);
|
||||
for (const arg of [null, {}, true, 1, undefined, NaN, Symbol()]) {
|
||||
assertThrowsInstanceOf(function () {
|
||||
const set = new Set();
|
||||
set.isDisjointFrom(arg);
|
||||
}, TypeError);
|
||||
}
|
||||
|
||||
// `this` must be an Object
|
||||
for (const arg of [null, undefined, Symbol()]) {
|
||||
assertThrowsInstanceOf(function () {
|
||||
Set.prototype.isDisjointFrom.call(arg, []);
|
||||
}, TypeError);
|
||||
}
|
||||
|
||||
// `this` must be iterable
|
||||
assertThrowsInstanceOf(function () {
|
||||
Set.prototype.isDisjointFrom.call({}, []);
|
||||
}, TypeError);
|
||||
} else {
|
||||
assertEq(typeof Set.prototype.isDisjointFrom, 'undefined');
|
||||
}
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* https://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
if (typeof getBuildConfiguration === "undefined") {
|
||||
var getBuildConfiguration = SpecialPowers.Cu.getJSTestingFunctions().getBuildConfiguration;
|
||||
}
|
||||
|
||||
if (typeof getRealmConfiguration === "undefined") {
|
||||
var getRealmConfiguration = SpecialPowers.Cu.getJSTestingFunctions().getRealmConfiguration;
|
||||
}
|
||||
|
||||
if (getBuildConfiguration()['new-set-methods'] && getRealmConfiguration().enableNewSetMethods) {
|
||||
|
||||
assertEq(typeof Set.prototype.isSubsetOf, 'function');
|
||||
assertEq(Set.prototype.isSubsetOf.length, 1);
|
||||
assertEq(Set.prototype.isSubsetOf.name, 'isSubsetOf');
|
||||
|
||||
assertEq(new Set([1, true, null]).isSubsetOf(new Set()), false);
|
||||
|
||||
assertEq(new Set([1, true, null]).isSubsetOf([1, true, null]), true);
|
||||
assertEq(new Set([1, 2, 3]).isSubsetOf([2, 3, 4]), false);
|
||||
assertEq(new Set([1, 2, 3]).isSubsetOf([1, 2, 3, 4]), true);
|
||||
// Works when the argument is a custom iterable which follows the Symbol.iterator protocol
|
||||
assertEq(new Set([1, 2, 3]).isSubsetOf(makeArrayIteratorWithHasMethod([3, 4])), false);
|
||||
|
||||
// Works when the `this` is a custom iterable which follows the Symbol.iterator protocol
|
||||
assertEq(
|
||||
Set.prototype.isSubsetOf.call(
|
||||
makeArrayIteratorWithHasMethod([1, 2, 3, 3, 2]),
|
||||
makeArrayIteratorWithHasMethod([4, 5, 6])
|
||||
),
|
||||
false
|
||||
);
|
||||
|
||||
// Does not modify the original set object
|
||||
const set = new Set([1]);
|
||||
assertEq(set.isSubsetOf(new Set([2])) !== set, true);
|
||||
|
||||
// Argument must be iterable and an object
|
||||
assertThrowsInstanceOf(function () {
|
||||
const set = new Set();
|
||||
set.isSubsetOf();
|
||||
}, TypeError);
|
||||
for (const arg of [null, {}, true, 1, undefined, NaN, Symbol(), ""]) {
|
||||
assertThrowsInstanceOf(function () {
|
||||
const set = new Set();
|
||||
set.isSubsetOf(arg);
|
||||
}, TypeError);
|
||||
}
|
||||
|
||||
// `this` must be an Object
|
||||
for (const arg of [null, undefined, Symbol()]) {
|
||||
assertThrowsInstanceOf(function () {
|
||||
Set.prototype.isSubsetOf.call(arg, []);
|
||||
}, TypeError);
|
||||
}
|
||||
|
||||
// `this` must be iterable
|
||||
assertThrowsInstanceOf(function () {
|
||||
Set.prototype.isSubsetOf.call({}, []);
|
||||
}, TypeError);
|
||||
} else {
|
||||
assertEq(typeof Set.prototype.isSubsetOf, 'undefined');
|
||||
}
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* https://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
if (typeof getBuildConfiguration === "undefined") {
|
||||
var getBuildConfiguration = SpecialPowers.Cu.getJSTestingFunctions().getBuildConfiguration;
|
||||
}
|
||||
|
||||
if (typeof getRealmConfiguration === "undefined") {
|
||||
var getRealmConfiguration = SpecialPowers.Cu.getJSTestingFunctions().getRealmConfiguration;
|
||||
}
|
||||
|
||||
if (getBuildConfiguration()['new-set-methods'] && getRealmConfiguration().enableNewSetMethods) {
|
||||
|
||||
assertEq(typeof Set.prototype.isSupersetOf, 'function');
|
||||
assertEq(Set.prototype.isSupersetOf.length, 1);
|
||||
assertEq(Set.prototype.isSupersetOf.name, 'isSupersetOf');
|
||||
|
||||
assertEq(new Set([1, true, null]).isSupersetOf(new Set()), true);
|
||||
assertEq(new Set([1, true, null]).isSupersetOf([1, true, null]), true);
|
||||
assertEq(new Set([1, 2, 3]).isSupersetOf([2, 3, 4]), false);
|
||||
assertEq(new Set([1, 2, 3]).isSupersetOf([3]), true);
|
||||
// Works when the argument is a custom iterable which follows the Symbol.iterator protocol
|
||||
assertEq(new Set([1, 2, 3]).isSupersetOf(makeArrayIteratorWithHasMethod([2, 3])), true);
|
||||
assertEq(new Set(['a']).isSupersetOf('abc'), false);
|
||||
|
||||
// Works when the `this` is a custom iterable which follows the Symbol.iterator protocol
|
||||
assertEq(Set.prototype.isSupersetOf.call(makeArrayIteratorWithHasMethod([1, 2, 3, 3, 2]), [4, 5, 6]), false);
|
||||
|
||||
// Does not modify the original set object
|
||||
const set = new Set([1]);
|
||||
assertEq(set.isSupersetOf([2]) !== set, true);
|
||||
|
||||
// Argument must be iterable
|
||||
assertThrowsInstanceOf(function () {
|
||||
const set = new Set();
|
||||
set.isSupersetOf();
|
||||
}, TypeError);
|
||||
for (const arg of [null, {}, true, 1, undefined, NaN, Symbol()]) {
|
||||
assertThrowsInstanceOf(function () {
|
||||
const set = new Set();
|
||||
set.isSupersetOf(arg);
|
||||
}, TypeError);
|
||||
}
|
||||
|
||||
// `this` must be an Object
|
||||
for (const arg of [null, undefined, Symbol()]) {
|
||||
assertThrowsInstanceOf(function () {
|
||||
Set.prototype.isSupersetOf.call(arg, []);
|
||||
}, TypeError);
|
||||
}
|
||||
|
||||
// `this` must be iterable
|
||||
assertThrowsInstanceOf(function () {
|
||||
Set.prototype.isSupersetOf.call({}, []);
|
||||
}, TypeError);
|
||||
} else {
|
||||
assertEq(typeof Set.prototype.isSupersetOf, 'undefined');
|
||||
}
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
|
@ -0,0 +1,45 @@
|
|||
function makeArrayIterator(array) {
|
||||
let i = 0;
|
||||
return {
|
||||
[Symbol.iterator]() {
|
||||
return {
|
||||
next() {
|
||||
if (i >= array.length) {
|
||||
return { done: true };
|
||||
} else {
|
||||
return { value: array[i++] };
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function makeArrayIteratorWithHasMethod(array) {
|
||||
let i = 0;
|
||||
return {
|
||||
has(item) {
|
||||
return array.includes(item);
|
||||
},
|
||||
[Symbol.iterator]() {
|
||||
return {
|
||||
next() {
|
||||
if (i >= array.length) {
|
||||
return { done: true };
|
||||
} else {
|
||||
return { value: array[i++] };
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function assertSetContainsExactOrderedItems(actual, expected) {
|
||||
assertEq(actual.size, expected.length);
|
||||
let index = 0;
|
||||
for (const item of actual) {
|
||||
assertEq(item, expected[index]);
|
||||
index++;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* https://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
if (typeof getBuildConfiguration === "undefined") {
|
||||
var getBuildConfiguration = SpecialPowers.Cu.getJSTestingFunctions().getBuildConfiguration;
|
||||
}
|
||||
|
||||
if (typeof getRealmConfiguration === "undefined") {
|
||||
var getRealmConfiguration = SpecialPowers.Cu.getJSTestingFunctions().getRealmConfiguration;
|
||||
}
|
||||
|
||||
if (getBuildConfiguration()['new-set-methods'] && getRealmConfiguration().enableNewSetMethods) {
|
||||
|
||||
assertEq(typeof Set.prototype.symmetricDifference, 'function');
|
||||
assertEq(Set.prototype.symmetricDifference.length, 1);
|
||||
assertEq(Set.prototype.symmetricDifference.name, 'symmetricDifference');
|
||||
|
||||
assertSetContainsExactOrderedItems(new Set([1, true, null]).symmetricDifference(new Set()), [1, true, null]);
|
||||
assertSetContainsExactOrderedItems(new Set([1, true, null]).symmetricDifference([1, true, null]), []);
|
||||
assertSetContainsExactOrderedItems(new Set([1, 2, 3]).symmetricDifference([2, 3, 4]), [1, 4]);
|
||||
assertSetContainsExactOrderedItems(new Set([1, 2, 3]).symmetricDifference([4]), [1, 2, 3, 4]);
|
||||
// Works when the argument is a custom iterable which follows the Symbol.iterator protocol
|
||||
assertSetContainsExactOrderedItems(new Set([1, 2, 3]).symmetricDifference(makeArrayIterator([3, 4])), [1, 2, 4]);
|
||||
assertSetContainsExactOrderedItems(new Set(['a']).symmetricDifference('abc'), ['b', 'c']);
|
||||
|
||||
// Works when the `this` is a custom iterable which follows the Symbol.iterator protocol
|
||||
assertSetContainsExactOrderedItems(Set.prototype.symmetricDifference.call(makeArrayIterator([1, 2, 3, 3, 2]), [4, 5, 6]), [1, 2, 3, 4, 5, 6]);
|
||||
|
||||
// Does not modify the original set object
|
||||
const set = new Set([1]);
|
||||
assertEq(set.symmetricDifference([2]) !== set, true);
|
||||
|
||||
// Argument must be iterable
|
||||
assertThrowsInstanceOf(function () {
|
||||
const set = new Set();
|
||||
set.symmetricDifference();
|
||||
}, TypeError);
|
||||
for (const arg of [null, {}, true, 1, undefined, NaN, Symbol()]) {
|
||||
assertThrowsInstanceOf(function () {
|
||||
const set = new Set();
|
||||
set.symmetricDifference(arg);
|
||||
}, TypeError);
|
||||
}
|
||||
|
||||
// `this` must be an Object
|
||||
for (const arg of [null, undefined, Symbol()]) {
|
||||
assertThrowsInstanceOf(function () {
|
||||
Set.prototype.symmetricDifference.call(arg, []);
|
||||
}, TypeError);
|
||||
}
|
||||
|
||||
// `this` must be iterable
|
||||
assertThrowsInstanceOf(function () {
|
||||
Set.prototype.symmetricDifference.call({}, []);
|
||||
}, TypeError);
|
||||
} else {
|
||||
assertEq(typeof Set.prototype.symmetricDifference, 'undefined');
|
||||
}
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* https://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
if (typeof getBuildConfiguration === "undefined") {
|
||||
var getBuildConfiguration =
|
||||
SpecialPowers.Cu.getJSTestingFunctions().getBuildConfiguration;
|
||||
}
|
||||
|
||||
if (typeof getRealmConfiguration === "undefined") {
|
||||
var getRealmConfiguration =
|
||||
SpecialPowers.Cu.getJSTestingFunctions().getRealmConfiguration;
|
||||
}
|
||||
|
||||
if (getBuildConfiguration()['new-set-methods'] && getRealmConfiguration().enableNewSetMethods) {
|
||||
|
||||
assertEq(typeof Set.prototype.union, 'function');
|
||||
assertEq(Set.prototype.union.length, 1);
|
||||
assertEq(Set.prototype.union.name, 'union');
|
||||
|
||||
assertSetContainsExactOrderedItems(new Set([1, true, null]).union(new Set()), [1, true, null]);
|
||||
assertSetContainsExactOrderedItems(new Set([1, true, null]).union([1, true, null]), [1, true, null]);
|
||||
assertSetContainsExactOrderedItems(new Set([1, 2, 3]).union([2, 3, 4]), [1, 2, 3, 4]);
|
||||
assertSetContainsExactOrderedItems(new Set([1, 2, 3]).union([4]), [1, 2, 3, 4]);
|
||||
// Works when the argument is a custom iterable which follows the Symbol.iterator protocol
|
||||
assertSetContainsExactOrderedItems(new Set([1, 2, 3]).union(makeArrayIterator([3, 4])), [1, 2, 3, 4]);
|
||||
assertSetContainsExactOrderedItems(new Set(['a']).union('abc'), ['a', 'b', 'c']);
|
||||
|
||||
// Works when the `this` is a custom iterable which follows the Symbol.iterator protocol
|
||||
assertSetContainsExactOrderedItems(Set.prototype.union.call(makeArrayIterator([1, 2, 3, 3, 2]), [4, 5, 6]), [1, 2, 3, 4, 5, 6]);
|
||||
|
||||
// Does not modify the original set object
|
||||
const set = new Set([1]);
|
||||
assertEq(set.union([2]) !== set, true);
|
||||
|
||||
// Argument must be iterable
|
||||
assertThrowsInstanceOf(function () {
|
||||
const set = new Set();
|
||||
set.union();
|
||||
}, TypeError);
|
||||
for (const arg of [null, {}, true, 1, undefined, NaN, Symbol()]) {
|
||||
assertThrowsInstanceOf(function () {
|
||||
const set = new Set();
|
||||
set.union(arg);
|
||||
}, TypeError);
|
||||
}
|
||||
|
||||
// `this` must be an Object
|
||||
for (const arg of [null, undefined, Symbol()]) {
|
||||
assertThrowsInstanceOf(function () {
|
||||
Set.prototype.union.call(arg, []);
|
||||
}, TypeError);
|
||||
}
|
||||
|
||||
// `this` must be iterable
|
||||
assertThrowsInstanceOf(function () {
|
||||
Set.prototype.union.call({}, []);
|
||||
}, TypeError);
|
||||
} else {
|
||||
assertEq(typeof Set.prototype.union, 'undefined');
|
||||
}
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
|
@ -35,3 +35,4 @@ user_pref("javascript.options.experimental.iterator_helpers", true);
|
|||
user_pref("javascript.options.experimental.top_level_await", true);
|
||||
user_pref("javascript.options.experimental.ergonomic_brand_checks", true);
|
||||
user_pref("javascript.options.experimental.enable_change_array_by_copy", false);
|
||||
user_pref("javascript.options.experimental.enable_new_set_methods", false);
|
|
@ -28,6 +28,8 @@ static JSProtoKey ToProtoKey(BuiltinObjectKind kind) {
|
|||
return JSProto_Promise;
|
||||
case BuiltinObjectKind::RegExp:
|
||||
return JSProto_RegExp;
|
||||
case BuiltinObjectKind::Set:
|
||||
return JSProto_Set;
|
||||
case BuiltinObjectKind::SharedArrayBuffer:
|
||||
return JSProto_SharedArrayBuffer;
|
||||
case BuiltinObjectKind::Symbol:
|
||||
|
@ -61,6 +63,7 @@ static bool IsPrototype(BuiltinObjectKind kind) {
|
|||
case BuiltinObjectKind::Iterator:
|
||||
case BuiltinObjectKind::Promise:
|
||||
case BuiltinObjectKind::RegExp:
|
||||
case BuiltinObjectKind::Set:
|
||||
case BuiltinObjectKind::SharedArrayBuffer:
|
||||
case BuiltinObjectKind::Symbol:
|
||||
return false;
|
||||
|
@ -101,6 +104,9 @@ BuiltinObjectKind js::BuiltinConstructorForName(
|
|||
if (name == frontend::TaggedParserAtomIndex::WellKnown::RegExp()) {
|
||||
return BuiltinObjectKind::RegExp;
|
||||
}
|
||||
if (name == frontend::TaggedParserAtomIndex::WellKnown::Set()) {
|
||||
return BuiltinObjectKind::Set;
|
||||
}
|
||||
if (name == frontend::TaggedParserAtomIndex::WellKnown::SharedArrayBuffer()) {
|
||||
return BuiltinObjectKind::SharedArrayBuffer;
|
||||
}
|
||||
|
@ -166,6 +172,8 @@ const char* js::BuiltinObjectName(BuiltinObjectKind kind) {
|
|||
return "RegExp";
|
||||
case BuiltinObjectKind::SharedArrayBuffer:
|
||||
return "SharedArrayBuffer";
|
||||
case BuiltinObjectKind::Set:
|
||||
return "Set";
|
||||
case BuiltinObjectKind::Symbol:
|
||||
return "Symbol";
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ enum class BuiltinObjectKind : uint8_t {
|
|||
Iterator,
|
||||
Promise,
|
||||
RegExp,
|
||||
Set,
|
||||
SharedArrayBuffer,
|
||||
Symbol,
|
||||
|
||||
|
|
|
@ -121,6 +121,7 @@
|
|||
MACRO_(defineSetter, defineSetter, "__defineSetter__") \
|
||||
MACRO_(delete, delete_, "delete") \
|
||||
MACRO_(deleteProperty, deleteProperty, "deleteProperty") \
|
||||
MACRO_(difference, difference, "difference") \
|
||||
MACRO_(displayURL, displayURL, "displayURL") \
|
||||
MACRO2(do, do_, "do") \
|
||||
MACRO_(domNode, domNode, "domNode") \
|
||||
|
@ -243,6 +244,7 @@
|
|||
MACRO_(index, index, "index") \
|
||||
MACRO_(indices, indices, "indices") \
|
||||
MACRO_(infinity, infinity, "infinity") \
|
||||
MACRO_(intersection, intersection, "intersection") \
|
||||
MACRO_(Infinity, Infinity, "Infinity") \
|
||||
MACRO_(initial, initial, "initial") \
|
||||
MACRO_(InitializeCollator, InitializeCollator, "InitializeCollator") \
|
||||
|
@ -271,12 +273,15 @@
|
|||
"InterpretGeneratorResume") \
|
||||
MACRO_(InvalidDate, InvalidDate, "Invalid Date") \
|
||||
MACRO_(isBreakpoint, isBreakpoint, "isBreakpoint") \
|
||||
MACRO_(isDisjointFrom, isDisjointFrom, "isDisjointFrom") \
|
||||
MACRO_(isEntryPoint, isEntryPoint, "isEntryPoint") \
|
||||
MACRO_(isExtensible, isExtensible, "isExtensible") \
|
||||
MACRO_(isFinite, isFinite, "isFinite") \
|
||||
MACRO_(isNaN, isNaN, "isNaN") \
|
||||
MACRO_(isPrototypeOf, isPrototypeOf, "isPrototypeOf") \
|
||||
MACRO_(isStepStart, isStepStart, "isStepStart") \
|
||||
MACRO_(isSubsetOf, isSubsetOf, "isSubsetOf") \
|
||||
MACRO_(isSupersetOf, isSupersetOf, "isSupersetOf") \
|
||||
MACRO_(IterableToList, IterableToList, "IterableToList") \
|
||||
MACRO_(iterate, iterate, "iterate") \
|
||||
MACRO_(join, join, "join") \
|
||||
|
@ -457,6 +462,7 @@
|
|||
MACRO_(style, style, "style") \
|
||||
MACRO_(super, super, "super") \
|
||||
MACRO_(switch, switch_, "switch") \
|
||||
MACRO_(symmetricDifference, symmetricDifference, "symmetricDifference") \
|
||||
MACRO_(Symbol_iterator_fun, Symbol_iterator_fun, "[Symbol.iterator]") \
|
||||
MACRO_(target, target, "target") \
|
||||
MACRO_(test, test, "test") \
|
||||
|
@ -497,6 +503,7 @@
|
|||
MACRO_(uneval, uneval, "uneval") \
|
||||
MACRO_(unicode, unicode, "unicode") \
|
||||
MACRO_(uninitialized, uninitialized, "uninitialized") \
|
||||
MACRO_(union, union_, "union") \
|
||||
MACRO_(unit, unit, "unit") \
|
||||
MACRO_(unitDisplay, unitDisplay, "unitDisplay") \
|
||||
MACRO_(unknown, unknown, "unknown") \
|
||||
|
|
|
@ -2164,6 +2164,20 @@ JS_PUBLIC_API bool js::ShouldIgnorePropertyDefinition(JSContext* cx,
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_NEW_SET_METHODS
|
||||
if (key == JSProto_Set &&
|
||||
!cx->realm()->creationOptions().getNewSetMethodsEnabled() &&
|
||||
(id == NameToId(cx->names().union_) ||
|
||||
id == NameToId(cx->names().difference) ||
|
||||
id == NameToId(cx->names().intersection) ||
|
||||
id == NameToId(cx->names().isSubsetOf) ||
|
||||
id == NameToId(cx->names().isSupersetOf) ||
|
||||
id == NameToId(cx->names().isDisjointFrom) ||
|
||||
id == NameToId(cx->names().symmetricDifference))) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -2456,6 +2456,8 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||
ReflectGetPrototypeOf),
|
||||
JS_FN("std_Reflect_isExtensible", Reflect_isExtensible, 1, 0),
|
||||
JS_FN("std_Reflect_ownKeys", Reflect_ownKeys, 1, 0),
|
||||
JS_FN("std_Set_add", SetObject::add, 1, 0),
|
||||
JS_FN("std_Set_has", SetObject::has, 1, 0),
|
||||
JS_FN("std_Set_values", SetObject::values, 0, 0),
|
||||
JS_INLINABLE_FN("std_String_charCodeAt", str_charCodeAt, 1, 0,
|
||||
StringCharCodeAt),
|
||||
|
|
|
@ -800,7 +800,11 @@ void xpc::SetPrefableRealmOptions(JS::RealmOptions& options) {
|
|||
StaticPrefs::javascript_options_writable_streams())
|
||||
.setPropertyErrorMessageFixEnabled(sPropertyErrorMessageFixEnabled)
|
||||
.setWeakRefsEnabled(GetWeakRefsEnabled())
|
||||
.setIteratorHelpersEnabled(sIteratorHelpersEnabled);
|
||||
.setIteratorHelpersEnabled(sIteratorHelpersEnabled)
|
||||
#ifdef ENABLE_NEW_SET_METHODS
|
||||
.setNewSetMethodsEnabled(enableNewSetMethods)
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
// Mirrored value of javascript.options.self_hosted.use_shared_memory.
|
||||
|
@ -944,6 +948,11 @@ static void ReloadPrefsCallback(const char* pref, void* aXpccx) {
|
|||
Preferences::GetBool(JS_OPTIONS_DOT_STR "experimental.iterator_helpers");
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_NEW_SET_METHODS
|
||||
bool enableNewSetMethods =
|
||||
Preferences::GetBool(JS_OPTIONS_DOT_STR "experimental.new_set_methods");
|
||||
#endif
|
||||
|
||||
#ifdef JS_GC_ZEAL
|
||||
int32_t zeal = Preferences::GetInt(JS_OPTIONS_DOT_STR "gczeal", -1);
|
||||
int32_t zeal_frequency = Preferences::GetInt(
|
||||
|
|
|
@ -35,6 +35,7 @@ prefs =
|
|||
javascript.options.large_arraybuffers=true
|
||||
javascript.options.experimental.ergonomic_brand_checks=true
|
||||
javascript.options.experimental.enable_change_array_by_copy=false
|
||||
javascript.options.experimental.enable_new_set_methods=false
|
||||
|
||||
[test_APIExposer.xhtml]
|
||||
[test_bug361111.xhtml]
|
||||
|
|
|
@ -45,6 +45,7 @@ prefs =
|
|||
javascript.options.experimental.ergonomic_brand_checks=true
|
||||
javascript.options.experimental.top_level_await=true
|
||||
javascript.options.experimental.enable_change_array_by_copy=false
|
||||
javascript.options.experimental.enable_new_set_methods=false
|
||||
|
||||
[test_bug384632.html]
|
||||
[test_bug390488.html]
|
||||
|
|
|
@ -6275,6 +6275,14 @@
|
|||
value: false
|
||||
mirror: always
|
||||
|
||||
#if defined(ENABLE_NEW_SET_METHODS)
|
||||
# Experimental support for New Set methods
|
||||
- name: javascript.options.experimental.enable_new_set_methods
|
||||
type: bool
|
||||
value: false
|
||||
mirror: always
|
||||
#endif
|
||||
|
||||
# Experimental support for Top-level Await in JavaScript.
|
||||
- name: javascript.options.experimental.top_level_await
|
||||
type: bool
|
||||
|
|
Загрузка…
Ссылка в новой задаче