ArrayConstructor.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. /*
  2. * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2020-2023, Linus Groh <linusg@serenityos.org>
  4. * Copyright (c) 2023, Shannon Booth <shannon@serenityos.org>
  5. *
  6. * SPDX-License-Identifier: BSD-2-Clause
  7. */
  8. #include <AK/Function.h>
  9. #include <LibJS/Runtime/AbstractOperations.h>
  10. #include <LibJS/Runtime/Array.h>
  11. #include <LibJS/Runtime/ArrayConstructor.h>
  12. #include <LibJS/Runtime/AsyncFromSyncIteratorPrototype.h>
  13. #include <LibJS/Runtime/Completion.h>
  14. #include <LibJS/Runtime/ECMAScriptFunctionObject.h>
  15. #include <LibJS/Runtime/Error.h>
  16. #include <LibJS/Runtime/GlobalObject.h>
  17. #include <LibJS/Runtime/Iterator.h>
  18. #include <LibJS/Runtime/PromiseCapability.h>
  19. #include <LibJS/Runtime/PromiseConstructor.h>
  20. #include <LibJS/Runtime/Shape.h>
  21. namespace JS {
  22. ArrayConstructor::ArrayConstructor(Realm& realm)
  23. : NativeFunction(realm.vm().names.Array.as_string(), realm.intrinsics().function_prototype())
  24. {
  25. }
  26. void ArrayConstructor::initialize(Realm& realm)
  27. {
  28. auto& vm = this->vm();
  29. Base::initialize(realm);
  30. // 23.1.2.4 Array.prototype, https://tc39.es/ecma262/#sec-array.prototype
  31. define_direct_property(vm.names.prototype, realm.intrinsics().array_prototype(), 0);
  32. u8 attr = Attribute::Writable | Attribute::Configurable;
  33. define_native_function(realm, vm.names.from, from, 1, attr);
  34. define_native_function(realm, vm.names.fromAsync, from_async, 1, attr);
  35. define_native_function(realm, vm.names.isArray, is_array, 1, attr);
  36. define_native_function(realm, vm.names.of, of, 0, attr);
  37. // 23.1.2.5 get Array [ @@species ], https://tc39.es/ecma262/#sec-get-array-@@species
  38. define_native_accessor(realm, vm.well_known_symbol_species(), symbol_species_getter, {}, Attribute::Configurable);
  39. define_direct_property(vm.names.length, Value(1), Attribute::Configurable);
  40. }
  41. // 23.1.1.1 Array ( ...values ), https://tc39.es/ecma262/#sec-array
  42. ThrowCompletionOr<Value> ArrayConstructor::call()
  43. {
  44. // 1. If NewTarget is undefined, let newTarget be the active function object; else let newTarget be NewTarget.
  45. return TRY(construct(*this));
  46. }
  47. // 23.1.1.1 Array ( ...values ), https://tc39.es/ecma262/#sec-array
  48. ThrowCompletionOr<NonnullGCPtr<Object>> ArrayConstructor::construct(FunctionObject& new_target)
  49. {
  50. auto& vm = this->vm();
  51. auto& realm = *vm.current_realm();
  52. // 2. Let proto be ? GetPrototypeFromConstructor(newTarget, "%Array.prototype%").
  53. auto* proto = TRY(get_prototype_from_constructor(vm, new_target, &Intrinsics::array_prototype));
  54. // 3. Let numberOfArgs be the number of elements in values.
  55. // 4. If numberOfArgs = 0, then
  56. if (vm.argument_count() == 0) {
  57. // a. Return ! ArrayCreate(0, proto).
  58. return MUST(Array::create(realm, 0, proto));
  59. }
  60. // 5. Else if numberOfArgs = 1, then
  61. if (vm.argument_count() == 1) {
  62. // a. Let len be values[0].
  63. auto length = vm.argument(0);
  64. // b. Let array be ! ArrayCreate(0, proto).
  65. auto array = MUST(Array::create(realm, 0, proto));
  66. size_t int_length;
  67. // c. If len is not a Number, then
  68. if (!length.is_number()) {
  69. // i. Perform ! CreateDataPropertyOrThrow(array, "0", len).
  70. MUST(array->create_data_property_or_throw(0, length));
  71. // ii. Let intLen be 1𝔽.
  72. int_length = 1;
  73. }
  74. // d. Else,
  75. else {
  76. // i. Let intLen be ! ToUint32(len).
  77. int_length = MUST(length.to_u32(vm));
  78. // ii. If SameValueZero(intLen, len) is false, throw a RangeError exception.
  79. if (int_length != length.as_double())
  80. return vm.throw_completion<RangeError>(ErrorType::InvalidLength, "array");
  81. }
  82. // e. Perform ! Set(array, "length", intLen, true).
  83. TRY(array->set(vm.names.length, Value(int_length), Object::ShouldThrowExceptions::Yes));
  84. // f. Return array.
  85. return array;
  86. }
  87. // 6. Else,
  88. // a. Assert: numberOfArgs ≥ 2.
  89. VERIFY(vm.argument_count() >= 2);
  90. // b. Let array be ? ArrayCreate(numberOfArgs, proto).
  91. auto array = TRY(Array::create(realm, vm.argument_count(), proto));
  92. // c. Let k be 0.
  93. // d. Repeat, while k < numberOfArgs,
  94. for (size_t k = 0; k < vm.argument_count(); ++k) {
  95. // i. Let Pk be ! ToString(𝔽(k)).
  96. auto property_key = PropertyKey { k };
  97. // ii. Let itemK be values[k].
  98. auto item_k = vm.argument(k);
  99. // iii. Perform ! CreateDataPropertyOrThrow(array, Pk, itemK).
  100. MUST(array->create_data_property_or_throw(property_key, item_k));
  101. // iv. Set k to k + 1.
  102. }
  103. // e. Assert: The mathematical value of array's "length" property is numberOfArgs.
  104. // f. Return array.
  105. return array;
  106. }
  107. // 23.1.2.1 Array.from ( items [ , mapfn [ , thisArg ] ] ), https://tc39.es/ecma262/#sec-array.from
  108. JS_DEFINE_NATIVE_FUNCTION(ArrayConstructor::from)
  109. {
  110. auto& realm = *vm.current_realm();
  111. auto items = vm.argument(0);
  112. auto mapfn_value = vm.argument(1);
  113. auto this_arg = vm.argument(2);
  114. // 1. Let C be the this value.
  115. auto constructor = vm.this_value();
  116. // 2. If mapfn is undefined, let mapping be false.
  117. GCPtr<FunctionObject> mapfn;
  118. // 3. Else,
  119. if (!mapfn_value.is_undefined()) {
  120. // a. If IsCallable(mapfn) is false, throw a TypeError exception.
  121. if (!mapfn_value.is_function())
  122. return vm.throw_completion<TypeError>(ErrorType::NotAFunction, TRY_OR_THROW_OOM(vm, mapfn_value.to_string_without_side_effects()));
  123. // b. Let mapping be true.
  124. mapfn = &mapfn_value.as_function();
  125. }
  126. // 4. Let usingIterator be ? GetMethod(items, @@iterator).
  127. auto using_iterator = TRY(items.get_method(vm, vm.well_known_symbol_iterator()));
  128. // 5. If usingIterator is not undefined, then
  129. if (using_iterator) {
  130. GCPtr<Object> array;
  131. // a. If IsConstructor(C) is true, then
  132. if (constructor.is_constructor()) {
  133. // i. Let A be ? Construct(C).
  134. array = TRY(JS::construct(vm, constructor.as_function()));
  135. }
  136. // b. Else,
  137. else {
  138. // i. Let A be ! ArrayCreate(0).
  139. array = MUST(Array::create(realm, 0));
  140. }
  141. // c. Let iteratorRecord be ? GetIteratorFromMethod(items, usingIterator).
  142. auto iterator = TRY(get_iterator_from_method(vm, items, *using_iterator));
  143. // d. Let k be 0.
  144. // e. Repeat,
  145. for (size_t k = 0;; ++k) {
  146. // i. If k ≥ 2^53 - 1, then
  147. if (k >= MAX_ARRAY_LIKE_INDEX) {
  148. // 1. Let error be ThrowCompletion(a newly created TypeError object).
  149. auto error = vm.throw_completion<TypeError>(ErrorType::ArrayMaxSize);
  150. // 2. Return ? IteratorClose(iteratorRecord, error).
  151. return *TRY(iterator_close(vm, iterator, move(error)));
  152. }
  153. // ii. Let Pk be ! ToString(𝔽(k)).
  154. auto property_key = PropertyKey { k };
  155. // iii. Let next be ? IteratorStep(iteratorRecord).
  156. auto next = TRY(iterator_step(vm, iterator));
  157. // iv. If next is false, then
  158. if (!next) {
  159. // 1. Perform ? Set(A, "length", 𝔽(k), true).
  160. TRY(array->set(vm.names.length, Value(k), Object::ShouldThrowExceptions::Yes));
  161. // 2. Return A.
  162. return array;
  163. }
  164. // v. Let nextValue be ? IteratorValue(next).
  165. auto next_value = TRY(iterator_value(vm, *next));
  166. Value mapped_value;
  167. // vi. If mapping is true, then
  168. if (mapfn) {
  169. // 1. Let mappedValue be Completion(Call(mapfn, thisArg, « nextValue, 𝔽(k) »)).
  170. auto mapped_value_or_error = JS::call(vm, *mapfn, this_arg, next_value, Value(k));
  171. // 2. IfAbruptCloseIterator(mappedValue, iteratorRecord).
  172. if (mapped_value_or_error.is_error())
  173. return *TRY(iterator_close(vm, iterator, mapped_value_or_error.release_error()));
  174. mapped_value = mapped_value_or_error.release_value();
  175. }
  176. // vii. Else, let mappedValue be nextValue.
  177. else {
  178. mapped_value = next_value;
  179. }
  180. // viii. Let defineStatus be Completion(CreateDataPropertyOrThrow(A, Pk, mappedValue)).
  181. auto result_or_error = array->create_data_property_or_throw(property_key, mapped_value);
  182. // IfAbruptCloseIterator(defineStatus, iteratorRecord).
  183. if (result_or_error.is_error())
  184. return *TRY(iterator_close(vm, iterator, result_or_error.release_error()));
  185. // x. Set k to k + 1.
  186. }
  187. }
  188. // 6. NOTE: items is not an Iterable so assume it is an array-like object.
  189. // 7. Let arrayLike be ! ToObject(items).
  190. auto array_like = MUST(items.to_object(vm));
  191. // 8. Let len be ? LengthOfArrayLike(arrayLike).
  192. auto length = TRY(length_of_array_like(vm, array_like));
  193. GCPtr<Object> array;
  194. // 9. If IsConstructor(C) is true, then
  195. if (constructor.is_constructor()) {
  196. // a. Let A be ? Construct(C, « 𝔽(len) »).
  197. array = TRY(JS::construct(vm, constructor.as_function(), Value(length)));
  198. } else {
  199. // a. Let A be ? ArrayCreate(len).
  200. array = TRY(Array::create(realm, length));
  201. }
  202. // 11. Let k be 0.
  203. // 12. Repeat, while k < len,
  204. for (size_t k = 0; k < length; ++k) {
  205. // a. Let Pk be ! ToString(𝔽(k)).
  206. auto property_key = PropertyKey { k };
  207. // b. Let kValue be ? Get(arrayLike, Pk).
  208. auto k_value = TRY(array_like->get(property_key));
  209. Value mapped_value;
  210. // c. If mapping is true, then
  211. if (mapfn) {
  212. // i. Let mappedValue be ? Call(mapfn, thisArg, « kValue, 𝔽(k) »).
  213. mapped_value = TRY(JS::call(vm, *mapfn, this_arg, k_value, Value(k)));
  214. }
  215. // d. Else, let mappedValue be kValue.
  216. else {
  217. mapped_value = k_value;
  218. }
  219. // e. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
  220. TRY(array->create_data_property_or_throw(property_key, mapped_value));
  221. // f. Set k to k + 1.
  222. }
  223. // 13. Perform ? Set(A, "length", 𝔽(len), true).
  224. TRY(array->set(vm.names.length, Value(length), Object::ShouldThrowExceptions::Yes));
  225. // 14. Return A.
  226. return array;
  227. }
  228. // 2.1.1.1 Array.fromAsync ( asyncItems [ , mapfn [ , thisArg ] ] ), https://tc39.es/proposal-array-from-async/#sec-array.fromAsync
  229. JS_DEFINE_NATIVE_FUNCTION(ArrayConstructor::from_async)
  230. {
  231. auto& realm = *vm.current_realm();
  232. auto async_items = vm.argument(0);
  233. auto mapfn = vm.argument(1);
  234. auto this_arg = vm.argument(2);
  235. // 1. Let C be the this value.
  236. auto constructor = vm.this_value();
  237. // 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
  238. auto promise_capability = MUST(new_promise_capability(vm, realm.intrinsics().promise_constructor()));
  239. // 3. Let fromAsyncClosure be a new Abstract Closure with no parameters that captures C, mapfn, and thisArg and performs the following steps when called:
  240. SafeFunction<Completion()> from_async_closure = [constructor, mapfn, this_arg, &vm, &realm, async_items]() mutable -> Completion {
  241. bool mapping;
  242. // a. If mapfn is undefined, let mapping be false.
  243. if (mapfn.is_undefined()) {
  244. mapping = false;
  245. }
  246. // b. Else,
  247. else {
  248. // i. If IsCallable(mapfn) is false, throw a TypeError exception.
  249. if (!mapfn.is_function())
  250. return vm.throw_completion<TypeError>(ErrorType::NotAFunction, TRY_OR_THROW_OOM(vm, mapfn.to_string_without_side_effects()));
  251. // ii. Let mapping be true.
  252. mapping = true;
  253. }
  254. // c. Let usingAsyncIterator be ? GetMethod(asyncItems, @@asyncIterator).
  255. auto using_async_iterator = TRY(async_items.get_method(vm, vm.well_known_symbol_async_iterator()));
  256. GCPtr<FunctionObject> using_sync_iterator;
  257. // d. If usingAsyncIterator is undefined, then
  258. if (!using_async_iterator) {
  259. // i. Let usingSyncIterator be ? GetMethod(asyncItems, @@iterator).
  260. using_sync_iterator = TRY(async_items.get_method(vm, vm.well_known_symbol_iterator()));
  261. }
  262. GCPtr<Object> array;
  263. // e. If IsConstructor(C) is true, then
  264. if (constructor.is_constructor()) {
  265. // i. Let A be ? Construct(C).
  266. array = TRY(JS::construct(vm, constructor.as_function()));
  267. }
  268. // f. Else,
  269. else {
  270. // i. Let A be ! ArrayCreate(0).
  271. array = MUST(Array::create(realm, 0));
  272. }
  273. // g. Let iteratorRecord be undefined.
  274. Optional<IteratorRecord> iterator_record;
  275. // h. If usingAsyncIterator is not undefined, then
  276. if (using_async_iterator) {
  277. // i. Set iteratorRecord to ? GetIterator(asyncItems, async, usingAsyncIterator).
  278. // FIXME: The Array.from proposal is out of date - it should be using GetIteratorFromMethod.
  279. iterator_record = TRY(get_iterator_from_method(vm, async_items, *using_async_iterator));
  280. }
  281. // i. Else if usingSyncIterator is not undefined, then
  282. else if (using_sync_iterator) {
  283. // i. Set iteratorRecord to ? CreateAsyncFromSyncIterator(GetIterator(asyncItems, sync, usingSyncIterator)).
  284. // FIXME: The Array.from proposal is out of date - it should be using GetIteratorFromMethod.
  285. iterator_record = create_async_from_sync_iterator(vm, TRY(get_iterator_from_method(vm, async_items, *using_sync_iterator)));
  286. }
  287. // j. If iteratorRecord is not undefined, then
  288. if (iterator_record.has_value()) {
  289. // i. Let k be 0.
  290. // ii. Repeat,
  291. for (size_t k = 0;; ++k) {
  292. // 1. If k ≥ 2^53 - 1, then
  293. if (k >= MAX_ARRAY_LIKE_INDEX) {
  294. // a. Let error be ThrowCompletion(a newly created TypeError object).
  295. auto error = vm.throw_completion<TypeError>(ErrorType::ArrayMaxSize);
  296. // b. Return ? AsyncIteratorClose(iteratorRecord, error).
  297. return *TRY(async_iterator_close(vm, iterator_record.value(), move(error)));
  298. }
  299. // 2. Let Pk be ! ToString(𝔽(k)).
  300. auto property_key = PropertyKey { k };
  301. // FIXME: Spec bug: https://github.com/tc39/proposal-array-from-async/issues/33.
  302. // Implementing the following would cause an infinite loop.
  303. //
  304. // 3. Let next be ? Await(IteratorStep(iteratorRecord)).
  305. // 4. If next is false, then
  306. // a. Perform ? Set(A, "length", 𝔽(k), true).
  307. // b. Return Completion Record { [[Type]]: return, [[Value]]: A, [[Target]]: empty }.
  308. // 5. Let nextValue be ? IteratorValue(next).
  309. //
  310. // Below implements the suggested fix: https://github.com/tc39/proposal-array-from-async/issues/33#issuecomment-1279296963
  311. //
  312. // There also seems to be a second issue here where we are not respecting array mutation. After resolving the first entry, the
  313. // iterator should also take into account any other changes which are made to async_items (which does not seem to be happening).
  314. // Let nextResult be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]).
  315. auto next_result = TRY(JS::call(vm, iterator_record->next_method, iterator_record->iterator));
  316. // Set nextResult to ? Await(nextResult).
  317. next_result = TRY(await(vm, next_result));
  318. // If nextResult is not an Object, throw a TypeError exception.
  319. if (!next_result.is_object())
  320. return vm.throw_completion<TypeError>(ErrorType::IterableNextBadReturn);
  321. // Let done be ? IteratorComplete(nextResult).
  322. auto done = TRY(JS::iterator_complete(vm, next_result.as_object()));
  323. // If done is true,
  324. if (done) {
  325. // Perform ? Set(A, "length", 𝔽(k), true).
  326. TRY(array->set(vm.names.length, Value(k), Object::ShouldThrowExceptions::Yes));
  327. // Return Completion Record { [[Type]]: return, [[Value]]: A, [[Target]]: empty }.
  328. return Completion { Completion::Type::Return, array, {} };
  329. }
  330. // Let nextValue be ? IteratorValue(nextResult).
  331. auto next_value = TRY(iterator_value(vm, next_result.as_object()));
  332. // (spec deviation ends here)
  333. Value mapped_value;
  334. // 6. If mapping is true, then
  335. if (mapping) {
  336. // a. Let mappedValue be Call(mapfn, thisArg, « nextValue, 𝔽(k) »).
  337. auto mapped_value_or_error = JS::call(vm, mapfn, this_arg, next_value, Value(k));
  338. // b. IfAbruptCloseAsyncIterator(mappedValue, iteratorRecord).
  339. if (mapped_value_or_error.is_error()) {
  340. TRY(async_iterator_close(vm, iterator_record.value(), mapped_value_or_error));
  341. return mapped_value_or_error;
  342. }
  343. // c. Set mappedValue to Await(mappedValue).
  344. mapped_value_or_error = await(vm, mapped_value_or_error.value());
  345. // d. IfAbruptCloseAsyncIterator(mappedValue, iteratorRecord).
  346. if (mapped_value_or_error.is_error()) {
  347. TRY(async_iterator_close(vm, iterator_record.value(), mapped_value_or_error));
  348. return mapped_value_or_error;
  349. }
  350. mapped_value = mapped_value_or_error.value();
  351. }
  352. // 7. Else, let mappedValue be nextValue.
  353. else {
  354. mapped_value = next_value;
  355. }
  356. // 8. Let defineStatus be CreateDataPropertyOrThrow(A, Pk, mappedValue).
  357. auto define_status = array->create_data_property_or_throw(property_key, mapped_value);
  358. // 9. If defineStatus is an abrupt completion, return ? AsyncIteratorClose(iteratorRecord, defineStatus).
  359. if (define_status.is_error())
  360. return *TRY(iterator_close(vm, iterator_record.value(), define_status.release_error()));
  361. // 10. Set k to k + 1.
  362. }
  363. }
  364. // k. Else,
  365. else {
  366. // i. NOTE: asyncItems is neither an AsyncIterable nor an Iterable so assume it is an array-like object.
  367. // ii. Let arrayLike be ! ToObject(asyncItems).
  368. auto array_like = MUST(async_items.to_object(vm));
  369. // iii. Let len be ? LengthOfArrayLike(arrayLike).
  370. auto length = TRY(length_of_array_like(vm, array_like));
  371. // iv. If IsConstructor(C) is true, then
  372. if (constructor.is_constructor()) {
  373. // 1. Let A be ? Construct(C, « 𝔽(len) »).
  374. array = TRY(JS::construct(vm, constructor.as_function(), Value(length)));
  375. }
  376. // v. Else,
  377. else {
  378. // 1. Let A be ? ArrayCreate(len).
  379. array = TRY(Array::create(realm, length));
  380. }
  381. // vi. Let k be 0.
  382. // vii. Repeat, while k < len,
  383. for (size_t k = 0; k < length; ++k) {
  384. // 1. Let Pk be ! ToString(𝔽(k)).
  385. auto property_key = PropertyKey { k };
  386. // 2. Let kValue be ? Get(arrayLike, Pk).
  387. auto k_value = TRY(array_like->get(property_key));
  388. // 3. Set kValue to ? Await(kValue).
  389. k_value = TRY(await(vm, k_value));
  390. Value mapped_value;
  391. // 4. If mapping is true, then
  392. if (mapping) {
  393. // a. Let mappedValue be ? Call(mapfn, thisArg, « kValue, 𝔽(k) »).
  394. mapped_value = TRY(JS::call(vm, mapfn, this_arg, k_value, Value(k)));
  395. // b. Set mappedValue to ? Await(mappedValue).
  396. mapped_value = TRY(await(vm, mapped_value));
  397. }
  398. // 5. Else, let mappedValue be kValue.
  399. else {
  400. mapped_value = k_value;
  401. }
  402. // 6. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
  403. TRY(array->create_data_property_or_throw(property_key, mapped_value));
  404. // 7. Set k to k + 1.
  405. }
  406. // viii. Perform ? Set(A, "length", 𝔽(len), true).
  407. TRY(array->set(vm.names.length, Value(length), Object::ShouldThrowExceptions::Yes));
  408. // ix. Return Completion Record { [[Type]]: return, [[Value]]: A, [[Target]]: empty }.
  409. return Completion { Completion::Type::Return, array, {} };
  410. }
  411. };
  412. // 4. Perform AsyncFunctionStart(promiseCapability, fromAsyncClosure).
  413. async_function_start(vm, promise_capability, from_async_closure);
  414. // 5. Return promiseCapability.[[Promise]].
  415. return promise_capability->promise();
  416. }
  417. // 23.1.2.2 Array.isArray ( arg ), https://tc39.es/ecma262/#sec-array.isarray
  418. JS_DEFINE_NATIVE_FUNCTION(ArrayConstructor::is_array)
  419. {
  420. auto arg = vm.argument(0);
  421. // 1. Return ? IsArray(arg).
  422. return Value(TRY(arg.is_array(vm)));
  423. }
  424. // 23.1.2.3 Array.of ( ...items ), https://tc39.es/ecma262/#sec-array.of
  425. JS_DEFINE_NATIVE_FUNCTION(ArrayConstructor::of)
  426. {
  427. auto& realm = *vm.current_realm();
  428. // 1. Let len be the number of elements in items.
  429. auto len = vm.argument_count();
  430. // 2. Let lenNumber be 𝔽(len).
  431. auto len_number = Value(len);
  432. // 3. Let C be the this value.
  433. auto constructor = vm.this_value();
  434. GCPtr<Object> array;
  435. // 4. If IsConstructor(C) is true, then
  436. if (constructor.is_constructor()) {
  437. // a. Let A be ? Construct(C, « lenNumber »).
  438. array = TRY(JS::construct(vm, constructor.as_function(), Value(vm.argument_count())));
  439. } else {
  440. // a. Let A be ? ArrayCreate(len).
  441. array = TRY(Array::create(realm, len));
  442. }
  443. // 6. Let k be 0.
  444. // 7. Repeat, while k < len,
  445. for (size_t k = 0; k < len; ++k) {
  446. // a. Let kValue be items[k].
  447. auto k_value = vm.argument(k);
  448. // b. Let Pk be ! ToString(𝔽(k)).
  449. auto property_key = PropertyKey { k };
  450. // c. Perform ? CreateDataPropertyOrThrow(A, Pk, kValue).
  451. TRY(array->create_data_property_or_throw(property_key, k_value));
  452. // d. Set k to k + 1.
  453. }
  454. // 8. Perform ? Set(A, "length", lenNumber, true).
  455. TRY(array->set(vm.names.length, len_number, Object::ShouldThrowExceptions::Yes));
  456. // 9. Return A.
  457. return array;
  458. }
  459. // 23.1.2.5 get Array [ @@species ], https://tc39.es/ecma262/#sec-get-array-@@species
  460. JS_DEFINE_NATIVE_FUNCTION(ArrayConstructor::symbol_species_getter)
  461. {
  462. // 1. Return the this value.
  463. return vm.this_value();
  464. }
  465. }