2021-06-12 23:54:40 +03:00
/*
* Copyright ( c ) 2021 , Idan Horowitz < idan . horowitz @ serenityos . org >
2023-07-11 16:23:00 +02:00
* Copyright ( c ) 2021 - 2023 , Linus Groh < linusg @ serenityos . org >
2021-06-12 23:54:40 +03:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2021-06-20 01:09:39 +01:00
# include <LibJS/Runtime/AbstractOperations.h>
2023-07-11 16:23:00 +02:00
# include <LibJS/Runtime/Array.h>
2021-06-12 23:54:40 +03:00
# include <LibJS/Runtime/Error.h>
2023-07-19 06:54:48 -04:00
# include <LibJS/Runtime/Iterator.h>
2021-06-12 23:54:40 +03:00
# include <LibJS/Runtime/Map.h>
# include <LibJS/Runtime/MapConstructor.h>
namespace JS {
2024-11-15 04:01:23 +13:00
GC_DEFINE_ALLOCATOR ( MapConstructor ) ;
2023-11-19 09:45:05 +01:00
2022-08-16 00:20:49 +01:00
MapConstructor : : MapConstructor ( Realm & realm )
2023-04-13 00:47:15 +02:00
: NativeFunction ( realm . vm ( ) . names . Map . as_string ( ) , realm . intrinsics ( ) . function_prototype ( ) )
2021-06-12 23:54:40 +03:00
{
}
2023-08-07 08:41:28 +02:00
void MapConstructor : : initialize ( Realm & realm )
2021-06-12 23:54:40 +03:00
{
auto & vm = this - > vm ( ) ;
2023-08-07 08:41:28 +02:00
Base : : initialize ( realm ) ;
2021-06-13 12:20:21 +01:00
2023-12-26 08:55:15 -05:00
// 24.1.2.2 Map.prototype, https://tc39.es/ecma262/#sec-map.prototype
2022-08-27 00:54:55 +01:00
define_direct_property ( vm . names . prototype , realm . intrinsics ( ) . map_prototype ( ) , 0 ) ;
2021-06-13 12:20:21 +01:00
2023-07-11 16:23:00 +02:00
u8 attr = Attribute : : Writable | Attribute : : Configurable ;
define_native_function ( realm , vm . names . groupBy , group_by , 2 , attr ) ;
2023-04-13 01:14:45 +02:00
define_native_accessor ( realm , vm . well_known_symbol_species ( ) , symbol_species_getter , { } , Attribute : : Configurable ) ;
2021-07-08 02:49:53 +03:00
define_direct_property ( vm . names . length , Value ( 0 ) , Attribute : : Configurable ) ;
2021-06-12 23:54:40 +03:00
}
2021-06-13 12:20:21 +01:00
// 24.1.1.1 Map ( [ iterable ] ), https://tc39.es/ecma262/#sec-map-iterable
2021-10-20 21:16:30 +01:00
ThrowCompletionOr < Value > MapConstructor : : call ( )
2021-06-12 23:54:40 +03:00
{
auto & vm = this - > vm ( ) ;
2022-08-16 20:33:17 +01:00
return vm . throw_completion < TypeError > ( ErrorType : : ConstructorWithoutNew , vm . names . Map ) ;
2021-06-12 23:54:40 +03:00
}
// 24.1.1.1 Map ( [ iterable ] ), https://tc39.es/ecma262/#sec-map-iterable
2024-11-15 04:01:23 +13:00
ThrowCompletionOr < GC : : Ref < Object > > MapConstructor : : construct ( FunctionObject & new_target )
2021-06-12 23:54:40 +03:00
{
auto & vm = this - > vm ( ) ;
2021-06-20 01:09:39 +01:00
2022-12-14 18:34:32 +00:00
auto map = TRY ( ordinary_create_from_constructor < Map > ( vm , new_target , & Intrinsics : : map_prototype ) ) ;
2021-06-12 23:54:40 +03:00
if ( vm . argument ( 0 ) . is_nullish ( ) )
2022-12-14 19:18:10 +00:00
return map ;
2021-06-12 23:54:40 +03:00
2021-10-20 21:16:30 +01:00
auto adder = TRY ( map - > get ( vm . names . set ) ) ;
if ( ! adder . is_function ( ) )
2022-08-16 20:33:17 +01:00
return vm . throw_completion < TypeError > ( ErrorType : : NotAFunction , " 'set' property of Map " ) ;
2021-10-20 12:10:23 -04:00
2022-08-21 15:56:27 +01:00
( void ) TRY ( get_iterator_values ( vm , vm . argument ( 0 ) , [ & ] ( Value iterator_value ) - > Optional < Completion > {
2021-10-20 12:10:23 -04:00
if ( ! iterator_value . is_object ( ) )
2023-12-16 17:49:34 +03:30
return vm . throw_completion < TypeError > ( ErrorType : : NotAnObject , ByteString : : formatted ( " Iterator value {} " , iterator_value . to_string_without_side_effects ( ) ) ) ;
2021-10-20 12:10:23 -04:00
auto key = TRY ( iterator_value . as_object ( ) . get ( 0 ) ) ;
auto value = TRY ( iterator_value . as_object ( ) . get ( 1 ) ) ;
2022-08-21 19:24:32 +01:00
TRY ( JS : : call ( vm , adder . as_function ( ) , map , key , value ) ) ;
2021-10-20 12:10:23 -04:00
2021-06-12 23:54:40 +03:00
return { } ;
2021-10-20 12:10:23 -04:00
} ) ) ;
2022-12-14 19:18:10 +00:00
return map ;
2021-06-12 23:54:40 +03:00
}
2023-12-26 08:55:15 -05:00
// 24.1.2.1 Map.groupBy ( items, callbackfn ), https://tc39.es/ecma262/#sec-map.groupby
2023-07-11 16:23:00 +02:00
JS_DEFINE_NATIVE_FUNCTION ( MapConstructor : : group_by )
{
auto & realm = * vm . current_realm ( ) ;
auto items = vm . argument ( 0 ) ;
auto callback_function = vm . argument ( 1 ) ;
2024-11-15 04:01:23 +13:00
struct KeyedGroupTraits : public Traits < GC : : Root < Value > > {
static unsigned hash ( GC : : Root < Value > const & value_handle )
2023-07-11 16:23:00 +02:00
{
return ValueTraits : : hash ( value_handle . value ( ) ) ;
}
2024-11-15 04:01:23 +13:00
static bool equals ( GC : : Root < Value > const & a , GC : : Root < Value > const & b )
2023-07-11 16:23:00 +02:00
{
// AddValueToKeyedGroup uses SameValue on the keys on Step 1.a.
return same_value ( a . value ( ) , b . value ( ) ) ;
}
} ;
// 1. Let groups be ? GroupBy(items, callbackfn, zero).
2024-11-15 04:01:23 +13:00
auto groups = TRY ( ( JS : : group_by < OrderedHashMap < GC : : Root < Value > , GC : : MarkedVector < Value > , KeyedGroupTraits > , void > ( vm , items , callback_function ) ) ) ;
2023-07-11 16:23:00 +02:00
// 2. Let map be ! Construct(%Map%).
auto map = Map : : create ( realm ) ;
// 3. For each Record { [[Key]], [[Elements]] } g of groups, do
for ( auto & group : groups ) {
// a. Let elements be CreateArrayFromList(g.[[Elements]]).
auto elements = Array : : create_from ( realm , group . value ) ;
// b. Let entry be the Record { [[Key]]: g.[[Key]], [[Value]]: elements }.
// c. Append entry to map.[[MapData]].
map - > map_set ( group . key . value ( ) , elements ) ;
}
// 4. Return map.
return map ;
}
2023-12-26 08:55:15 -05:00
// 24.1.2.3 get Map [ @@species ], https://tc39.es/ecma262/#sec-get-map-@@species
2021-10-29 01:00:36 +03:00
JS_DEFINE_NATIVE_FUNCTION ( MapConstructor : : symbol_species_getter )
2021-06-12 23:54:40 +03:00
{
2022-08-20 09:48:43 +01:00
return vm . this_value ( ) ;
2021-06-12 23:54:40 +03:00
}
}