2020-04-04 20:28:21 +00:00
/*
2024-10-04 11:19:50 +00:00
* Copyright ( c ) 2020 , Andreas Kling < andreas @ ladybird . org >
2023-03-01 14:52:31 +00:00
* Copyright ( c ) 2020 - 2023 , Linus Groh < linusg @ serenityos . org >
2023-07-15 10:37:22 +00:00
* Copyright ( c ) 2023 , Shannon Booth < shannon @ serenityos . org >
2020-04-04 20:28:21 +00:00
*
2021-04-22 08:24:48 +00:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-04-04 20:28:21 +00:00
*/
# include <AK/Function.h>
2021-07-03 22:36:44 +00:00
# include <LibJS/Runtime/AbstractOperations.h>
2020-04-04 20:28:21 +00:00
# include <LibJS/Runtime/Array.h>
# include <LibJS/Runtime/ArrayConstructor.h>
2023-07-15 10:37:22 +00:00
# include <LibJS/Runtime/AsyncFromSyncIteratorPrototype.h>
# include <LibJS/Runtime/Completion.h>
# include <LibJS/Runtime/ECMAScriptFunctionObject.h>
2020-05-08 15:23:56 +00:00
# include <LibJS/Runtime/Error.h>
2020-04-18 11:18:06 +00:00
# include <LibJS/Runtime/GlobalObject.h>
2023-07-19 10:54:48 +00:00
# include <LibJS/Runtime/Iterator.h>
2023-07-15 10:37:22 +00:00
# include <LibJS/Runtime/PromiseCapability.h>
# include <LibJS/Runtime/PromiseConstructor.h>
2020-04-04 20:28:21 +00:00
# include <LibJS/Runtime/Shape.h>
namespace JS {
2024-11-14 15:01:23 +00:00
GC_DEFINE_ALLOCATOR ( ArrayConstructor ) ;
2023-11-19 08:45:05 +00:00
2022-08-15 23:20:49 +00:00
ArrayConstructor : : ArrayConstructor ( Realm & realm )
2023-04-12 22:47:15 +00:00
: NativeFunction ( realm . vm ( ) . names . Array . as_string ( ) , realm . intrinsics ( ) . function_prototype ( ) )
2020-04-04 20:28:21 +00:00
{
2020-06-20 13:40:48 +00:00
}
2023-08-07 06:41:28 +00:00
void ArrayConstructor : : initialize ( Realm & realm )
2020-06-20 13:40:48 +00:00
{
2020-10-13 21:49:19 +00:00
auto & vm = this - > vm ( ) ;
2023-08-07 06:41:28 +00:00
Base : : initialize ( realm ) ;
2020-06-20 13:40:48 +00:00
2021-06-12 23:22:35 +00:00
// 23.1.2.4 Array.prototype, https://tc39.es/ecma262/#sec-array.prototype
2022-08-26 23:54:55 +00:00
define_direct_property ( vm . names . prototype , realm . intrinsics ( ) . array_prototype ( ) , 0 ) ;
2021-06-12 23:22:35 +00:00
2020-05-08 15:28:35 +00:00
u8 attr = Attribute : : Writable | Attribute : : Configurable ;
2022-08-22 20:47:35 +00:00
define_native_function ( realm , vm . names . from , from , 1 , attr ) ;
2023-07-15 10:37:22 +00:00
define_native_function ( realm , vm . names . fromAsync , from_async , 1 , attr ) ;
2022-08-22 20:47:35 +00:00
define_native_function ( realm , vm . names . isArray , is_array , 1 , attr ) ;
define_native_function ( realm , vm . names . of , of , 0 , attr ) ;
2021-06-07 16:31:32 +00:00
2021-06-12 23:22:35 +00:00
// 23.1.2.5 get Array [ @@species ], https://tc39.es/ecma262/#sec-get-array-@@species
2023-04-12 23:14:45 +00:00
define_native_accessor ( realm , vm . well_known_symbol_species ( ) , symbol_species_getter , { } , Attribute : : Configurable ) ;
2021-07-07 23:49:53 +00:00
define_direct_property ( vm . names . length , Value ( 1 ) , Attribute : : Configurable ) ;
2020-04-04 20:28:21 +00:00
}
2021-06-12 23:22:35 +00:00
// 23.1.1.1 Array ( ...values ), https://tc39.es/ecma262/#sec-array
2021-10-20 20:16:30 +00:00
ThrowCompletionOr < Value > ArrayConstructor : : call ( )
2020-04-04 20:28:21 +00:00
{
2023-01-27 21:29:55 +00:00
// 1. If NewTarget is undefined, let newTarget be the active function object; else let newTarget be NewTarget.
2021-10-20 20:16:30 +00:00
return TRY ( construct ( * this ) ) ;
2021-07-03 22:36:44 +00:00
}
// 23.1.1.1 Array ( ...values ), https://tc39.es/ecma262/#sec-array
2024-11-14 15:01:23 +00:00
ThrowCompletionOr < GC : : Ref < Object > > ArrayConstructor : : construct ( FunctionObject & new_target )
2021-07-03 22:36:44 +00:00
{
auto & vm = this - > vm ( ) ;
2022-08-22 18:00:49 +00:00
auto & realm = * vm . current_realm ( ) ;
2021-07-03 22:36:44 +00:00
2023-01-27 21:29:55 +00:00
// 2. Let proto be ? GetPrototypeFromConstructor(newTarget, "%Array.prototype%").
2022-08-26 23:54:55 +00:00
auto * proto = TRY ( get_prototype_from_constructor ( vm , new_target , & Intrinsics : : array_prototype ) ) ;
2021-07-03 22:36:44 +00:00
2023-01-27 21:29:55 +00:00
// 3. Let numberOfArgs be the number of elements in values.
// 4. If numberOfArgs = 0, then
if ( vm . argument_count ( ) = = 0 ) {
// a. Return ! ArrayCreate(0, proto).
2022-12-14 19:18:10 +00:00
return MUST ( Array : : create ( realm , 0 , proto ) ) ;
2023-01-27 21:29:55 +00:00
}
2021-07-03 22:36:44 +00:00
2023-01-27 21:29:55 +00:00
// 5. Else if numberOfArgs = 1, then
2021-07-03 22:36:44 +00:00
if ( vm . argument_count ( ) = = 1 ) {
2023-01-27 21:29:55 +00:00
// a. Let len be values[0].
2021-07-03 22:36:44 +00:00
auto length = vm . argument ( 0 ) ;
2023-01-27 21:29:55 +00:00
// b. Let array be ! ArrayCreate(0, proto).
2022-12-13 20:49:49 +00:00
auto array = MUST ( Array : : create ( realm , 0 , proto ) ) ;
2023-01-27 21:29:55 +00:00
2021-07-03 22:36:44 +00:00
size_t int_length ;
2023-01-27 21:29:55 +00:00
// c. If len is not a Number, then
2021-07-03 22:36:44 +00:00
if ( ! length . is_number ( ) ) {
2023-01-27 21:29:55 +00:00
// i. Perform ! CreateDataPropertyOrThrow(array, "0", len).
2021-10-03 00:18:46 +00:00
MUST ( array - > create_data_property_or_throw ( 0 , length ) ) ;
2023-01-27 21:29:55 +00:00
// ii. Let intLen be 1𝔽 .
2021-07-03 22:36:44 +00:00
int_length = 1 ;
2023-01-27 21:29:55 +00:00
}
// d. Else,
else {
// i. Let intLen be ! ToUint32(len).
2022-08-21 13:00:56 +00:00
int_length = MUST ( length . to_u32 ( vm ) ) ;
2023-01-27 21:29:55 +00:00
// ii. If SameValueZero(intLen, len) is false, throw a RangeError exception.
2021-10-20 20:16:30 +00:00
if ( int_length ! = length . as_double ( ) )
2022-08-16 19:33:17 +00:00
return vm . throw_completion < RangeError > ( ErrorType : : InvalidLength , " array " ) ;
2020-05-08 15:23:56 +00:00
}
2023-01-27 21:29:55 +00:00
// e. Perform ! Set(array, "length", intLen, true).
2021-10-20 20:16:30 +00:00
TRY ( array - > set ( vm . names . length , Value ( int_length ) , Object : : ShouldThrowExceptions : : Yes ) ) ;
2023-01-27 21:29:55 +00:00
// f. Return array.
2022-12-14 19:18:10 +00:00
return array ;
2020-04-04 20:28:21 +00:00
}
2023-01-27 21:29:55 +00:00
// 6. Else,
// a. Assert: numberOfArgs ≥ 2.
VERIFY ( vm . argument_count ( ) > = 2 ) ;
// b. Let array be ? ArrayCreate(numberOfArgs, proto).
2022-12-13 20:49:49 +00:00
auto array = TRY ( Array : : create ( realm , vm . argument_count ( ) , proto ) ) ;
2020-04-04 20:28:21 +00:00
2023-01-27 21:29:55 +00:00
// c. Let k be 0.
// d. Repeat, while k < numberOfArgs,
for ( size_t k = 0 ; k < vm . argument_count ( ) ; + + k ) {
// i. Let Pk be ! ToString(𝔽 (k)).
auto property_key = PropertyKey { k } ;
// ii. Let itemK be values[k].
auto item_k = vm . argument ( k ) ;
// iii. Perform ! CreateDataPropertyOrThrow(array, Pk, itemK).
MUST ( array - > create_data_property_or_throw ( property_key , item_k ) ) ;
// iv. Set k to k + 1.
}
// e. Assert: The mathematical value of array's "length" property is numberOfArgs.
2021-07-03 22:36:44 +00:00
2023-01-27 21:29:55 +00:00
// f. Return array.
2022-12-14 19:18:10 +00:00
return array ;
2020-04-04 20:28:21 +00:00
}
2021-06-12 23:22:35 +00:00
// 23.1.2.1 Array.from ( items [ , mapfn [ , thisArg ] ] ), https://tc39.es/ecma262/#sec-array.from
2021-10-22 22:51:56 +00:00
JS_DEFINE_NATIVE_FUNCTION ( ArrayConstructor : : from )
2020-08-17 13:52:24 +00:00
{
2022-08-22 10:48:08 +00:00
auto & realm = * vm . current_realm ( ) ;
2023-01-27 21:29:55 +00:00
auto items = vm . argument ( 0 ) ;
auto mapfn_value = vm . argument ( 1 ) ;
auto this_arg = vm . argument ( 2 ) ;
// 1. Let C be the this value.
2022-08-20 08:48:43 +00:00
auto constructor = vm . this_value ( ) ;
2020-08-17 13:52:24 +00:00
2023-01-27 21:29:55 +00:00
// 2. If mapfn is undefined, let mapping be false.
2024-11-14 15:01:23 +00:00
GC : : Ptr < FunctionObject > mapfn ;
2021-04-06 20:12:38 +00:00
2023-01-27 21:29:55 +00:00
// 3. Else,
if ( ! mapfn_value . is_undefined ( ) ) {
// a. If IsCallable(mapfn) is false, throw a TypeError exception.
if ( ! mapfn_value . is_function ( ) )
2023-08-09 06:49:02 +00:00
return vm . throw_completion < TypeError > ( ErrorType : : NotAFunction , mapfn_value . to_string_without_side_effects ( ) ) ;
2021-04-12 08:59:26 +00:00
2023-01-27 21:29:55 +00:00
// b. Let mapping be true.
mapfn = & mapfn_value . as_function ( ) ;
}
// 4. Let usingIterator be ? GetMethod(items, @@iterator).
2023-04-12 23:14:45 +00:00
auto using_iterator = TRY ( items . get_method ( vm , vm . well_known_symbol_iterator ( ) ) ) ;
2023-01-27 21:29:55 +00:00
// 5. If usingIterator is not undefined, then
2021-07-03 22:36:44 +00:00
if ( using_iterator ) {
2024-11-14 15:01:23 +00:00
GC : : Ptr < Object > array ;
2023-01-27 21:29:55 +00:00
// a. If IsConstructor(C) is true, then
if ( constructor . is_constructor ( ) ) {
// i. Let A be ? Construct(C).
array = TRY ( JS : : construct ( vm , constructor . as_function ( ) ) ) ;
}
// b. Else,
else {
// i. Let A be ! ArrayCreate(0).
2022-08-15 23:20:49 +00:00
array = MUST ( Array : : create ( realm , 0 ) ) ;
2023-01-27 21:29:55 +00:00
}
2021-04-06 20:12:38 +00:00
2023-07-18 18:40:02 +00:00
// c. Let iteratorRecord be ? GetIteratorFromMethod(items, usingIterator).
auto iterator = TRY ( get_iterator_from_method ( vm , items , * using_iterator ) ) ;
2021-04-06 20:12:38 +00:00
2023-01-27 21:29:55 +00:00
// d. Let k be 0.
// e. Repeat,
for ( size_t k = 0 ; ; + + k ) {
// i. If k ≥ 2^53 - 1, then
2021-07-03 22:36:44 +00:00
if ( k > = MAX_ARRAY_LIKE_INDEX ) {
2023-01-27 21:29:55 +00:00
// 1. Let error be ThrowCompletion(a newly created TypeError object).
2022-08-16 19:33:17 +00:00
auto error = vm . throw_completion < TypeError > ( ErrorType : : ArrayMaxSize ) ;
2023-01-27 21:29:55 +00:00
// 2. Return ? IteratorClose(iteratorRecord, error).
2023-03-01 14:52:31 +00:00
return * TRY ( iterator_close ( vm , iterator , move ( error ) ) ) ;
2021-07-03 22:36:44 +00:00
}
2023-01-27 21:29:55 +00:00
// ii. Let Pk be ! ToString(𝔽 (k)).
auto property_key = PropertyKey { k } ;
2024-02-01 19:53:28 +00:00
// iii. Let next be ? IteratorStepValue(iteratorRecord).
auto next = TRY ( iterator_step_value ( vm , iterator ) ) ;
2023-01-27 21:29:55 +00:00
2024-02-01 19:53:28 +00:00
// iv. If next is DONE, then
if ( ! next . has_value ( ) ) {
2023-01-27 21:29:55 +00:00
// 1. Perform ? Set(A, "length", 𝔽 (k), true).
2021-10-22 22:51:56 +00:00
TRY ( array - > set ( vm . names . length , Value ( k ) , Object : : ShouldThrowExceptions : : Yes ) ) ;
2023-01-27 21:29:55 +00:00
// 2. Return A.
2021-07-03 22:36:44 +00:00
return array ;
2021-04-06 20:12:38 +00:00
}
2021-07-03 22:36:44 +00:00
Value mapped_value ;
2023-01-27 21:29:55 +00:00
2024-02-01 19:53:28 +00:00
// v. If mapping is true, then
2023-01-27 21:29:55 +00:00
if ( mapfn ) {
// 1. Let mappedValue be Completion(Call(mapfn, thisArg, « nextValue, 𝔽 (k) »)).
2024-02-01 19:53:28 +00:00
auto mapped_value_or_error = JS : : call ( vm , * mapfn , this_arg , next . release_value ( ) , Value ( k ) ) ;
2023-01-27 21:29:55 +00:00
// 2. IfAbruptCloseIterator(mappedValue, iteratorRecord).
2021-10-20 17:36:14 +00:00
if ( mapped_value_or_error . is_error ( ) )
2023-03-01 14:52:31 +00:00
return * TRY ( iterator_close ( vm , iterator , mapped_value_or_error . release_error ( ) ) ) ;
2021-09-23 22:41:54 +00:00
mapped_value = mapped_value_or_error . release_value ( ) ;
2023-01-27 21:29:55 +00:00
}
2024-02-01 19:53:28 +00:00
// vi. Else, let mappedValue be nextValue.
2023-01-27 21:29:55 +00:00
else {
2024-02-01 19:53:28 +00:00
mapped_value = next . release_value ( ) ;
2021-04-06 20:12:38 +00:00
}
2024-02-01 19:53:28 +00:00
// vii. Let defineStatus be Completion(CreateDataPropertyOrThrow(A, Pk, mappedValue)).
2023-01-27 21:29:55 +00:00
auto result_or_error = array - > create_data_property_or_throw ( property_key , mapped_value ) ;
2024-02-01 19:53:28 +00:00
// viii. IfAbruptCloseIterator(defineStatus, iteratorRecord).
2021-10-20 17:36:14 +00:00
if ( result_or_error . is_error ( ) )
2023-03-01 14:52:31 +00:00
return * TRY ( iterator_close ( vm , iterator , result_or_error . release_error ( ) ) ) ;
2021-07-03 22:36:44 +00:00
2024-02-01 19:53:28 +00:00
// ix. Set k to k + 1.
2021-07-03 22:36:44 +00:00
}
}
2023-01-27 21:29:55 +00:00
// 6. NOTE: items is not an Iterable so assume it is an array-like object.
// 7. Let arrayLike be ! ToObject(items).
2023-04-13 13:26:41 +00:00
auto array_like = MUST ( items . to_object ( vm ) ) ;
2021-07-03 22:36:44 +00:00
2023-01-27 21:29:55 +00:00
// 8. Let len be ? LengthOfArrayLike(arrayLike).
2023-04-13 13:26:41 +00:00
auto length = TRY ( length_of_array_like ( vm , array_like ) ) ;
2021-07-03 22:36:44 +00:00
2024-11-14 15:01:23 +00:00
GC : : Ptr < Object > array ;
2023-01-27 21:29:55 +00:00
// 9. If IsConstructor(C) is true, then
if ( constructor . is_constructor ( ) ) {
// a. Let A be ? Construct(C, « 𝔽 (len) »).
2022-08-21 18:24:32 +00:00
array = TRY ( JS : : construct ( vm , constructor . as_function ( ) , Value ( length ) ) ) ;
2023-01-27 21:29:55 +00:00
} else {
// a. Let A be ? ArrayCreate(len).
2022-08-15 23:20:49 +00:00
array = TRY ( Array : : create ( realm , length ) ) ;
2023-01-27 21:29:55 +00:00
}
2020-08-17 13:52:24 +00:00
2023-01-27 21:29:55 +00:00
// 11. Let k be 0.
// 12. Repeat, while k < len,
2021-07-03 22:36:44 +00:00
for ( size_t k = 0 ; k < length ; + + k ) {
2023-01-27 21:29:55 +00:00
// a. Let Pk be ! ToString(𝔽 (k)).
auto property_key = PropertyKey { k } ;
// b. Let kValue be ? Get(arrayLike, Pk).
auto k_value = TRY ( array_like - > get ( property_key ) ) ;
2021-07-03 22:36:44 +00:00
Value mapped_value ;
2023-01-27 21:29:55 +00:00
// c. If mapping is true, then
if ( mapfn ) {
// i. Let mappedValue be ? Call(mapfn, thisArg, « kValue, 𝔽 (k) »).
mapped_value = TRY ( JS : : call ( vm , * mapfn , this_arg , k_value , Value ( k ) ) ) ;
}
// d. Else, let mappedValue be kValue.
else {
2021-07-03 22:36:44 +00:00
mapped_value = k_value ;
2023-01-27 21:29:55 +00:00
}
// e. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
TRY ( array - > create_data_property_or_throw ( property_key , mapped_value ) ) ;
// f. Set k to k + 1.
2021-07-03 22:36:44 +00:00
}
2023-01-27 21:29:55 +00:00
// 13. Perform ? Set(A, "length", 𝔽 (len), true).
2021-10-22 22:51:56 +00:00
TRY ( array - > set ( vm . names . length , Value ( length ) , Object : : ShouldThrowExceptions : : Yes ) ) ;
2021-07-03 22:36:44 +00:00
2023-01-27 21:29:55 +00:00
// 14. Return A.
2020-08-17 13:52:24 +00:00
return array ;
}
2023-07-15 10:37:22 +00:00
// 2.1.1.1 Array.fromAsync ( asyncItems [ , mapfn [ , thisArg ] ] ), https://tc39.es/proposal-array-from-async/#sec-array.fromAsync
JS_DEFINE_NATIVE_FUNCTION ( ArrayConstructor : : from_async )
{
auto & realm = * vm . current_realm ( ) ;
auto async_items = vm . argument ( 0 ) ;
auto mapfn = vm . argument ( 1 ) ;
auto this_arg = vm . argument ( 2 ) ;
// 1. Let C be the this value.
auto constructor = vm . this_value ( ) ;
// 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
auto promise_capability = MUST ( new_promise_capability ( vm , realm . intrinsics ( ) . promise_constructor ( ) ) ) ;
// 3. Let fromAsyncClosure be a new Abstract Closure with no parameters that captures C, mapfn, and thisArg and performs the following steps when called:
2024-11-14 15:01:23 +00:00
auto from_async_closure = GC : : create_function ( realm . heap ( ) , [ constructor , mapfn , this_arg , & vm , & realm , async_items ] ( ) mutable - > Completion {
2023-07-15 10:37:22 +00:00
bool mapping ;
// a. If mapfn is undefined, let mapping be false.
if ( mapfn . is_undefined ( ) ) {
mapping = false ;
}
// b. Else,
else {
// i. If IsCallable(mapfn) is false, throw a TypeError exception.
if ( ! mapfn . is_function ( ) )
2023-08-09 06:49:02 +00:00
return vm . throw_completion < TypeError > ( ErrorType : : NotAFunction , mapfn . to_string_without_side_effects ( ) ) ;
2023-07-15 10:37:22 +00:00
// ii. Let mapping be true.
mapping = true ;
}
// c. Let usingAsyncIterator be ? GetMethod(asyncItems, @@asyncIterator).
auto using_async_iterator = TRY ( async_items . get_method ( vm , vm . well_known_symbol_async_iterator ( ) ) ) ;
2024-11-14 15:01:23 +00:00
GC : : Ptr < FunctionObject > using_sync_iterator ;
2023-07-15 10:37:22 +00:00
// d. If usingAsyncIterator is undefined, then
if ( ! using_async_iterator ) {
// i. Let usingSyncIterator be ? GetMethod(asyncItems, @@iterator).
using_sync_iterator = TRY ( async_items . get_method ( vm , vm . well_known_symbol_iterator ( ) ) ) ;
}
2023-08-28 08:13:01 +00:00
// e. Let iteratorRecord be undefined.
2024-11-14 15:01:23 +00:00
GC : : Ptr < IteratorRecord > iterator_record ;
2023-07-15 10:37:22 +00:00
2023-08-28 08:13:01 +00:00
// f. If usingAsyncIterator is not undefined, then
2023-07-15 10:37:22 +00:00
if ( using_async_iterator ) {
// i. Set iteratorRecord to ? GetIterator(asyncItems, async, usingAsyncIterator).
2023-07-18 18:40:02 +00:00
// FIXME: The Array.from proposal is out of date - it should be using GetIteratorFromMethod.
iterator_record = TRY ( get_iterator_from_method ( vm , async_items , * using_async_iterator ) ) ;
2023-07-15 10:37:22 +00:00
}
2023-08-28 08:13:01 +00:00
// g. Else if usingSyncIterator is not undefined, then
2023-07-15 10:37:22 +00:00
else if ( using_sync_iterator ) {
// i. Set iteratorRecord to ? CreateAsyncFromSyncIterator(GetIterator(asyncItems, sync, usingSyncIterator)).
2023-07-18 18:40:02 +00:00
// FIXME: The Array.from proposal is out of date - it should be using GetIteratorFromMethod.
iterator_record = create_async_from_sync_iterator ( vm , TRY ( get_iterator_from_method ( vm , async_items , * using_sync_iterator ) ) ) ;
2023-07-15 10:37:22 +00:00
}
2023-08-28 08:13:01 +00:00
// h. If iteratorRecord is not undefined, then
2023-12-07 09:44:41 +00:00
if ( iterator_record ) {
2024-11-14 15:01:23 +00:00
GC : : Ptr < Object > array ;
2023-08-28 08:13:01 +00:00
// i. If IsConstructor(C) is true, then
if ( constructor . is_constructor ( ) ) {
// 1. Let A be ? Construct(C).
array = TRY ( JS : : construct ( vm , constructor . as_function ( ) ) ) ;
}
// ii. Else,
else {
// i. Let A be ! ArrayCreate(0).
array = MUST ( Array : : create ( realm , 0 ) ) ;
}
// iii. Let k be 0.
// iv. Repeat,
2023-07-15 10:37:22 +00:00
for ( size_t k = 0 ; ; + + k ) {
// 1. If k ≥ 2^53 - 1, then
if ( k > = MAX_ARRAY_LIKE_INDEX ) {
// a. Let error be ThrowCompletion(a newly created TypeError object).
auto error = vm . throw_completion < TypeError > ( ErrorType : : ArrayMaxSize ) ;
// b. Return ? AsyncIteratorClose(iteratorRecord, error).
2023-12-07 09:44:41 +00:00
return * TRY ( async_iterator_close ( vm , * iterator_record , move ( error ) ) ) ;
2023-07-15 10:37:22 +00:00
}
// 2. Let Pk be ! ToString(𝔽 (k)).
auto property_key = PropertyKey { k } ;
2023-12-23 22:26:00 +00:00
// FIXME: There seems to be a bug here where we are not respecting array mutation. After resolving the first entry, the
// iterator should also take into account any other changes which are made to async_items (which does not seem to
// be happening).
// 3. Let nextResult be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]).
2023-07-15 10:37:22 +00:00
auto next_result = TRY ( JS : : call ( vm , iterator_record - > next_method , iterator_record - > iterator ) ) ;
2023-12-23 22:26:00 +00:00
// 4. Set nextResult to ? Await(nextResult).
2023-07-15 10:37:22 +00:00
next_result = TRY ( await ( vm , next_result ) ) ;
2023-12-23 22:26:00 +00:00
// 5. If nextResult is not an Object, throw a TypeError exception.
2023-07-15 10:37:22 +00:00
if ( ! next_result . is_object ( ) )
return vm . throw_completion < TypeError > ( ErrorType : : IterableNextBadReturn ) ;
2023-12-23 22:26:00 +00:00
// 6. Let done be ? IteratorComplete(nextResult).
2023-07-15 10:37:22 +00:00
auto done = TRY ( JS : : iterator_complete ( vm , next_result . as_object ( ) ) ) ;
2023-12-23 22:26:00 +00:00
// 7. If done is true,
2023-07-15 10:37:22 +00:00
if ( done ) {
2023-12-23 22:26:00 +00:00
// a. Perform ? Set(A, "length", 𝔽 (k), true).
2023-07-15 10:37:22 +00:00
TRY ( array - > set ( vm . names . length , Value ( k ) , Object : : ShouldThrowExceptions : : Yes ) ) ;
2023-12-23 22:26:00 +00:00
// b. Return Completion Record { [[Type]]: return, [[Value]]: A, [[Target]]: empty }.
2024-05-10 07:28:48 +00:00
return Completion { Completion : : Type : : Return , array } ;
2023-07-15 10:37:22 +00:00
}
2023-12-23 22:26:00 +00:00
// 8. Let nextValue be ? IteratorValue(nextResult).
2023-07-15 10:37:22 +00:00
auto next_value = TRY ( iterator_value ( vm , next_result . as_object ( ) ) ) ;
Value mapped_value ;
2023-12-23 22:26:00 +00:00
// 9. If mapping is true, then
2023-07-15 10:37:22 +00:00
if ( mapping ) {
// a. Let mappedValue be Call(mapfn, thisArg, « nextValue, 𝔽 (k) »).
auto mapped_value_or_error = JS : : call ( vm , mapfn , this_arg , next_value , Value ( k ) ) ;
// b. IfAbruptCloseAsyncIterator(mappedValue, iteratorRecord).
if ( mapped_value_or_error . is_error ( ) ) {
2023-12-07 09:44:41 +00:00
TRY ( async_iterator_close ( vm , * iterator_record , mapped_value_or_error ) ) ;
2023-07-15 10:37:22 +00:00
return mapped_value_or_error ;
}
// c. Set mappedValue to Await(mappedValue).
mapped_value_or_error = await ( vm , mapped_value_or_error . value ( ) ) ;
// d. IfAbruptCloseAsyncIterator(mappedValue, iteratorRecord).
if ( mapped_value_or_error . is_error ( ) ) {
2023-12-07 09:44:41 +00:00
TRY ( async_iterator_close ( vm , * iterator_record , mapped_value_or_error ) ) ;
2023-07-15 10:37:22 +00:00
return mapped_value_or_error ;
}
mapped_value = mapped_value_or_error . value ( ) ;
}
2023-12-23 22:26:00 +00:00
// 10. Else, let mappedValue be nextValue.
2023-07-15 10:37:22 +00:00
else {
mapped_value = next_value ;
}
2023-12-23 22:26:00 +00:00
// 11. Let defineStatus be CreateDataPropertyOrThrow(A, Pk, mappedValue).
2023-07-15 10:37:22 +00:00
auto define_status = array - > create_data_property_or_throw ( property_key , mapped_value ) ;
2023-12-23 22:26:00 +00:00
// 12. If defineStatus is an abrupt completion, return ? AsyncIteratorClose(iteratorRecord, defineStatus).
2023-07-15 10:37:22 +00:00
if ( define_status . is_error ( ) )
2023-12-07 09:44:41 +00:00
return * TRY ( iterator_close ( vm , * iterator_record , define_status . release_error ( ) ) ) ;
2023-07-15 10:37:22 +00:00
2023-12-23 22:26:00 +00:00
// 13. Set k to k + 1.
2023-07-15 10:37:22 +00:00
}
}
// k. Else,
else {
// i. NOTE: asyncItems is neither an AsyncIterable nor an Iterable so assume it is an array-like object.
// ii. Let arrayLike be ! ToObject(asyncItems).
auto array_like = MUST ( async_items . to_object ( vm ) ) ;
// iii. Let len be ? LengthOfArrayLike(arrayLike).
auto length = TRY ( length_of_array_like ( vm , array_like ) ) ;
2024-11-14 15:01:23 +00:00
GC : : Ptr < Object > array ;
2023-08-28 08:13:01 +00:00
2023-07-15 10:37:22 +00:00
// iv. If IsConstructor(C) is true, then
if ( constructor . is_constructor ( ) ) {
// 1. Let A be ? Construct(C, « 𝔽 (len) »).
array = TRY ( JS : : construct ( vm , constructor . as_function ( ) , Value ( length ) ) ) ;
}
// v. Else,
else {
// 1. Let A be ? ArrayCreate(len).
array = TRY ( Array : : create ( realm , length ) ) ;
}
// vi. Let k be 0.
// vii. Repeat, while k < len,
for ( size_t k = 0 ; k < length ; + + k ) {
// 1. Let Pk be ! ToString(𝔽 (k)).
auto property_key = PropertyKey { k } ;
// 2. Let kValue be ? Get(arrayLike, Pk).
auto k_value = TRY ( array_like - > get ( property_key ) ) ;
// 3. Set kValue to ? Await(kValue).
k_value = TRY ( await ( vm , k_value ) ) ;
Value mapped_value ;
// 4. If mapping is true, then
if ( mapping ) {
// a. Let mappedValue be ? Call(mapfn, thisArg, « kValue, 𝔽 (k) »).
mapped_value = TRY ( JS : : call ( vm , mapfn , this_arg , k_value , Value ( k ) ) ) ;
// b. Set mappedValue to ? Await(mappedValue).
mapped_value = TRY ( await ( vm , mapped_value ) ) ;
}
// 5. Else, let mappedValue be kValue.
else {
mapped_value = k_value ;
}
// 6. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
TRY ( array - > create_data_property_or_throw ( property_key , mapped_value ) ) ;
// 7. Set k to k + 1.
}
// viii. Perform ? Set(A, "length", 𝔽 (len), true).
TRY ( array - > set ( vm . names . length , Value ( length ) , Object : : ShouldThrowExceptions : : Yes ) ) ;
// ix. Return Completion Record { [[Type]]: return, [[Value]]: A, [[Target]]: empty }.
2024-05-10 07:28:48 +00:00
return Completion { Completion : : Type : : Return , array } ;
2023-07-15 10:37:22 +00:00
}
2024-10-30 17:21:59 +00:00
} ) ;
2023-07-15 10:37:22 +00:00
// 4. Perform AsyncFunctionStart(promiseCapability, fromAsyncClosure).
2024-10-30 17:21:59 +00:00
async_function_start ( vm , promise_capability , * from_async_closure ) ;
2023-07-15 10:37:22 +00:00
// 5. Return promiseCapability.[[Promise]].
return promise_capability - > promise ( ) ;
}
2021-06-12 23:22:35 +00:00
// 23.1.2.2 Array.isArray ( arg ), https://tc39.es/ecma262/#sec-array.isarray
2021-10-22 22:51:56 +00:00
JS_DEFINE_NATIVE_FUNCTION ( ArrayConstructor : : is_array )
2020-05-08 15:28:35 +00:00
{
2023-01-27 21:29:55 +00:00
auto arg = vm . argument ( 0 ) ;
// 1. Return ? IsArray(arg).
return Value ( TRY ( arg . is_array ( vm ) ) ) ;
2020-05-08 15:28:35 +00:00
}
2021-06-12 23:22:35 +00:00
// 23.1.2.3 Array.of ( ...items ), https://tc39.es/ecma262/#sec-array.of
2021-10-22 22:51:56 +00:00
JS_DEFINE_NATIVE_FUNCTION ( ArrayConstructor : : of )
2020-05-08 15:32:56 +00:00
{
2022-08-22 10:48:08 +00:00
auto & realm = * vm . current_realm ( ) ;
2023-01-27 21:29:55 +00:00
// 1. Let len be the number of elements in items.
auto len = vm . argument_count ( ) ;
// 2. Let lenNumber be 𝔽 (len).
auto len_number = Value ( len ) ;
// 3. Let C be the this value.
auto constructor = vm . this_value ( ) ;
2024-11-14 15:01:23 +00:00
GC : : Ptr < Object > array ;
2023-01-27 21:29:55 +00:00
// 4. If IsConstructor(C) is true, then
if ( constructor . is_constructor ( ) ) {
// a. Let A be ? Construct(C, « lenNumber »).
array = TRY ( JS : : construct ( vm , constructor . as_function ( ) , Value ( vm . argument_count ( ) ) ) ) ;
} else {
// a. Let A be ? ArrayCreate(len).
array = TRY ( Array : : create ( realm , len ) ) ;
}
// 6. Let k be 0.
// 7. Repeat, while k < len,
for ( size_t k = 0 ; k < len ; + + k ) {
// a. Let kValue be items[k].
auto k_value = vm . argument ( k ) ;
// b. Let Pk be ! ToString(𝔽 (k)).
auto property_key = PropertyKey { k } ;
// c. Perform ? CreateDataPropertyOrThrow(A, Pk, kValue).
TRY ( array - > create_data_property_or_throw ( property_key , k_value ) ) ;
// d. Set k to k + 1.
}
// 8. Perform ? Set(A, "length", lenNumber, true).
TRY ( array - > set ( vm . names . length , len_number , Object : : ShouldThrowExceptions : : Yes ) ) ;
// 9. Return A.
2020-05-08 15:32:56 +00:00
return array ;
}
2021-06-12 23:22:35 +00:00
// 23.1.2.5 get Array [ @@species ], https://tc39.es/ecma262/#sec-get-array-@@species
2021-10-22 22:51:56 +00:00
JS_DEFINE_NATIVE_FUNCTION ( ArrayConstructor : : symbol_species_getter )
2021-06-07 16:31:32 +00:00
{
2023-01-27 21:29:55 +00:00
// 1. Return the this value.
2022-08-20 08:48:43 +00:00
return vm . this_value ( ) ;
2021-06-07 16:31:32 +00:00
}
2020-04-04 20:28:21 +00:00
}