|
@@ -44,16 +44,35 @@ ThrowCompletionOr<void> MapPrototype::initialize(Realm& realm)
|
|
|
// 24.1.3.1 Map.prototype.clear ( ), https://tc39.es/ecma262/#sec-map.prototype.clear
|
|
|
JS_DEFINE_NATIVE_FUNCTION(MapPrototype::clear)
|
|
|
{
|
|
|
+ // 1. Let M be the this value.
|
|
|
+ // 2. Perform ? RequireInternalSlot(M, [[MapData]]).
|
|
|
auto map = TRY(typed_this_object(vm));
|
|
|
+
|
|
|
+ // 3. For each Record { [[Key]], [[Value]] } p of M.[[MapData]], do
|
|
|
+ // a. Set p.[[Key]] to empty.
|
|
|
+ // b. Set p.[[Value]] to empty.
|
|
|
map->map_clear();
|
|
|
+
|
|
|
+ // 4. Return undefined.
|
|
|
return js_undefined();
|
|
|
}
|
|
|
|
|
|
// 24.1.3.3 Map.prototype.delete ( key ), https://tc39.es/ecma262/#sec-map.prototype.delete
|
|
|
JS_DEFINE_NATIVE_FUNCTION(MapPrototype::delete_)
|
|
|
{
|
|
|
+ auto key = vm.argument(0);
|
|
|
+
|
|
|
+ // 1. Let M be the this value.
|
|
|
+ // 2. Perform ? RequireInternalSlot(M, [[MapData]]).
|
|
|
auto map = TRY(typed_this_object(vm));
|
|
|
- return Value(map->map_remove(vm.argument(0)));
|
|
|
+
|
|
|
+ // 3. For each Record { [[Key]], [[Value]] } p of M.[[MapData]], do
|
|
|
+ // a. If p.[[Key]] is not empty and SameValueZero(p.[[Key]], key) is true, then
|
|
|
+ // i. Set p.[[Key]] to empty.
|
|
|
+ // ii. Set p.[[Value]] to empty.
|
|
|
+ // iii. Return true.
|
|
|
+ // 4. Return false.
|
|
|
+ return Value(map->map_remove(key));
|
|
|
}
|
|
|
|
|
|
// 24.1.3.4 Map.prototype.entries ( ), https://tc39.es/ecma262/#sec-map.prototype.entries
|
|
@@ -61,38 +80,80 @@ JS_DEFINE_NATIVE_FUNCTION(MapPrototype::entries)
|
|
|
{
|
|
|
auto& realm = *vm.current_realm();
|
|
|
|
|
|
+ // 1. Let M be the this value.
|
|
|
auto map = TRY(typed_this_object(vm));
|
|
|
|
|
|
- return MapIterator::create(realm, map, Object::PropertyKind::KeyAndValue);
|
|
|
+ // 2. Return ? CreateMapIterator(M, key+value).
|
|
|
+ return MapIterator::create(realm, *map, Object::PropertyKind::KeyAndValue);
|
|
|
}
|
|
|
|
|
|
// 24.1.3.5 Map.prototype.forEach ( callbackfn [ , thisArg ] ), https://tc39.es/ecma262/#sec-map.prototype.foreach
|
|
|
JS_DEFINE_NATIVE_FUNCTION(MapPrototype::for_each)
|
|
|
{
|
|
|
+ auto callbackfn = vm.argument(0);
|
|
|
+ auto this_arg = vm.argument(1);
|
|
|
+
|
|
|
+ // 1. Let M be the this value.
|
|
|
+ // 2. Perform ? RequireInternalSlot(M, [[MapData]]).
|
|
|
auto map = TRY(typed_this_object(vm));
|
|
|
- if (!vm.argument(0).is_function())
|
|
|
- return vm.throw_completion<TypeError>(ErrorType::NotAFunction, TRY_OR_THROW_OOM(vm, vm.argument(0).to_string_without_side_effects()));
|
|
|
- auto this_value = vm.this_value();
|
|
|
- for (auto& entry : *map)
|
|
|
- TRY(call(vm, vm.argument(0).as_function(), vm.argument(1), entry.value, entry.key, this_value));
|
|
|
+
|
|
|
+ // 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
|
|
|
+ if (!callbackfn.is_function())
|
|
|
+ return vm.throw_completion<TypeError>(ErrorType::NotAFunction, TRY_OR_THROW_OOM(vm, callbackfn.to_string_without_side_effects()));
|
|
|
+
|
|
|
+ // 4. Let entries be M.[[MapData]].
|
|
|
+ // 5. Let numEntries be the number of elements in entries.
|
|
|
+ // 6. Let index be 0.
|
|
|
+ // 7. Repeat, while index < numEntries,
|
|
|
+ for (auto& entry : *map) {
|
|
|
+ // i. Let e be entries[index].
|
|
|
+ // b. Set index to index + 1.
|
|
|
+ // c. If e.[[Key]] is not empty, then
|
|
|
+ // NOTE: This is handled by Map's IteratorImpl.
|
|
|
+
|
|
|
+ // i. Perform ? Call(callbackfn, thisArg, « e.[[Value]], e.[[Key]], M »).
|
|
|
+ TRY(call(vm, callbackfn.as_function(), this_arg, entry.value, entry.key, map));
|
|
|
+
|
|
|
+ // 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.
|
|
|
+ }
|
|
|
+
|
|
|
+ // 8. Return undefined.
|
|
|
return js_undefined();
|
|
|
}
|
|
|
|
|
|
// 24.1.3.6 Map.prototype.get ( key ), https://tc39.es/ecma262/#sec-map.prototype.get
|
|
|
JS_DEFINE_NATIVE_FUNCTION(MapPrototype::get)
|
|
|
{
|
|
|
+ auto key = vm.argument(0);
|
|
|
+
|
|
|
+ // 1. Let M be the this value.
|
|
|
+ // 2. Perform ? RequireInternalSlot(M, [[MapData]]).
|
|
|
auto map = TRY(typed_this_object(vm));
|
|
|
- auto result = map->map_get(vm.argument(0));
|
|
|
- if (!result.has_value())
|
|
|
- return js_undefined();
|
|
|
- return result.value();
|
|
|
+
|
|
|
+ // 3. For each Record { [[Key]], [[Value]] } p of M.[[MapData]], do
|
|
|
+ // a. If p.[[Key]] is not empty and SameValueZero(p.[[Key]], key) is true, return p.[[Value]].
|
|
|
+ auto result = map->map_get(key);
|
|
|
+ if (result.has_value())
|
|
|
+ return result.value();
|
|
|
+
|
|
|
+ // 4. Return undefined.
|
|
|
+ return js_undefined();
|
|
|
}
|
|
|
|
|
|
// 24.1.3.7 Map.prototype.has ( key ), https://tc39.es/ecma262/#sec-map.prototype.has
|
|
|
JS_DEFINE_NATIVE_FUNCTION(MapPrototype::has)
|
|
|
{
|
|
|
+ auto key = vm.argument(0);
|
|
|
+
|
|
|
+ // 1. Let M be the this value.
|
|
|
+ // 2. Perform ? RequireInternalSlot(M, [[MapData]]).
|
|
|
auto map = TRY(typed_this_object(vm));
|
|
|
- return map->map_has(vm.argument(0));
|
|
|
+
|
|
|
+ // 3. For each Record { [[Key]], [[Value]] } p of M.[[MapData]], do
|
|
|
+ // a. If p.[[Key]] is not empty and SameValueZero(p.[[Key]], key) is true, return true.
|
|
|
+ // 4. Return false.
|
|
|
+ return map->map_has(key);
|
|
|
}
|
|
|
|
|
|
// 24.1.3.8 Map.prototype.keys ( ), https://tc39.es/ecma262/#sec-map.prototype.keys
|
|
@@ -100,37 +161,65 @@ JS_DEFINE_NATIVE_FUNCTION(MapPrototype::keys)
|
|
|
{
|
|
|
auto& realm = *vm.current_realm();
|
|
|
|
|
|
+ // 1. Let M be the this value.
|
|
|
auto map = TRY(typed_this_object(vm));
|
|
|
|
|
|
- return MapIterator::create(realm, map, Object::PropertyKind::Key);
|
|
|
+ // 2. Return ? CreateMapIterator(M, key).
|
|
|
+ return MapIterator::create(realm, *map, Object::PropertyKind::Key);
|
|
|
}
|
|
|
|
|
|
// 24.1.3.9 Map.prototype.set ( key, value ), https://tc39.es/ecma262/#sec-map.prototype.set
|
|
|
JS_DEFINE_NATIVE_FUNCTION(MapPrototype::set)
|
|
|
{
|
|
|
- auto map = TRY(typed_this_object(vm));
|
|
|
auto key = vm.argument(0);
|
|
|
+ auto value = vm.argument(1);
|
|
|
+
|
|
|
+ // 1. Let M be the this value.
|
|
|
+ // 2. Perform ? RequireInternalSlot(M, [[MapData]]).
|
|
|
+ auto map = TRY(typed_this_object(vm));
|
|
|
+
|
|
|
+ // 4. If key is -0𝔽, set key to +0𝔽.
|
|
|
if (key.is_negative_zero())
|
|
|
key = Value(0);
|
|
|
- map->map_set(key, vm.argument(1));
|
|
|
+
|
|
|
+ // 3. For each Record { [[Key]], [[Value]] } p of M.[[MapData]], do
|
|
|
+ // a. If p.[[Key]] is not empty and SameValueZero(p.[[Key]], key) is true, then
|
|
|
+ // i. Set p.[[Value]] to value.
|
|
|
+ // ii. Return M.
|
|
|
+ // 5. Let p be the Record { [[Key]]: key, [[Value]]: value }.
|
|
|
+ // 6. Append p to M.[[MapData]].
|
|
|
+ map->map_set(key, value);
|
|
|
+
|
|
|
+ // 7. Return M.
|
|
|
return map;
|
|
|
}
|
|
|
|
|
|
-// 24.1.3.11 Map.prototype.values ( ), https://tc39.es/ecma262/#sec-map.prototype.values
|
|
|
-JS_DEFINE_NATIVE_FUNCTION(MapPrototype::values)
|
|
|
+// 24.1.3.10 get Map.prototype.size, https://tc39.es/ecma262/#sec-get-map.prototype.size
|
|
|
+JS_DEFINE_NATIVE_FUNCTION(MapPrototype::size_getter)
|
|
|
{
|
|
|
- auto& realm = *vm.current_realm();
|
|
|
-
|
|
|
+ // 1. Let M be the this value.
|
|
|
+ // 2. Perform ? RequireInternalSlot(M, [[MapData]]).
|
|
|
auto map = TRY(typed_this_object(vm));
|
|
|
|
|
|
- return MapIterator::create(realm, map, Object::PropertyKind::Value);
|
|
|
+ // 3. Let count be 0.
|
|
|
+ // 4. For each Record { [[Key]], [[Value]] } p of M.[[MapData]], do
|
|
|
+ // a. If p.[[Key]] is not empty, set count to count + 1.
|
|
|
+ auto count = map->map_size();
|
|
|
+
|
|
|
+ // 5. Return 𝔽(count).
|
|
|
+ return Value(count);
|
|
|
}
|
|
|
|
|
|
-// 24.1.3.10 get Map.prototype.size, https://tc39.es/ecma262/#sec-get-map.prototype.size
|
|
|
-JS_DEFINE_NATIVE_FUNCTION(MapPrototype::size_getter)
|
|
|
+// 24.1.3.11 Map.prototype.values ( ), https://tc39.es/ecma262/#sec-map.prototype.values
|
|
|
+JS_DEFINE_NATIVE_FUNCTION(MapPrototype::values)
|
|
|
{
|
|
|
+ auto& realm = *vm.current_realm();
|
|
|
+
|
|
|
+ // 1. Let M be the this value.
|
|
|
auto map = TRY(typed_this_object(vm));
|
|
|
- return Value(map->map_size());
|
|
|
+
|
|
|
+ // 2. Return ? CreateMapIterator(M, value).
|
|
|
+ return MapIterator::create(realm, *map, Object::PropertyKind::Value);
|
|
|
}
|
|
|
|
|
|
}
|