diff options
author | Linus Groh <mail@linusgroh.de> | 2023-04-14 17:03:05 +0200 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2023-04-15 14:07:28 +0200 |
commit | f3f78642f4a479e81d8112e2e0e9af6b8aad60a3 (patch) | |
tree | 5661993ade12c1aaadd2d9f81e16f0a1f4ab9be5 | |
parent | 2140200a196c60f68a0f380e425508411df5b080 (diff) | |
download | serenity-f3f78642f4a479e81d8112e2e0e9af6b8aad60a3.zip |
LibJS: Add spec comments to MapPrototype
-rw-r--r-- | Userland/Libraries/LibJS/Runtime/MapPrototype.cpp | 135 |
1 files changed, 112 insertions, 23 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/MapPrototype.cpp b/Userland/Libraries/LibJS/Runtime/MapPrototype.cpp index b165315e88..4dff35c5b7 100644 --- a/Userland/Libraries/LibJS/Runtime/MapPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/MapPrototype.cpp @@ -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); } } |