123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598 |
- /*
- * Copyright (c) 2021-2022, Idan Horowitz <idan.horowitz@serenityos.org>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #include <AK/HashTable.h>
- #include <AK/TypeCasts.h>
- #include <LibJS/Runtime/AbstractOperations.h>
- #include <LibJS/Runtime/FunctionObject.h>
- #include <LibJS/Runtime/Iterator.h>
- #include <LibJS/Runtime/KeyedCollections.h>
- #include <LibJS/Runtime/SetIterator.h>
- #include <LibJS/Runtime/SetPrototype.h>
- #include <LibJS/Runtime/ValueInlines.h>
- namespace JS {
- GC_DEFINE_ALLOCATOR(SetPrototype);
- SetPrototype::SetPrototype(Realm& realm)
- : PrototypeObject(realm.intrinsics().object_prototype())
- {
- }
- void SetPrototype::initialize(Realm& realm)
- {
- auto& vm = this->vm();
- Base::initialize(realm);
- u8 attr = Attribute::Writable | Attribute::Configurable;
- define_native_function(realm, vm.names.add, add, 1, attr);
- define_native_function(realm, vm.names.clear, clear, 0, attr);
- define_native_function(realm, vm.names.delete_, delete_, 1, attr);
- define_native_function(realm, vm.names.difference, difference, 1, attr);
- define_native_function(realm, vm.names.entries, entries, 0, attr);
- define_native_function(realm, vm.names.forEach, for_each, 1, attr);
- define_native_function(realm, vm.names.has, has, 1, attr);
- define_native_function(realm, vm.names.intersection, intersection, 1, attr);
- define_native_function(realm, vm.names.isDisjointFrom, is_disjoint_from, 1, attr);
- define_native_function(realm, vm.names.isSubsetOf, is_subset_of, 1, attr);
- define_native_function(realm, vm.names.isSupersetOf, is_superset_of, 1, attr);
- define_native_accessor(realm, vm.names.size, size_getter, {}, Attribute::Configurable);
- define_native_function(realm, vm.names.symmetricDifference, symmetric_difference, 1, attr);
- define_native_function(realm, vm.names.union_, union_, 1, attr);
- define_native_function(realm, vm.names.values, values, 0, attr);
- define_direct_property(vm.names.keys, get_without_side_effects(vm.names.values), attr);
- // 24.2.3.18 Set.prototype [ @@iterator ] ( ), https://tc39.es/ecma262/#sec-set.prototype-@@iterator
- define_direct_property(vm.well_known_symbol_iterator(), get_without_side_effects(vm.names.values), attr);
- // 24.2.3.19 Set.prototype [ @@toStringTag ], https://tc39.es/ecma262/#sec-set.prototype-@@tostringtag
- define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, vm.names.Set.as_string()), Attribute::Configurable);
- }
- // 24.2.3.1 Set.prototype.add ( value ), https://tc39.es/ecma262/#sec-set.prototype.add
- JS_DEFINE_NATIVE_FUNCTION(SetPrototype::add)
- {
- auto value = vm.argument(0);
- // 1. Let S be the this value.
- // 2. Perform ? RequireInternalSlot(S, [[SetData]]).
- auto set = TRY(typed_this_object(vm));
- // 3. Set value to CanonicalizeKeyedCollectionKey(value).
- value = canonicalize_keyed_collection_key(value);
- // 4. For each element e of S.[[SetData]], do
- // a. If e is not empty and SameValue(e, value) is true, then
- // i. Return S.
- // 5. Append value to S.[[SetData]].
- set->set_add(value);
- // 6. Return S.
- return set;
- }
- // 24.2.3.2 Set.prototype.clear ( ), https://tc39.es/ecma262/#sec-set.prototype.clear
- JS_DEFINE_NATIVE_FUNCTION(SetPrototype::clear)
- {
- // 1. Let S be the this value.
- // 2. Perform ? RequireInternalSlot(S, [[SetData]]).
- auto set = TRY(typed_this_object(vm));
- // 3. For each element e of S.[[SetData]], do
- // a. Replace the element of S.[[SetData]] whose value is e with an element whose value is empty.
- set->set_clear();
- // 4. Return undefined.
- return js_undefined();
- }
- // 24.2.3.4 Set.prototype.delete ( value ), https://tc39.es/ecma262/#sec-set.prototype.delete
- JS_DEFINE_NATIVE_FUNCTION(SetPrototype::delete_)
- {
- auto value = vm.argument(0);
- // 1. Let S be the this value.
- // 2. Perform ? RequireInternalSlot(S, [[SetData]]).
- auto set = TRY(typed_this_object(vm));
- // 3. Set value to CanonicalizeKeyedCollectionKey(value).
- value = canonicalize_keyed_collection_key(value);
- // 4. For each element e of S.[[SetData]], do
- // a. If e is not empty and SameValue(e, value) is true, then
- // i. Replace the element of S.[[SetData]] whose value is e with an element whose value is empty.
- // ii. Return true.
- // 5. Return false.
- return Value(set->set_remove(value));
- }
- // 24.2.4.5 Set.prototype.difference ( other ), https://tc39.es/ecma262/#sec-set.prototype.difference
- JS_DEFINE_NATIVE_FUNCTION(SetPrototype::difference)
- {
- // 1. Let O be the this value.
- // 2. Perform ? RequireInternalSlot(O, [[SetData]]).
- auto set = TRY(typed_this_object(vm));
- // 3. Let otherRec be ? GetSetRecord(other).
- auto other_record = TRY(get_set_record(vm, vm.argument(0)));
- // 4. Let resultSetData be a copy of O.[[SetData]].
- auto result = set->copy();
- // 5. If SetDataSize(O.[[SetData]]) ≤ otherRec.[[Size]], then
- if (set->set_size() <= other_record.size) {
- // a. Let thisSize be the number of elements in O.[[SetData]].
- // b. Let index be 0.
- // c. Repeat, while index < thisSize,
- for (auto const& element : *set) {
- // i. Let e be resultSetData[index].
- // ii. If e is not EMPTY, then
- // 1. Let inOther be ToBoolean(? Call(otherRec.[[Has]], otherRec.[[SetObject]], « e »)).
- auto in_other = TRY(call(vm, *other_record.has, other_record.set_object, element.key)).to_boolean();
- // 2. If inOther is true, then
- if (in_other) {
- // a. Set resultSetData[index] to EMPTY.
- result->set_remove(element.key);
- }
- // iii. Set index to index + 1.
- }
- }
- // 6. Else,
- else {
- // a. Let keysIter be ? GetIteratorFromMethod(otherRec.[[SetObject]], otherRec.[[Keys]]).
- auto keys_iterator = TRY(get_iterator_from_method(vm, other_record.set_object, other_record.keys));
- // b. Let next be NOT-STARTED.
- Optional<Value> next;
- // c. Repeat, while next is not DONE,
- do {
- // i. Set next to ? IteratorStepValue(keysIter).
- next = TRY(iterator_step_value(vm, keys_iterator));
- // ii. If next is not DONE, then
- if (next.has_value()) {
- // 1. Set next to CanonicalizeKeyedCollectionKey(next).
- next = canonicalize_keyed_collection_key(*next);
- // 2. Let valueIndex be SetDataIndex(resultSetData, next).
- // 3. If valueIndex is not NOT-FOUND, then
- if (result->set_has(*next)) {
- // a. Set resultSetData[valueIndex] to EMPTY.
- result->set_remove(*next);
- }
- }
- } while (next.has_value());
- }
- // 7. Let result be OrdinaryObjectCreate(%Set.prototype%, « [[SetData]] »).
- // 8. Set result.[[SetData]] to resultSetData.
- // 9. Return result.
- return result;
- }
- // 24.2.3.6 Set.prototype.entries ( ), https://tc39.es/ecma262/#sec-set.prototype.entries
- JS_DEFINE_NATIVE_FUNCTION(SetPrototype::entries)
- {
- auto& realm = *vm.current_realm();
- // 1. Let S be the this value.
- auto set = TRY(typed_this_object(vm));
- // 2. Return ? CreateSetIterator(S, key+value).
- return SetIterator::create(realm, set, Object::PropertyKind::KeyAndValue);
- }
- // 24.2.3.7 Set.prototype.forEach ( callbackfn [ , thisArg ] ), https://tc39.es/ecma262/#sec-set.prototype.foreach
- JS_DEFINE_NATIVE_FUNCTION(SetPrototype::for_each)
- {
- auto callback_fn = vm.argument(0);
- auto this_arg = vm.argument(1);
- // 1. Let S be the this value.
- // 2. Perform ? RequireInternalSlot(S, [[SetData]]).
- auto set = TRY(typed_this_object(vm));
- // 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
- if (!callback_fn.is_function())
- return vm.throw_completion<TypeError>(ErrorType::NotAFunction, vm.argument(0).to_string_without_side_effects());
- // 4. Let entries be S.[[SetData]].
- // 5. Let numEntries be the number of elements in entries.
- // 6. Let index be 0.
- // 7. Repeat, while index < numEntries,
- for (auto& entry : *set) {
- // a. Let e be entries[index].
- // b. Set index to index + 1.
- // c. If e is not empty, then
- // NOTE: This is handled in Map::IteratorImpl.
- // i. Perform ? Call(callbackfn, thisArg, « e, e, S »).
- TRY(call(vm, callback_fn.as_function(), this_arg, entry.key, entry.key, set));
- // ii. NOTE: The number of elements in entries may have increased during execution of callbackfn.
- // iii. Set numEntries to the number of elements in entries.
- // NOTE: This is handled in Map::IteratorImpl.
- }
- // 8. Return undefined.
- return js_undefined();
- }
- // 24.2.3.8 Set.prototype.has ( value ), https://tc39.es/ecma262/#sec-set.prototype.has
- JS_DEFINE_NATIVE_FUNCTION(SetPrototype::has)
- {
- auto value = vm.argument(0);
- // 1. Let S be the this value.
- // 2. Perform ? RequireInternalSlot(S, [[SetData]]).
- auto set = TRY(typed_this_object(vm));
- // 3. Set value to CanonicalizeKeyedCollectionKey(value).
- value = canonicalize_keyed_collection_key(value);
- // 4. For each element e of S.[[SetData]], do
- // a. If e is not empty and SameValue(e, value) is true, return true.
- // 5. Return false.
- return Value(set->set_has(value));
- }
- // 24.2.4.9 Set.prototype.intersection ( other ), https://tc39.es/ecma262/#sec-set.prototype.intersection
- JS_DEFINE_NATIVE_FUNCTION(SetPrototype::intersection)
- {
- auto& realm = *vm.current_realm();
- // 1. Let O be the this value.
- // 2. Perform ? RequireInternalSlot(O, [[SetData]]).
- auto set = TRY(typed_this_object(vm));
- // 3. Let otherRec be ? GetSetRecord(other).
- auto other_record = TRY(get_set_record(vm, vm.argument(0)));
- // 4. Let resultSetData be a new empty List.
- auto result = Set::create(realm);
- // 5. If SetDataSize(O.[[SetData]]) ≤ otherRec.[[Size]], then
- if (set->set_size() <= other_record.size) {
- // a. Let thisSize be the number of elements in O.[[SetData]].
- // b. Let index be 0.
- // c. Repeat, while index < thisSize,
- for (auto const& element : *set) {
- // i. Let e be O.[[SetData]][index].
- // ii. Set index to index + 1.
- // iii. If e is not empty, then
- // 1. Let inOther be ToBoolean(? Call(otherRec.[[Has]], otherRec.[[SetObject]], « e »)).
- auto in_other = TRY(call(vm, *other_record.has, other_record.set_object, element.key)).to_boolean();
- // 2. If inOther is true, then
- if (in_other) {
- // a. NOTE: It is possible for earlier calls to otherRec.[[Has]] to remove and re-add an element of O.[[SetData]], which can cause the same element to be visited twice during this iteration.
- // b. If SetDataHas(resultSetData, e) is false, then
- if (!set_data_has(result, element.key)) {
- // i. Append e to resultSetData.
- result->set_add(element.key);
- }
- }
- // 3. NOTE: The number of elements in O.[[SetData]] may have increased during execution of otherRec.[[Has]].
- // 4. Set thisSize to the number of elements in O.[[SetData]].
- }
- }
- // 6. Else,
- else {
- // a. Let keysIter be ? GetIteratorFromMethod(otherRec.[[SetObject]], otherRec.[[Keys]]).
- auto keys_iterator = TRY(get_iterator_from_method(vm, other_record.set_object, other_record.keys));
- // b. Let next be NOT-STARTED.
- Optional<Value> next;
- // c. Repeat, while next is not DONE,
- do {
- // i. Set next to ? IteratorStepValue(keysIter).
- next = TRY(iterator_step_value(vm, keys_iterator));
- // ii. If next is not DONE, then
- if (next.has_value()) {
- // 1. Set next to CanonicalizeKeyedCollectionKey(next).
- next = canonicalize_keyed_collection_key(*next);
- // 2. Let inThis be SetDataHas(O.[[SetData]], next).
- auto in_this = set_data_has(set, *next);
- // 3. If inThis is true, then
- if (in_this) {
- // a. NOTE: Because other is an arbitrary object, it is possible for its "keys" iterator to produce the same value more than once.
- // b. If SetDataHas(resultSetData, next) is false, then
- if (!set_data_has(result, *next)) {
- // i. Append next to resultSetData.
- result->set_add(*next);
- }
- }
- }
- } while (next.has_value());
- }
- // 7. Let result be OrdinaryObjectCreate(%Set.prototype%, « [[SetData]] »).
- // 8. Set result.[[SetData]] to resultSetData.
- // 9. Return result.
- return result;
- }
- // 24.2.4.10 Set.prototype.isDisjointFrom ( other ), https://tc39.es/ecma262/#sec-set.prototype.isdisjointfrom
- JS_DEFINE_NATIVE_FUNCTION(SetPrototype::is_disjoint_from)
- {
- // 1. Let O be the this value.
- // 2. Perform ? RequireInternalSlot(O, [[SetData]]).
- auto set = TRY(typed_this_object(vm));
- // 3. Let otherRec be ? GetSetRecord(other).
- auto other_record = TRY(get_set_record(vm, vm.argument(0)));
- // 4. If SetDataSize(O.[[SetData]]) ≤ otherRec.[[Size]], then
- if (set->set_size() <= other_record.size) {
- // a. Let thisSize be the number of elements in O.[[SetData]].
- // b. Let index be 0.
- // c. Repeat, while index < thisSize,
- for (auto const& element : *set) {
- // i. Let e be O.[[SetData]][index].
- // ii. Set index to index + 1.
- // iii. If e is not empty, then
- // 1. Let inOther be ToBoolean(? Call(otherRec.[[Has]], otherRec.[[SetObject]], « e »)).
- auto in_other = TRY(call(vm, *other_record.has, other_record.set_object, element.key)).to_boolean();
- // 2. If inOther is true, return false.
- if (in_other)
- return false;
- // 3. NOTE: The number of elements in O.[[SetData]] may have increased during execution of otherRec.[[Has]].
- // 4. Set thisSize to the number of elements in O.[[SetData]].
- }
- }
- // 5. Else,
- else {
- // a. Let keysIter be ? GetIteratorFromMethod(otherRec.[[SetObject]], otherRec.[[Keys]]).
- auto keys_iterator = TRY(get_iterator_from_method(vm, other_record.set_object, other_record.keys));
- // b. Let next be NOT-STARTED.
- Optional<Value> next;
- // c. Repeat, while next is not DONE,
- do {
- // i. Set next to ? IteratorStepValue(keysIter).
- next = TRY(iterator_step_value(vm, keys_iterator));
- // ii. If next is not DONE, then
- if (next.has_value()) {
- // 1. If SetDataHas(O.[[SetData]], next) is true, then
- if (set_data_has(set, *next)) {
- // a. Perform ? IteratorClose(keysIter, NormalCompletion(UNUSED)).
- TRY(iterator_close(vm, keys_iterator, normal_completion({})));
- // b. Return false.
- return false;
- }
- }
- } while (next.has_value());
- }
- // 6. Return true.
- return true;
- }
- // 24.2.4.11 Set.prototype.isSubsetOf ( other ), https://tc39.es/ecma262/#sec-set.prototype.issubsetof
- JS_DEFINE_NATIVE_FUNCTION(SetPrototype::is_subset_of)
- {
- // 1. Let O be the this value.
- // 2. Perform ? RequireInternalSlot(O, [[SetData]]).
- auto set = TRY(typed_this_object(vm));
- // 3. Let otherRec be ? GetSetRecord(other).
- auto other_record = TRY(get_set_record(vm, vm.argument(0)));
- // 4. If SetDataSize(O.[[SetData]]) > otherRec.[[Size]], return false.
- if (set->set_size() > other_record.size)
- return false;
- // 5. Let thisSize be the number of elements in O.[[SetData]].
- // 6. Let index be 0.
- // 7. Repeat, while index < thisSize,
- for (auto const& element : *set) {
- // a. Let e be O.[[SetData]][index].
- // b. Set index to index + 1.
- // c. If e is not empty, then
- // i. Let inOther be ToBoolean(? Call(otherRec.[[Has]], otherRec.[[SetObject]], « e »)).
- auto in_other = TRY(call(vm, *other_record.has, other_record.set_object, element.key)).to_boolean();
- // ii. If inOther is false, return false.
- if (!in_other)
- return false;
- // iii. NOTE: The number of elements in O.[[SetData]] may have increased during execution of otherRec.[[Has]].
- // iv. Set thisSize to the number of elements in O.[[SetData]].
- }
- // 8. Return true.
- return true;
- }
- // 24.2.4.12 Set.prototype.isSupersetOf ( other ), https://tc39.es/ecma262/#sec-set.prototype.issupersetof
- JS_DEFINE_NATIVE_FUNCTION(SetPrototype::is_superset_of)
- {
- // 1. Let O be the this value.
- // 2. Perform ? RequireInternalSlot(O, [[SetData]]).
- auto set = TRY(typed_this_object(vm));
- // 3. Let otherRec be ? GetSetRecord(other).
- auto other_record = TRY(get_set_record(vm, vm.argument(0)));
- // 4. If SetDataSize(O.[[SetData]]) < otherRec.[[Size]], return false.
- if (set->set_size() < other_record.size)
- return false;
- // 5. Let keysIter be ? GetIteratorFromMethod(otherRec.[[SetObject]], otherRec.[[Keys]]).
- auto keys_iterator = TRY(get_iterator_from_method(vm, other_record.set_object, other_record.keys));
- // 6. Let next be NOT-STARTED.
- Optional<Value> next;
- // 7. Repeat, while next is not DONE,
- do {
- // a. Set next to ? IteratorStepValue(keysIter).
- next = TRY(iterator_step_value(vm, keys_iterator));
- // b. If next is not DONE, then
- if (next.has_value()) {
- // i. If SetDataHas(O.[[SetData]], next) is false, then
- if (!set_data_has(set, *next)) {
- // 1. Perform ? IteratorClose(keysIter, NormalCompletion(UNUSED)).
- TRY(iterator_close(vm, keys_iterator, normal_completion({})));
- // 2. Return false.
- return false;
- }
- }
- } while (next.has_value());
- // 8. Return true.
- return true;
- }
- // 24.2.3.14 get Set.prototype.size, https://tc39.es/ecma262/#sec-get-set.prototype.size
- JS_DEFINE_NATIVE_FUNCTION(SetPrototype::size_getter)
- {
- // 1. Let S be the this value.
- // 2. Perform ? RequireInternalSlot(S, [[SetData]]).
- auto set = TRY(typed_this_object(vm));
- // 3. Let count be 0.
- // 4. For each element e of S.[[SetData]], do
- // a. If e is not empty, set count to count + 1.
- auto count = set->set_size();
- // 5. Return 𝔽(count).
- return Value(count);
- }
- // 24.2.4.15 Set.prototype.symmetricDifference ( other ), https://tc39.es/ecma262/#sec-set.prototype.symmetricdifference
- JS_DEFINE_NATIVE_FUNCTION(SetPrototype::symmetric_difference)
- {
- // 1. Let O be the this value.
- // 2. Perform ? RequireInternalSlot(O, [[SetData]]).
- auto set = TRY(typed_this_object(vm));
- // 3. Let otherRec be ? GetSetRecord(other).
- auto other_record = TRY(get_set_record(vm, vm.argument(0)));
- // 4. Let keysIter be ? GetIteratorFromMethod(otherRec.[[SetObject]], otherRec.[[Keys]]).
- auto keys_iterator = TRY(get_iterator_from_method(vm, other_record.set_object, other_record.keys));
- // 5. Let resultSetData be a copy of O.[[SetData]].
- auto result = set->copy();
- // 6. Let next be NOT-STARTED.
- Optional<Value> next;
- // 7. Repeat, while next is not DONE,
- do {
- // a. Set next to ? IteratorStepValue(keysIter).
- next = TRY(iterator_step_value(vm, keys_iterator));
- // b. If next is not DONE, then
- if (next.has_value()) {
- // i. Set next to CanonicalizeKeyedCollectionKey(next).
- next = canonicalize_keyed_collection_key(*next);
- // ii. Let resultIndex be SetDataIndex(resultSetData, next).
- // iii. If resultIndex is not-found, let alreadyInResult be false. Otherwise let alreadyInResult be true.
- auto already_in_result = result->set_has(*next);
- // iv. If SetDataHas(O.[[SetData]], next) is true, then
- if (set_data_has(set, *next)) {
- // 1. If alreadyInResult is true, set resultSetData[resultIndex] to empty.
- if (already_in_result)
- result->set_remove(*next);
- }
- // v. Else,
- else {
- // 1. If alreadyInResult is false, append next to resultSetData.
- if (!already_in_result)
- result->set_add(*next);
- }
- }
- } while (next.has_value());
- // 8. Let result be OrdinaryObjectCreate(%Set.prototype%, « [[SetData]] »).
- // 9. Set result.[[SetData]] to resultSetData.
- // 10. Return result.
- return result;
- }
- // 24.2.4.16 Set.prototype.union ( other ), https://tc39.es/ecma262/#sec-set.prototype.union
- JS_DEFINE_NATIVE_FUNCTION(SetPrototype::union_)
- {
- // 1. Let O be the this value.
- // 2. Perform ? RequireInternalSlot(O, [[SetData]]).
- auto set = TRY(typed_this_object(vm));
- // 3. Let otherRec be ? GetSetRecord(other).
- auto other_record = TRY(get_set_record(vm, vm.argument(0)));
- // 4. Let keysIter be ? GetIteratorFromMethod(otherRec.[[SetObject]], otherRec.[[Keys]]).
- auto keys_iterator = TRY(get_iterator_from_method(vm, other_record.set_object, other_record.keys));
- // 5. Let resultSetData be a copy of O.[[SetData]].
- auto result = set->copy();
- // 6. Let next be NOT-STARTED.
- Optional<Value> next;
- // 7. Repeat, while next is not DONE,
- do {
- // a. Set next to ? IteratorStepValue(keysIter).
- next = TRY(iterator_step_value(vm, keys_iterator));
- // b. If next is not DONE, then
- if (next.has_value()) {
- // i. Set next to CanonicalizeKeyedCollectionKey(next).
- next = canonicalize_keyed_collection_key(*next);
- // ii. If SetDataHas(resultSetData, next) is false, then
- if (!set_data_has(result, *next)) {
- // 1. Append next to resultSetData.
- result->set_add(*next);
- }
- }
- } while (next.has_value());
- // 8. Let result be OrdinaryObjectCreate(%Set.prototype%, « [[SetData]] »).
- // 9. Set result.[[SetData]] to resultSetData.
- // 10. Return result.
- return result;
- }
- // 24.2.3.17 Set.prototype.values ( ), https://tc39.es/ecma262/#sec-set.prototype.values
- JS_DEFINE_NATIVE_FUNCTION(SetPrototype::values)
- {
- auto& realm = *vm.current_realm();
- // 1. Let S be the this value.
- // NOTE: CreateSetIterator checks the presence of a [[SetData]] slot, so we can do this here.
- auto set = TRY(typed_this_object(vm));
- // 2. Return ? CreateSetIterator(S, value).
- return SetIterator::create(realm, set, Object::PropertyKind::Value);
- }
- }
|