ArrayPrototype.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  1. /*
  2. * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
  4. * Copyright (c) 2020, Marcin Gasperowicz <xnooga@gmail.com>
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright notice, this
  11. * list of conditions and the following disclaimer.
  12. *
  13. * 2. Redistributions in binary form must reproduce the above copyright notice,
  14. * this list of conditions and the following disclaimer in the documentation
  15. * and/or other materials provided with the distribution.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  18. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  23. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  24. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  25. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  26. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. #include <AK/Function.h>
  29. #include <AK/StringBuilder.h>
  30. #include <LibJS/Heap/Heap.h>
  31. #include <LibJS/Interpreter.h>
  32. #include <LibJS/Runtime/Array.h>
  33. #include <LibJS/Runtime/ArrayPrototype.h>
  34. #include <LibJS/Runtime/Error.h>
  35. #include <LibJS/Runtime/Function.h>
  36. #include <LibJS/Runtime/GlobalObject.h>
  37. #include <LibJS/Runtime/MarkedValueList.h>
  38. #include <LibJS/Runtime/ObjectPrototype.h>
  39. #include <LibJS/Runtime/Value.h>
  40. namespace JS {
  41. ArrayPrototype::ArrayPrototype(GlobalObject& global_object)
  42. : Object(global_object.object_prototype())
  43. {
  44. }
  45. void ArrayPrototype::initialize(Interpreter&, GlobalObject&)
  46. {
  47. u8 attr = Attribute::Writable | Attribute::Configurable;
  48. define_native_function("filter", filter, 1, attr);
  49. define_native_function("forEach", for_each, 1, attr);
  50. define_native_function("map", map, 1, attr);
  51. define_native_function("pop", pop, 0, attr);
  52. define_native_function("push", push, 1, attr);
  53. define_native_function("shift", shift, 0, attr);
  54. define_native_function("toString", to_string, 0, attr);
  55. define_native_function("toLocaleString", to_locale_string, 0, attr);
  56. define_native_function("unshift", unshift, 1, attr);
  57. define_native_function("join", join, 1, attr);
  58. define_native_function("concat", concat, 1, attr);
  59. define_native_function("slice", slice, 2, attr);
  60. define_native_function("indexOf", index_of, 1, attr);
  61. define_native_function("reduce", reduce, 1, attr);
  62. define_native_function("reduceRight", reduce_right, 1, attr);
  63. define_native_function("reverse", reverse, 0, attr);
  64. define_native_function("lastIndexOf", last_index_of, 1, attr);
  65. define_native_function("includes", includes, 1, attr);
  66. define_native_function("find", find, 1, attr);
  67. define_native_function("findIndex", find_index, 1, attr);
  68. define_native_function("some", some, 1, attr);
  69. define_native_function("every", every, 1, attr);
  70. define_native_function("splice", splice, 2, attr);
  71. define_native_function("fill", fill, 1, attr);
  72. define_property("length", Value(0), Attribute::Configurable);
  73. }
  74. ArrayPrototype::~ArrayPrototype()
  75. {
  76. }
  77. static Function* callback_from_args(Interpreter& interpreter, const String& name)
  78. {
  79. if (interpreter.argument_count() < 1) {
  80. interpreter.throw_exception<TypeError>(ErrorType::ArrayPrototypeOneArg, name.characters());
  81. return nullptr;
  82. }
  83. auto callback = interpreter.argument(0);
  84. if (!callback.is_function()) {
  85. interpreter.throw_exception<TypeError>(ErrorType::NotAFunction, callback.to_string_without_side_effects().characters());
  86. return nullptr;
  87. }
  88. return &callback.as_function();
  89. }
  90. static size_t get_length(Interpreter& interpreter, Object& object)
  91. {
  92. auto length_property = object.get("length");
  93. if (interpreter.exception())
  94. return 0;
  95. return length_property.to_size_t(interpreter);
  96. }
  97. static void for_each_item(Interpreter& interpreter, GlobalObject& global_object, const String& name, AK::Function<IterationDecision(size_t index, Value value, Value callback_result)> callback, bool skip_empty = true)
  98. {
  99. auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
  100. if (!this_object)
  101. return;
  102. auto initial_length = get_length(interpreter, *this_object);
  103. if (interpreter.exception())
  104. return;
  105. auto* callback_function = callback_from_args(interpreter, name);
  106. if (!callback_function)
  107. return;
  108. auto this_value = interpreter.argument(1);
  109. for (size_t i = 0; i < initial_length; ++i) {
  110. auto value = this_object->get(i);
  111. if (interpreter.exception())
  112. return;
  113. if (value.is_empty()) {
  114. if (skip_empty)
  115. continue;
  116. value = js_undefined();
  117. }
  118. MarkedValueList arguments(interpreter.heap());
  119. arguments.append(value);
  120. arguments.append(Value((i32)i));
  121. arguments.append(this_object);
  122. auto callback_result = interpreter.call(*callback_function, this_value, move(arguments));
  123. if (interpreter.exception())
  124. return;
  125. if (callback(i, value, callback_result) == IterationDecision::Break)
  126. break;
  127. }
  128. }
  129. JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::filter)
  130. {
  131. auto* new_array = Array::create(global_object);
  132. for_each_item(interpreter, global_object, "filter", [&](auto, auto value, auto callback_result) {
  133. if (callback_result.to_boolean())
  134. new_array->indexed_properties().append(value);
  135. return IterationDecision::Continue;
  136. });
  137. return Value(new_array);
  138. }
  139. JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::for_each)
  140. {
  141. for_each_item(interpreter, global_object, "forEach", [](auto, auto, auto) {
  142. return IterationDecision::Continue;
  143. });
  144. return js_undefined();
  145. }
  146. JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::map)
  147. {
  148. auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
  149. if (!this_object)
  150. return {};
  151. auto initial_length = get_length(interpreter, *this_object);
  152. if (interpreter.exception())
  153. return {};
  154. auto* new_array = Array::create(global_object);
  155. new_array->indexed_properties().set_array_like_size(initial_length);
  156. for_each_item(interpreter, global_object, "map", [&](auto index, auto, auto callback_result) {
  157. new_array->put(index, callback_result);
  158. if (interpreter.exception())
  159. return IterationDecision::Break;
  160. return IterationDecision::Continue;
  161. });
  162. return Value(new_array);
  163. }
  164. JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::push)
  165. {
  166. auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
  167. if (!this_object)
  168. return {};
  169. if (this_object->is_array()) {
  170. auto* array = static_cast<Array*>(this_object);
  171. for (size_t i = 0; i < interpreter.argument_count(); ++i)
  172. array->indexed_properties().append(interpreter.argument(i));
  173. return Value(static_cast<i32>(array->indexed_properties().array_like_size()));
  174. }
  175. auto length = get_length(interpreter, *this_object);
  176. if (interpreter.exception())
  177. return {};
  178. auto argument_count = interpreter.argument_count();
  179. auto new_length = length + argument_count;
  180. if (new_length > MAX_ARRAY_LIKE_INDEX)
  181. return interpreter.throw_exception<TypeError>(ErrorType::ArrayMaxSize);
  182. for (size_t i = 0; i < argument_count; ++i) {
  183. this_object->put(length + i, interpreter.argument(i));
  184. if (interpreter.exception())
  185. return {};
  186. }
  187. auto new_length_value = Value((i32)new_length);
  188. this_object->put("length", new_length_value);
  189. if (interpreter.exception())
  190. return {};
  191. return new_length_value;
  192. }
  193. JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::unshift)
  194. {
  195. auto* array = Array::typed_this(interpreter, global_object);
  196. if (!array)
  197. return {};
  198. for (size_t i = 0; i < interpreter.argument_count(); ++i)
  199. array->indexed_properties().insert(i, interpreter.argument(i));
  200. return Value(static_cast<i32>(array->indexed_properties().array_like_size()));
  201. }
  202. JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::pop)
  203. {
  204. auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
  205. if (!this_object)
  206. return {};
  207. if (this_object->is_array()) {
  208. auto* array = static_cast<Array*>(this_object);
  209. if (array->indexed_properties().is_empty())
  210. return js_undefined();
  211. return array->indexed_properties().take_last(array).value.value_or(js_undefined());
  212. }
  213. auto length = get_length(interpreter, *this_object);
  214. if (length == 0) {
  215. this_object->put("length", Value(0));
  216. return js_undefined();
  217. }
  218. auto index = length - 1;
  219. auto element = this_object->get(index).value_or(js_undefined());
  220. if (interpreter.exception())
  221. return {};
  222. this_object->delete_property(index);
  223. if (interpreter.exception())
  224. return {};
  225. this_object->put("length", Value((i32)index));
  226. if (interpreter.exception())
  227. return {};
  228. return element;
  229. }
  230. JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::shift)
  231. {
  232. auto* array = Array::typed_this(interpreter, global_object);
  233. if (!array)
  234. return {};
  235. if (array->indexed_properties().is_empty())
  236. return js_undefined();
  237. auto result = array->indexed_properties().take_first(array);
  238. if (interpreter.exception())
  239. return {};
  240. return result.value.value_or(js_undefined());
  241. }
  242. JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::to_string)
  243. {
  244. auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
  245. if (!this_object)
  246. return {};
  247. auto join_function = this_object->get("join");
  248. if (interpreter.exception())
  249. return {};
  250. if (!join_function.is_function())
  251. return ObjectPrototype::to_string(interpreter, global_object);
  252. return interpreter.call(join_function.as_function(), this_object);
  253. }
  254. JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::to_locale_string)
  255. {
  256. auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
  257. if (!this_object)
  258. return {};
  259. String separator = ","; // NOTE: This is implementation-specific.
  260. auto length = get_length(interpreter, *this_object);
  261. if (interpreter.exception())
  262. return {};
  263. StringBuilder builder;
  264. for (size_t i = 0; i < length; ++i) {
  265. if (i > 0)
  266. builder.append(separator);
  267. auto value = this_object->get(i).value_or(js_undefined());
  268. if (interpreter.exception())
  269. return {};
  270. if (value.is_undefined() || value.is_null())
  271. continue;
  272. auto* value_object = value.to_object(interpreter, global_object);
  273. ASSERT(value_object);
  274. auto locale_string_result = value_object->invoke("toLocaleString");
  275. if (interpreter.exception())
  276. return {};
  277. auto string = locale_string_result.to_string(interpreter);
  278. if (interpreter.exception())
  279. return {};
  280. builder.append(string);
  281. }
  282. return js_string(interpreter, builder.to_string());
  283. }
  284. JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::join)
  285. {
  286. auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
  287. if (!this_object)
  288. return {};
  289. String separator = ",";
  290. if (interpreter.argument_count()) {
  291. separator = interpreter.argument(0).to_string(interpreter);
  292. if (interpreter.exception())
  293. return {};
  294. }
  295. auto length = get_length(interpreter, *this_object);
  296. if (interpreter.exception())
  297. return {};
  298. StringBuilder builder;
  299. for (size_t i = 0; i < length; ++i) {
  300. if (i > 0)
  301. builder.append(separator);
  302. auto value = this_object->get(i).value_or(js_undefined());
  303. if (interpreter.exception())
  304. return {};
  305. if (value.is_undefined() || value.is_null())
  306. continue;
  307. auto string = value.to_string(interpreter);
  308. if (interpreter.exception())
  309. return {};
  310. builder.append(string);
  311. }
  312. return js_string(interpreter, builder.to_string());
  313. }
  314. JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::concat)
  315. {
  316. auto* array = Array::typed_this(interpreter, global_object);
  317. if (!array)
  318. return {};
  319. auto* new_array = Array::create(global_object);
  320. new_array->indexed_properties().append_all(array, array->indexed_properties());
  321. if (interpreter.exception())
  322. return {};
  323. for (size_t i = 0; i < interpreter.argument_count(); ++i) {
  324. auto argument = interpreter.argument(i);
  325. if (argument.is_array()) {
  326. auto& argument_object = argument.as_object();
  327. new_array->indexed_properties().append_all(&argument_object, argument_object.indexed_properties());
  328. if (interpreter.exception())
  329. return {};
  330. } else {
  331. new_array->indexed_properties().append(argument);
  332. }
  333. }
  334. return Value(new_array);
  335. }
  336. JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::slice)
  337. {
  338. auto* array = Array::typed_this(interpreter, global_object);
  339. if (!array)
  340. return {};
  341. auto* new_array = Array::create(global_object);
  342. if (interpreter.argument_count() == 0) {
  343. new_array->indexed_properties().append_all(array, array->indexed_properties());
  344. if (interpreter.exception())
  345. return {};
  346. return new_array;
  347. }
  348. ssize_t array_size = static_cast<ssize_t>(array->indexed_properties().array_like_size());
  349. auto start_slice = interpreter.argument(0).to_i32(interpreter);
  350. if (interpreter.exception())
  351. return {};
  352. auto end_slice = array_size;
  353. if (start_slice > array_size)
  354. return new_array;
  355. if (start_slice < 0)
  356. start_slice = end_slice + start_slice;
  357. if (interpreter.argument_count() >= 2) {
  358. end_slice = interpreter.argument(1).to_i32(interpreter);
  359. if (interpreter.exception())
  360. return {};
  361. if (end_slice < 0)
  362. end_slice = array_size + end_slice;
  363. else if (end_slice > array_size)
  364. end_slice = array_size;
  365. }
  366. for (ssize_t i = start_slice; i < end_slice; ++i) {
  367. new_array->indexed_properties().append(array->get(i));
  368. if (interpreter.exception())
  369. return {};
  370. }
  371. return new_array;
  372. }
  373. JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::index_of)
  374. {
  375. auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
  376. if (!this_object)
  377. return {};
  378. i32 length = get_length(interpreter, *this_object);
  379. if (interpreter.exception())
  380. return {};
  381. if (length == 0)
  382. return Value(-1);
  383. i32 from_index = 0;
  384. if (interpreter.argument_count() >= 2) {
  385. from_index = interpreter.argument(1).to_i32(interpreter);
  386. if (interpreter.exception())
  387. return {};
  388. if (from_index >= length)
  389. return Value(-1);
  390. if (from_index < 0)
  391. from_index = max(length + from_index, 0);
  392. }
  393. auto search_element = interpreter.argument(0);
  394. for (i32 i = from_index; i < length; ++i) {
  395. auto element = this_object->get(i);
  396. if (interpreter.exception())
  397. return {};
  398. if (strict_eq(interpreter, element, search_element))
  399. return Value(i);
  400. }
  401. return Value(-1);
  402. }
  403. JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::reduce)
  404. {
  405. auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
  406. if (!this_object)
  407. return {};
  408. auto initial_length = get_length(interpreter, *this_object);
  409. if (interpreter.exception())
  410. return {};
  411. auto* callback_function = callback_from_args(interpreter, "reduce");
  412. if (!callback_function)
  413. return {};
  414. size_t start = 0;
  415. auto accumulator = js_undefined();
  416. if (interpreter.argument_count() > 1) {
  417. accumulator = interpreter.argument(1);
  418. } else {
  419. bool start_found = false;
  420. while (!start_found && start < initial_length) {
  421. auto value = this_object->get(start);
  422. if (interpreter.exception())
  423. return {};
  424. start_found = !value.is_empty();
  425. if (start_found)
  426. accumulator = value;
  427. start += 1;
  428. }
  429. if (!start_found) {
  430. interpreter.throw_exception<TypeError>(ErrorType::ReduceNoInitial);
  431. return {};
  432. }
  433. }
  434. auto this_value = js_undefined();
  435. for (size_t i = start; i < initial_length; ++i) {
  436. auto value = this_object->get(i);
  437. if (interpreter.exception())
  438. return {};
  439. if (value.is_empty())
  440. continue;
  441. MarkedValueList arguments(interpreter.heap());
  442. arguments.append(accumulator);
  443. arguments.append(value);
  444. arguments.append(Value((i32)i));
  445. arguments.append(this_object);
  446. accumulator = interpreter.call(*callback_function, this_value, move(arguments));
  447. if (interpreter.exception())
  448. return {};
  449. }
  450. return accumulator;
  451. }
  452. JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::reduce_right)
  453. {
  454. auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
  455. if (!this_object)
  456. return {};
  457. auto initial_length = get_length(interpreter, *this_object);
  458. if (interpreter.exception())
  459. return {};
  460. auto* callback_function = callback_from_args(interpreter, "reduceRight");
  461. if (!callback_function)
  462. return {};
  463. int start = initial_length - 1;
  464. auto accumulator = js_undefined();
  465. if (interpreter.argument_count() > 1) {
  466. accumulator = interpreter.argument(1);
  467. } else {
  468. bool start_found = false;
  469. while (!start_found && start >= 0) {
  470. auto value = this_object->get(start);
  471. if (interpreter.exception())
  472. return {};
  473. start_found = !value.is_empty();
  474. if (start_found)
  475. accumulator = value;
  476. start -= 1;
  477. }
  478. if (!start_found) {
  479. interpreter.throw_exception<TypeError>(ErrorType::ReduceNoInitial);
  480. return {};
  481. }
  482. }
  483. auto this_value = js_undefined();
  484. for (int i = start; i >= 0; --i) {
  485. auto value = this_object->get(i);
  486. if (interpreter.exception())
  487. return {};
  488. if (value.is_empty())
  489. continue;
  490. MarkedValueList arguments(interpreter.heap());
  491. arguments.append(accumulator);
  492. arguments.append(value);
  493. arguments.append(Value(i));
  494. arguments.append(this_object);
  495. accumulator = interpreter.call(*callback_function, this_value, move(arguments));
  496. if (interpreter.exception())
  497. return {};
  498. }
  499. return accumulator;
  500. }
  501. JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::reverse)
  502. {
  503. auto* array = Array::typed_this(interpreter, global_object);
  504. if (!array)
  505. return {};
  506. if (array->indexed_properties().is_empty())
  507. return array;
  508. Vector<Value> array_reverse;
  509. auto size = array->indexed_properties().array_like_size();
  510. array_reverse.ensure_capacity(size);
  511. for (ssize_t i = size - 1; i >= 0; --i) {
  512. array_reverse.append(array->get(i));
  513. if (interpreter.exception())
  514. return {};
  515. }
  516. array->set_indexed_property_elements(move(array_reverse));
  517. return array;
  518. }
  519. JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::last_index_of)
  520. {
  521. auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
  522. if (!this_object)
  523. return {};
  524. i32 length = get_length(interpreter, *this_object);
  525. if (interpreter.exception())
  526. return {};
  527. if (length == 0)
  528. return Value(-1);
  529. i32 from_index = length - 1;
  530. if (interpreter.argument_count() >= 2) {
  531. from_index = interpreter.argument(1).to_i32(interpreter);
  532. if (interpreter.exception())
  533. return {};
  534. if (from_index >= 0)
  535. from_index = min(from_index, length - 1);
  536. else
  537. from_index = length + from_index;
  538. }
  539. auto search_element = interpreter.argument(0);
  540. for (i32 i = from_index; i >= 0; --i) {
  541. auto element = this_object->get(i);
  542. if (interpreter.exception())
  543. return {};
  544. if (strict_eq(interpreter, element, search_element))
  545. return Value(i);
  546. }
  547. return Value(-1);
  548. }
  549. JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::includes)
  550. {
  551. auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
  552. if (!this_object)
  553. return {};
  554. i32 length = get_length(interpreter, *this_object);
  555. if (interpreter.exception())
  556. return {};
  557. if (length == 0)
  558. return Value(false);
  559. i32 from_index = 0;
  560. if (interpreter.argument_count() >= 2) {
  561. from_index = interpreter.argument(1).to_i32(interpreter);
  562. if (interpreter.exception())
  563. return {};
  564. if (from_index >= length)
  565. return Value(false);
  566. if (from_index < 0)
  567. from_index = max(length + from_index, 0);
  568. }
  569. auto value_to_find = interpreter.argument(0);
  570. for (i32 i = from_index; i < length; ++i) {
  571. auto element = this_object->get(i).value_or(js_undefined());
  572. if (interpreter.exception())
  573. return {};
  574. if (same_value_zero(interpreter, element, value_to_find))
  575. return Value(true);
  576. }
  577. return Value(false);
  578. }
  579. JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::find)
  580. {
  581. auto result = js_undefined();
  582. for_each_item(
  583. interpreter, global_object, "find", [&](auto, auto value, auto callback_result) {
  584. if (callback_result.to_boolean()) {
  585. result = value;
  586. return IterationDecision::Break;
  587. }
  588. return IterationDecision::Continue;
  589. },
  590. false);
  591. return result;
  592. }
  593. JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::find_index)
  594. {
  595. auto result_index = -1;
  596. for_each_item(
  597. interpreter, global_object, "findIndex", [&](auto index, auto, auto callback_result) {
  598. if (callback_result.to_boolean()) {
  599. result_index = index;
  600. return IterationDecision::Break;
  601. }
  602. return IterationDecision::Continue;
  603. },
  604. false);
  605. return Value(result_index);
  606. }
  607. JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::some)
  608. {
  609. auto result = false;
  610. for_each_item(interpreter, global_object, "some", [&](auto, auto, auto callback_result) {
  611. if (callback_result.to_boolean()) {
  612. result = true;
  613. return IterationDecision::Break;
  614. }
  615. return IterationDecision::Continue;
  616. });
  617. return Value(result);
  618. }
  619. JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::every)
  620. {
  621. auto result = true;
  622. for_each_item(interpreter, global_object, "every", [&](auto, auto, auto callback_result) {
  623. if (!callback_result.to_boolean()) {
  624. result = false;
  625. return IterationDecision::Break;
  626. }
  627. return IterationDecision::Continue;
  628. });
  629. return Value(result);
  630. }
  631. JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::splice)
  632. {
  633. auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
  634. if (!this_object)
  635. return {};
  636. auto initial_length = get_length(interpreter, *this_object);
  637. if (interpreter.exception())
  638. return {};
  639. auto relative_start = interpreter.argument(0).to_i32(interpreter);
  640. if (interpreter.exception())
  641. return {};
  642. size_t actual_start;
  643. if (relative_start < 0)
  644. actual_start = max((ssize_t)initial_length + relative_start, (ssize_t)0);
  645. else
  646. actual_start = min((size_t)relative_start, initial_length);
  647. size_t insert_count = 0;
  648. size_t actual_delete_count = 0;
  649. if (interpreter.argument_count() == 1) {
  650. actual_delete_count = initial_length - actual_start;
  651. } else if (interpreter.argument_count() >= 2) {
  652. insert_count = interpreter.argument_count() - 2;
  653. i32 delete_count = interpreter.argument(1).to_i32(interpreter);
  654. if (interpreter.exception())
  655. return {};
  656. actual_delete_count = min((size_t)max(delete_count, 0), initial_length - actual_start);
  657. }
  658. size_t new_length = initial_length + insert_count - actual_delete_count;
  659. if (new_length > MAX_ARRAY_LIKE_INDEX)
  660. return interpreter.throw_exception<TypeError>(ErrorType::ArrayMaxSize);
  661. auto removed_elements = Array::create(global_object);
  662. for (size_t i = 0; i < actual_delete_count; ++i) {
  663. auto value = this_object->get(actual_start + i);
  664. if (interpreter.exception())
  665. return {};
  666. removed_elements->indexed_properties().append(value);
  667. }
  668. if (insert_count < actual_delete_count) {
  669. for (size_t i = actual_start; i < initial_length - actual_delete_count; ++i) {
  670. auto from = this_object->get(i + actual_delete_count);
  671. if (interpreter.exception())
  672. return {};
  673. auto to = i + insert_count;
  674. if (!from.is_empty()) {
  675. this_object->put(to, from);
  676. } else {
  677. this_object->delete_property(to);
  678. }
  679. if (interpreter.exception())
  680. return {};
  681. }
  682. for (size_t i = initial_length; i > new_length; --i) {
  683. this_object->delete_property(i - 1);
  684. if (interpreter.exception())
  685. return {};
  686. }
  687. } else if (insert_count > actual_delete_count) {
  688. for (size_t i = initial_length - actual_delete_count; i > actual_start; --i) {
  689. auto from = this_object->get(i + actual_delete_count - 1);
  690. if (interpreter.exception())
  691. return {};
  692. auto to = i + insert_count - 1;
  693. if (!from.is_empty()) {
  694. this_object->put(to, from);
  695. } else {
  696. this_object->delete_property(to);
  697. }
  698. if (interpreter.exception())
  699. return {};
  700. }
  701. }
  702. for (size_t i = 0; i < insert_count; ++i) {
  703. this_object->put(actual_start + i, interpreter.argument(i + 2));
  704. if (interpreter.exception())
  705. return {};
  706. }
  707. this_object->put("length", Value((i32)new_length));
  708. if (interpreter.exception())
  709. return {};
  710. return removed_elements;
  711. }
  712. JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::fill)
  713. {
  714. auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);
  715. if (!this_object)
  716. return {};
  717. ssize_t length = get_length(interpreter, *this_object);
  718. if (interpreter.exception())
  719. return {};
  720. ssize_t relative_start = 0;
  721. ssize_t relative_end = length;
  722. if (interpreter.argument_count() >= 2) {
  723. relative_start = interpreter.argument(1).to_i32(interpreter);
  724. if (interpreter.exception())
  725. return {};
  726. }
  727. if (interpreter.argument_count() >= 3) {
  728. relative_end = interpreter.argument(2).to_i32(interpreter);
  729. if (interpreter.exception())
  730. return {};
  731. }
  732. size_t from, to;
  733. if (relative_start < 0)
  734. from = max(length + relative_start, 0L);
  735. else
  736. from = min(relative_start, length);
  737. if (relative_end < 0)
  738. to = max(length + relative_end, 0L);
  739. else
  740. to = min(relative_end, length);
  741. for (size_t i = from; i < to; i++) {
  742. this_object->put(i, interpreter.argument(0));
  743. if (interpreter.exception())
  744. return {};
  745. }
  746. return this_object;
  747. }
  748. }