@ugo-studio/jspp 0.2.9 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/LICENSE +25 -25
  2. package/README.md +20 -12
  3. package/dist/analysis/scope.js +5 -3
  4. package/dist/analysis/typeAnalyzer.js +21 -25
  5. package/dist/cli/index.js +14 -4
  6. package/dist/cli/utils.js +61 -0
  7. package/dist/core/codegen/class-handlers.js +6 -6
  8. package/dist/core/codegen/control-flow-handlers.js +10 -9
  9. package/dist/core/codegen/declaration-handlers.js +10 -3
  10. package/dist/core/codegen/destructuring-handlers.js +9 -4
  11. package/dist/core/codegen/expression-handlers.js +40 -29
  12. package/dist/core/codegen/function-handlers.js +78 -12
  13. package/dist/core/codegen/helpers.js +91 -14
  14. package/dist/core/codegen/index.js +4 -2
  15. package/dist/core/codegen/statement-handlers.js +9 -7
  16. package/package.json +2 -2
  17. package/scripts/precompile-headers.ts +249 -50
  18. package/scripts/setup-compiler.ts +63 -63
  19. package/src/prelude/any_value.cpp +636 -0
  20. package/src/prelude/any_value.hpp +369 -362
  21. package/src/prelude/{exception_helpers.hpp → exception.cpp} +53 -53
  22. package/src/prelude/exception.hpp +27 -27
  23. package/src/prelude/iterator_instantiations.hpp +10 -0
  24. package/src/prelude/{index.hpp → jspp.hpp} +10 -16
  25. package/src/prelude/library/array.cpp +191 -0
  26. package/src/prelude/library/array.hpp +13 -186
  27. package/src/prelude/library/console.cpp +125 -0
  28. package/src/prelude/library/console.hpp +24 -112
  29. package/src/prelude/library/error.cpp +100 -0
  30. package/src/prelude/library/error.hpp +13 -113
  31. package/src/prelude/library/function.cpp +69 -0
  32. package/src/prelude/library/function.hpp +11 -10
  33. package/src/prelude/library/global.cpp +96 -0
  34. package/src/prelude/library/global.hpp +12 -28
  35. package/src/prelude/library/global_usings.hpp +15 -0
  36. package/src/prelude/library/math.cpp +258 -0
  37. package/src/prelude/library/math.hpp +26 -308
  38. package/src/prelude/library/object.cpp +379 -0
  39. package/src/prelude/library/object.hpp +14 -276
  40. package/src/prelude/library/performance.cpp +21 -0
  41. package/src/prelude/library/performance.hpp +5 -20
  42. package/src/prelude/library/process.cpp +38 -0
  43. package/src/prelude/library/process.hpp +11 -39
  44. package/src/prelude/library/promise.cpp +131 -0
  45. package/src/prelude/library/promise.hpp +12 -123
  46. package/src/prelude/library/symbol.cpp +56 -0
  47. package/src/prelude/library/symbol.hpp +11 -52
  48. package/src/prelude/library/timer.cpp +88 -0
  49. package/src/prelude/library/timer.hpp +16 -92
  50. package/src/prelude/runtime.cpp +19 -0
  51. package/src/prelude/types.hpp +184 -179
  52. package/src/prelude/utils/access.hpp +502 -411
  53. package/src/prelude/utils/assignment_operators.hpp +99 -99
  54. package/src/prelude/utils/log_any_value/array.hpp +61 -40
  55. package/src/prelude/utils/log_any_value/function.hpp +39 -39
  56. package/src/prelude/utils/log_any_value/object.hpp +60 -3
  57. package/src/prelude/utils/operators.hpp +351 -336
  58. package/src/prelude/utils/operators_primitive.hpp +336 -336
  59. package/src/prelude/utils/well_known_symbols.hpp +24 -24
  60. package/src/prelude/values/array.cpp +1399 -0
  61. package/src/prelude/values/array.hpp +4 -1
  62. package/src/prelude/values/async_iterator.cpp +251 -0
  63. package/src/prelude/values/async_iterator.hpp +111 -83
  64. package/src/prelude/values/function.cpp +262 -0
  65. package/src/prelude/values/function.hpp +62 -82
  66. package/src/prelude/values/iterator.cpp +309 -0
  67. package/src/prelude/values/iterator.hpp +33 -64
  68. package/src/prelude/values/number.cpp +176 -0
  69. package/src/prelude/values/object.cpp +159 -0
  70. package/src/prelude/values/object.hpp +4 -0
  71. package/src/prelude/values/promise.cpp +479 -0
  72. package/src/prelude/values/promise.hpp +79 -72
  73. package/src/prelude/values/prototypes/array.hpp +46 -1336
  74. package/src/prelude/values/prototypes/async_iterator.hpp +19 -61
  75. package/src/prelude/values/prototypes/function.hpp +7 -46
  76. package/src/prelude/values/prototypes/iterator.hpp +25 -201
  77. package/src/prelude/values/prototypes/number.hpp +23 -210
  78. package/src/prelude/values/prototypes/object.hpp +7 -23
  79. package/src/prelude/values/prototypes/promise.hpp +18 -196
  80. package/src/prelude/values/prototypes/string.hpp +39 -542
  81. package/src/prelude/values/prototypes/symbol.hpp +9 -70
  82. package/src/prelude/values/shape.hpp +52 -52
  83. package/src/prelude/values/string.cpp +485 -0
  84. package/src/prelude/values/string.hpp +25 -26
  85. package/src/prelude/values/symbol.cpp +89 -0
  86. package/src/prelude/values/symbol.hpp +101 -101
  87. package/src/prelude/any_value_access.hpp +0 -170
  88. package/src/prelude/any_value_defines.hpp +0 -190
  89. package/src/prelude/any_value_helpers.hpp +0 -374
  90. package/src/prelude/values/helpers/array.hpp +0 -209
  91. package/src/prelude/values/helpers/async_iterator.hpp +0 -275
  92. package/src/prelude/values/helpers/function.hpp +0 -109
  93. package/src/prelude/values/helpers/iterator.hpp +0 -145
  94. package/src/prelude/values/helpers/object.hpp +0 -104
  95. package/src/prelude/values/helpers/promise.hpp +0 -254
  96. package/src/prelude/values/helpers/string.hpp +0 -61
  97. package/src/prelude/values/helpers/symbol.hpp +0 -21
@@ -0,0 +1,1399 @@
1
+ #include "jspp.hpp"
2
+ #include "values/array.hpp"
3
+ #include "values/prototypes/array.hpp"
4
+
5
+ namespace jspp {
6
+
7
+ // --- JsArray Implementation ---
8
+
9
+ JsArray::JsArray() : proto(Constants::Null), length(0) {}
10
+ JsArray::JsArray(const std::vector<jspp::AnyValue> &items) : dense(items), proto(Constants::Null), length(items.size()) {}
11
+ JsArray::JsArray(std::vector<jspp::AnyValue> &&items) : dense(std::move(items)), proto(Constants::Null), length(dense.size()) {}
12
+
13
+ std::string JsArray::to_std_string() const
14
+ {
15
+ if (length == 0)
16
+ {
17
+ return "";
18
+ }
19
+
20
+ std::string result = "";
21
+ for (uint64_t i = 0; i < length; ++i)
22
+ {
23
+ AnyValue itemVal = Constants::UNINITIALIZED;
24
+ if (i < dense.size())
25
+ {
26
+ itemVal = dense[i];
27
+ }
28
+ else
29
+ {
30
+ auto it = sparse.find(static_cast<uint32_t>(i));
31
+ if (it != sparse.end())
32
+ {
33
+ itemVal = it->second;
34
+ }
35
+ }
36
+
37
+ if (!itemVal.is_uninitialized())
38
+ {
39
+ if (!itemVal.is_undefined() && !itemVal.is_null())
40
+ {
41
+ result += itemVal.to_std_string();
42
+ }
43
+ }
44
+
45
+ if (i < length - 1)
46
+ {
47
+ result += ",";
48
+ }
49
+ }
50
+ return result;
51
+ }
52
+
53
+ bool JsArray::has_property(const std::string &key) const
54
+ {
55
+ if (key == "length")
56
+ return true;
57
+ if (is_array_index(key))
58
+ {
59
+ uint32_t idx = static_cast<uint32_t>(std::stoull(key));
60
+ if (idx < dense.size())
61
+ return !dense[idx].is_uninitialized();
62
+ if (sparse.find(idx) != sparse.end())
63
+ return !sparse.at(idx).is_uninitialized();
64
+ }
65
+ if (props.find(key) != props.end())
66
+ return true;
67
+
68
+ if (!proto.is_null() && !proto.is_undefined())
69
+ {
70
+ if (proto.has_property(key))
71
+ return true;
72
+ }
73
+
74
+ if (ArrayPrototypes::get(key).has_value())
75
+ return true;
76
+ return false;
77
+ }
78
+
79
+ bool JsArray::has_symbol_property(const AnyValue &key) const
80
+ {
81
+ if (symbol_props.count(key))
82
+ return true;
83
+ if (!proto.is_null() && !proto.is_undefined())
84
+ {
85
+ if (proto.has_property(key))
86
+ return true;
87
+ }
88
+ if (ArrayPrototypes::get(key).has_value())
89
+ return true;
90
+ return false;
91
+ }
92
+
93
+ jspp::AnyValue JsArray::get_property(const std::string &key, const AnyValue &thisVal)
94
+ {
95
+ if (!key.empty() && std::isdigit(static_cast<unsigned char>(key[0])) && is_array_index(key))
96
+ {
97
+ uint32_t idx = static_cast<uint32_t>(std::stoull(key));
98
+ return get_property(idx);
99
+ }
100
+ else
101
+ {
102
+ auto it = props.find(key);
103
+ if (it == props.end())
104
+ {
105
+ if (key == "length")
106
+ {
107
+ auto proto_it = ArrayPrototypes::get(key);
108
+ if (proto_it.has_value())
109
+ {
110
+ return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key);
111
+ }
112
+ }
113
+
114
+ if (!proto.is_null() && !proto.is_undefined())
115
+ {
116
+ if (proto.has_property(key))
117
+ {
118
+ return proto.get_property_with_receiver(key, thisVal);
119
+ }
120
+ }
121
+
122
+ auto proto_it = ArrayPrototypes::get(key);
123
+ if (proto_it.has_value())
124
+ {
125
+ return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key);
126
+ }
127
+ return Constants::UNDEFINED;
128
+ }
129
+ return AnyValue::resolve_property_for_read(it->second, thisVal, key);
130
+ }
131
+ }
132
+
133
+ jspp::AnyValue JsArray::get_symbol_property(const AnyValue &key, const AnyValue &thisVal)
134
+ {
135
+ auto it = symbol_props.find(key);
136
+ if (it == symbol_props.end())
137
+ {
138
+ if (!proto.is_null() && !proto.is_undefined())
139
+ {
140
+ auto res = proto.get_symbol_property_with_receiver(key, thisVal);
141
+ if (!res.is_undefined())
142
+ return res;
143
+ }
144
+
145
+ auto proto_it = ArrayPrototypes::get(key);
146
+ if (proto_it.has_value())
147
+ {
148
+ return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key.to_std_string());
149
+ }
150
+ return Constants::UNDEFINED;
151
+ }
152
+ return AnyValue::resolve_property_for_read(it->second, thisVal, key.to_std_string());
153
+ }
154
+
155
+ jspp::AnyValue JsArray::get_property(uint32_t idx)
156
+ {
157
+ if (idx < dense.size())
158
+ {
159
+ const auto &val = dense[idx];
160
+ return val.is_uninitialized() ? Constants::UNDEFINED : val;
161
+ }
162
+ const auto &it = sparse.find(idx);
163
+ if (it != sparse.end())
164
+ {
165
+ const auto &val = it->second;
166
+ return val.is_uninitialized() ? Constants::UNDEFINED : val;
167
+ }
168
+ return Constants::UNDEFINED;
169
+ }
170
+
171
+ jspp::AnyValue JsArray::set_property(const std::string &key, const AnyValue &value, const AnyValue &thisVal)
172
+ {
173
+ if (!key.empty() && std::isdigit(static_cast<unsigned char>(key[0])) && is_array_index(key))
174
+ {
175
+ uint32_t idx = static_cast<uint32_t>(std::stoull(key));
176
+ return set_property(idx, value);
177
+ }
178
+ else
179
+ {
180
+ auto proto_val_opt = ArrayPrototypes::get(key);
181
+
182
+ if (proto_val_opt.has_value())
183
+ {
184
+ auto proto_value = proto_val_opt.value();
185
+ if (proto_value.is_accessor_descriptor())
186
+ {
187
+ return AnyValue::resolve_property_for_write(proto_value, thisVal, value, key);
188
+ }
189
+ if (proto_value.is_data_descriptor() && !proto_value.as_data_descriptor()->writable)
190
+ {
191
+ return AnyValue::resolve_property_for_write(proto_value, thisVal, value, key);
192
+ }
193
+ }
194
+
195
+ auto it = props.find(key);
196
+ if (it != props.end())
197
+ {
198
+ return AnyValue::resolve_property_for_write(it->second, thisVal, value, key);
199
+ }
200
+ else
201
+ {
202
+ props[key] = value;
203
+ return value;
204
+ }
205
+ }
206
+ }
207
+
208
+ jspp::AnyValue JsArray::set_symbol_property(const AnyValue &key, const AnyValue &value, const AnyValue &thisVal)
209
+ {
210
+ auto it = symbol_props.find(key);
211
+ if (it != symbol_props.end())
212
+ {
213
+ return AnyValue::resolve_property_for_write(it->second, thisVal, value, key.to_std_string());
214
+ }
215
+ else
216
+ {
217
+ symbol_props[key] = value;
218
+ return value;
219
+ }
220
+ }
221
+
222
+ jspp::AnyValue JsArray::set_property(uint32_t idx, const AnyValue &value)
223
+ {
224
+ uint64_t newLen = static_cast<uint64_t>(idx) + 1;
225
+ if (newLen > length)
226
+ length = newLen;
227
+
228
+ const uint32_t DENSE_GROW_THRESHOLD = 1024;
229
+ if (idx < dense.size())
230
+ {
231
+ dense[idx] = value;
232
+ return value;
233
+ }
234
+ else if (idx <= dense.size() + DENSE_GROW_THRESHOLD)
235
+ {
236
+ dense.resize(idx + 1, Constants::UNINITIALIZED);
237
+ dense[idx] = value;
238
+ return value;
239
+ }
240
+ else
241
+ {
242
+ sparse[idx] = value;
243
+ return value;
244
+ }
245
+ }
246
+
247
+ // --- ArrayPrototypes Implementation ---
248
+
249
+ namespace ArrayPrototypes {
250
+
251
+ AnyValue &get_toString_fn()
252
+ {
253
+ static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> _) -> AnyValue
254
+ { return AnyValue::make_string(thisVal.as_array()->to_std_string()); },
255
+ "toString");
256
+ return fn;
257
+ }
258
+
259
+ AnyValue &get_iterator_fn()
260
+ {
261
+ static AnyValue fn = AnyValue::make_generator([](AnyValue thisVal, std::vector<AnyValue> _) -> jspp::JsIterator<jspp::AnyValue>
262
+ {
263
+ auto arr = thisVal.as_array();
264
+ for (uint64_t idx = 0; idx < arr->length; ++idx)
265
+ {
266
+ co_yield arr->get_property(static_cast<uint32_t>(idx));
267
+ }
268
+ co_return Constants::UNDEFINED; },
269
+ "Symbol.iterator");
270
+ return fn;
271
+ }
272
+
273
+ AnyValue &get_length_desc()
274
+ {
275
+ static auto getter = [](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
276
+ {
277
+ return AnyValue::make_number(thisVal.as_array()->length);
278
+ };
279
+
280
+ static auto setter = [](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
281
+ {
282
+ if (args.empty())
283
+ {
284
+ return Constants::UNDEFINED;
285
+ }
286
+
287
+ auto self = thisVal.as_array();
288
+ const auto &new_len_val = args[0];
289
+ double new_len_double = Operators_Private::ToNumber(new_len_val);
290
+
291
+ if (new_len_double < 0 || std::isnan(new_len_double) || std::isinf(new_len_double) || new_len_double != static_cast<uint64_t>(new_len_double))
292
+ {
293
+ throw Exception::make_exception("Invalid array length", "RangeError");
294
+ }
295
+ uint64_t new_len = static_cast<uint64_t>(new_len_double);
296
+
297
+ // Truncate dense part
298
+ if (new_len < self->dense.size())
299
+ {
300
+ self->dense.resize(new_len);
301
+ }
302
+
303
+ // Remove sparse elements beyond the new length
304
+ for (auto it = self->sparse.begin(); it != self->sparse.end();)
305
+ {
306
+ if (it->first >= new_len)
307
+ {
308
+ it = self->sparse.erase(it);
309
+ }
310
+ else
311
+ {
312
+ ++it;
313
+ }
314
+ }
315
+
316
+ self->length = new_len;
317
+ return new_len_val;
318
+ };
319
+
320
+ static AnyValue desc = AnyValue::make_accessor_descriptor(getter,
321
+ setter,
322
+ false,
323
+ false);
324
+ return desc;
325
+ }
326
+
327
+ AnyValue &get_push_fn()
328
+ {
329
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
330
+ {
331
+ auto self = thisVal.as_array();
332
+ for (const auto &arg : args)
333
+ {
334
+ self->set_property(static_cast<uint32_t>(self->length), arg);
335
+ }
336
+ return AnyValue::make_number(self->length); },
337
+ "push");
338
+ return fn;
339
+ }
340
+
341
+ AnyValue &get_pop_fn()
342
+ {
343
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
344
+ {
345
+ auto self = thisVal.as_array();
346
+ if (self->length == 0)
347
+ {
348
+ return Constants::UNDEFINED;
349
+ }
350
+ uint64_t last_idx = self->length - 1;
351
+ AnyValue last_val = self->get_property(static_cast<uint32_t>(last_idx));
352
+
353
+ // Remove from dense
354
+ if (last_idx < self->dense.size())
355
+ {
356
+ self->dense.pop_back();
357
+ }
358
+ // Remove from sparse
359
+ self->sparse.erase(static_cast<uint32_t>(last_idx));
360
+
361
+ self->length--;
362
+ return last_val; },
363
+ "pop");
364
+ return fn;
365
+ }
366
+
367
+ AnyValue &get_shift_fn()
368
+ {
369
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
370
+ {
371
+ auto self = thisVal.as_array();
372
+ if (self->length == 0)
373
+ {
374
+ return Constants::UNDEFINED;
375
+ }
376
+ AnyValue first_val = self->get_property(0u);
377
+
378
+ // Shift all elements to the left
379
+ for (uint64_t i = 0; i < self->length - 1; ++i)
380
+ {
381
+ self->set_property(static_cast<uint32_t>(i), self->get_property(static_cast<uint32_t>(i + 1)));
382
+ }
383
+
384
+ // remove last element
385
+ uint64_t last_idx = self->length - 1;
386
+ if (last_idx < self->dense.size())
387
+ {
388
+ self->dense.pop_back();
389
+ }
390
+ self->sparse.erase(static_cast<uint32_t>(last_idx));
391
+
392
+ self->length--;
393
+
394
+ return first_val; },
395
+ "shift");
396
+ return fn;
397
+ }
398
+
399
+ AnyValue &get_unshift_fn()
400
+ {
401
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
402
+ {
403
+ auto self = thisVal.as_array();
404
+ size_t args_count = args.size();
405
+ if (args_count == 0)
406
+ {
407
+ return AnyValue::make_number(self->length);
408
+ }
409
+
410
+ // Shift existing elements to the right
411
+ for (uint64_t i = self->length; i > 0; --i)
412
+ {
413
+ self->set_property(static_cast<uint32_t>(i + args_count - 1), self->get_property(static_cast<uint32_t>(i - 1)));
414
+ }
415
+
416
+ // Insert new elements at the beginning
417
+ for (size_t i = 0; i < args_count; ++i)
418
+ {
419
+ self->set_property(static_cast<uint32_t>(i), args[i]);
420
+ }
421
+
422
+ return AnyValue::make_number(self->length); },
423
+ "unshift");
424
+ return fn;
425
+ }
426
+
427
+ AnyValue &get_join_fn()
428
+ {
429
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
430
+ {
431
+ auto self = thisVal.as_array();
432
+ std::string sep = ",";
433
+ if (!args.empty() && !args[0].is_undefined())
434
+ {
435
+ sep = args[0].to_std_string();
436
+ }
437
+
438
+ std::string result = "";
439
+ for (uint64_t i = 0; i < self->length; ++i)
440
+ {
441
+ AnyValue item = self->get_property(static_cast<uint32_t>(i));
442
+ if (!item.is_undefined() && !item.is_null())
443
+ {
444
+ result += item.to_std_string();
445
+ }
446
+ if (i < self->length - 1)
447
+ {
448
+ result += sep;
449
+ }
450
+ }
451
+ return AnyValue::make_string(result); },
452
+ "join");
453
+ return fn;
454
+ }
455
+
456
+ AnyValue &get_forEach_fn()
457
+ {
458
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
459
+ {
460
+ auto self = thisVal.as_array();
461
+ if (args.empty() || !args[0].is_function())
462
+ {
463
+ throw Exception::make_exception("callback is not a function", "TypeError");
464
+ }
465
+ auto callback = args[0].as_function();
466
+ for (uint64_t i = 0; i < self->length; ++i)
467
+ {
468
+ AnyValue val = self->get_property(static_cast<uint32_t>(i));
469
+ if (!val.is_undefined())
470
+ { // forEach skips empty slots
471
+ AnyValue iVal = AnyValue::make_number(i);
472
+ const AnyValue cbArgs[] = {val, iVal, thisVal};
473
+ callback->call(thisVal, cbArgs);
474
+ }
475
+ }
476
+ return Constants::UNDEFINED; },
477
+ "forEach");
478
+ return fn;
479
+ }
480
+
481
+ AnyValue &get_at_fn()
482
+ {
483
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
484
+ {
485
+ auto self = thisVal.as_array();
486
+ double len = static_cast<double>(self->length);
487
+ double relativeIndex = args.empty() ? 0 : Operators_Private::ToNumber(args[0]);
488
+ double k;
489
+ if (relativeIndex >= 0) k = relativeIndex;
490
+ else k = len + relativeIndex;
491
+ if (k < 0 || k >= len) return Constants::UNDEFINED;
492
+ return self->get_property(static_cast<uint32_t>(k)); },
493
+ "at");
494
+ return fn;
495
+ }
496
+
497
+ AnyValue &get_includes_fn()
498
+ {
499
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
500
+ {
501
+ auto self = thisVal.as_array();
502
+ AnyValue searchElement = args.empty() ? Constants::UNDEFINED : args[0];
503
+ double len = static_cast<double>(self->length);
504
+ if (len == 0) return Constants::FALSE;
505
+ double n = (args.size() > 1) ? Operators_Private::ToNumber(args[1]) : 0;
506
+ double k;
507
+ if (n >= 0) k = n;
508
+ else k = len + n;
509
+ if (k < 0) k = 0;
510
+
511
+ for (uint64_t i = static_cast<uint64_t>(k); i < self->length; ++i)
512
+ {
513
+ AnyValue element = self->get_property(static_cast<uint32_t>(i));
514
+ // SameValueZero algorithm (includes handles NaN)
515
+ if (element.is_number() && searchElement.is_number() && std::isnan(element.as_double()) && std::isnan(searchElement.as_double())) return Constants::TRUE;
516
+ if (is_strictly_equal_to_primitive(element, searchElement)) return Constants::TRUE;
517
+ }
518
+ return Constants::FALSE; },
519
+ "includes");
520
+ return fn;
521
+ }
522
+
523
+ AnyValue &get_indexOf_fn()
524
+ {
525
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
526
+ {
527
+ auto self = thisVal.as_array();
528
+ AnyValue searchElement = args.empty() ? Constants::UNDEFINED : args[0];
529
+ double len = static_cast<double>(self->length);
530
+ if (len == 0) return AnyValue::make_number(-1);
531
+ double n = (args.size() > 1) ? Operators_Private::ToNumber(args[1]) : 0;
532
+ double k;
533
+ if (n >= 0) k = n;
534
+ else k = len + n;
535
+ if (k < 0) k = 0;
536
+
537
+ for (uint64_t i = static_cast<uint64_t>(k); i < self->length; ++i)
538
+ {
539
+ if (self->has_property(std::to_string(i))) {
540
+ AnyValue element = self->get_property(static_cast<uint32_t>(i));
541
+ if (is_strictly_equal_to_primitive(element, searchElement)) return AnyValue::make_number(i);
542
+ }
543
+ }
544
+ return AnyValue::make_number(-1); },
545
+ "indexOf");
546
+ return fn;
547
+ }
548
+
549
+ AnyValue &get_lastIndexOf_fn()
550
+ {
551
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
552
+ {
553
+ auto self = thisVal.as_array();
554
+ AnyValue searchElement = args.empty() ? Constants::UNDEFINED : args[0];
555
+ double len = static_cast<double>(self->length);
556
+ if (len == 0) return AnyValue::make_number(-1);
557
+ double n = (args.size() > 1) ? Operators_Private::ToNumber(args[1]) : len - 1;
558
+ double k;
559
+ if (n >= 0) k = std::min(n, len - 1);
560
+ else k = len + n;
561
+
562
+ if (k < 0) return AnyValue::make_number(-1);
563
+
564
+ for (int64_t i = static_cast<int64_t>(k); i >= 0; --i)
565
+ {
566
+ if (self->has_property(std::to_string(i))) {
567
+ AnyValue element = self->get_property(static_cast<uint32_t>(i));
568
+ if (is_strictly_equal_to_primitive(element, searchElement)) return AnyValue::make_number(i);
569
+ }
570
+ }
571
+ return AnyValue::make_number(-1); },
572
+ "lastIndexOf");
573
+ return fn;
574
+ }
575
+
576
+ AnyValue &get_find_fn()
577
+ {
578
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
579
+ {
580
+ auto self = thisVal.as_array();
581
+ if (args.empty() || !args[0].is_function()) throw Exception::make_exception("callback is not a function", "TypeError");
582
+ auto callback = args[0].as_function();
583
+ auto thisArg = (args.size() > 1) ? args[1] : Constants::UNDEFINED;
584
+
585
+ for (uint64_t i = 0; i < self->length; ++i)
586
+ {
587
+ AnyValue element = self->get_property(static_cast<uint32_t>(i));
588
+ AnyValue kVal = AnyValue::make_number(i);
589
+ const AnyValue cbArgs[] = {element, kVal, thisVal};
590
+
591
+ if (is_truthy(callback->call(thisArg, std::span<const AnyValue>(cbArgs, 3)))) {
592
+ return element;
593
+ }
594
+ }
595
+ return Constants::UNDEFINED; },
596
+ "find");
597
+ return fn;
598
+ }
599
+
600
+ AnyValue &get_findIndex_fn()
601
+ {
602
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
603
+ {
604
+ auto self = thisVal.as_array();
605
+ if (args.empty() || !args[0].is_function()) throw Exception::make_exception("callback is not a function", "TypeError");
606
+ auto callback = args[0].as_function();
607
+ auto thisArg = (args.size() > 1) ? args[1] : Constants::UNDEFINED;
608
+
609
+ for (uint64_t i = 0; i < self->length; ++i) {
610
+ AnyValue element = self->get_property(static_cast<uint32_t>(i));
611
+ AnyValue kVal = AnyValue::make_number(i);
612
+ const AnyValue cbArgs[] = {element, kVal, thisVal};
613
+
614
+ if (is_truthy(callback->call(thisArg, std::span<const AnyValue>(cbArgs, 3)))) {
615
+ return AnyValue::make_number(i);
616
+ }
617
+ }
618
+ return AnyValue::make_number(-1); },
619
+ "findIndex");
620
+ return fn;
621
+ }
622
+
623
+ AnyValue &get_findLast_fn()
624
+ {
625
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
626
+ {
627
+ auto self = thisVal.as_array();
628
+ if (args.empty() || !args[0].is_function()) throw Exception::make_exception("callback is not a function", "TypeError");
629
+ auto callback = args[0].as_function();
630
+ auto thisArg = (args.size() > 1) ? args[1] : Constants::UNDEFINED;
631
+
632
+ for (int64_t i = self->length - 1; i >= 0; --i)
633
+ {
634
+ AnyValue element = self->get_property(static_cast<uint32_t>(i));
635
+ AnyValue kVal = AnyValue::make_number(i);
636
+ const AnyValue cbArgs[] = {element, kVal, thisVal};
637
+
638
+ if (is_truthy(callback->call(thisArg, std::span<const AnyValue>(cbArgs, 3)))) {
639
+ return element;
640
+ }
641
+ }
642
+ return Constants::UNDEFINED; },
643
+ "findLast");
644
+ return fn;
645
+ }
646
+
647
+ AnyValue &get_findLastIndex_fn()
648
+ {
649
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
650
+ {
651
+ auto self = thisVal.as_array();
652
+ if (args.empty() || !args[0].is_function()) throw Exception::make_exception("callback is not a function", "TypeError");
653
+ auto callback = args[0].as_function();
654
+ auto thisArg = (args.size() > 1) ? args[1] : Constants::UNDEFINED;
655
+
656
+ for (int64_t i = self->length - 1; i >= 0; --i)
657
+ {
658
+ AnyValue element = self->get_property(static_cast<uint32_t>(i));
659
+ AnyValue kVal = AnyValue::make_number(i);
660
+ const AnyValue cbArgs[] = {element, kVal, thisVal};
661
+
662
+ if (is_truthy(callback->call(thisArg, std::span<const AnyValue>(cbArgs, 3)))) {
663
+ return AnyValue::make_number(i);
664
+ }
665
+ }
666
+ return AnyValue::make_number(-1); },
667
+ "findLastIndex");
668
+ return fn;
669
+ }
670
+
671
+ AnyValue &get_values_fn()
672
+ {
673
+ static AnyValue fn = AnyValue::make_generator([](AnyValue thisVal, std::vector<AnyValue> _) -> jspp::JsIterator<jspp::AnyValue>
674
+ {
675
+ auto arr = thisVal.as_array();
676
+ for (uint64_t idx = 0; idx < arr->length; ++idx)
677
+ {
678
+ co_yield arr->get_property(static_cast<uint32_t>(idx));
679
+ }
680
+ co_return Constants::UNDEFINED; },
681
+ "values");
682
+ return fn;
683
+ }
684
+
685
+ AnyValue &get_keys_fn()
686
+ {
687
+ static AnyValue fn = AnyValue::make_generator([](AnyValue thisVal, std::vector<AnyValue> _) -> jspp::JsIterator<jspp::AnyValue>
688
+ {
689
+ auto self = thisVal.as_array();
690
+ for (uint64_t i = 0; i < self->length; ++i) {
691
+ co_yield AnyValue::make_number(i);
692
+ }
693
+ co_return Constants::UNDEFINED; },
694
+ "keys");
695
+ return fn;
696
+ }
697
+
698
+ AnyValue &get_entries_fn()
699
+ {
700
+ static AnyValue fn = AnyValue::make_generator([](AnyValue thisVal, std::vector<AnyValue> _) -> jspp::JsIterator<jspp::AnyValue>
701
+ {
702
+ auto self = thisVal.as_array();
703
+ for (uint64_t i = 0; i < self->length; ++i) {
704
+ std::vector<AnyValue> entry;
705
+ entry.push_back(AnyValue::make_number(i));
706
+ entry.push_back(self->get_property(static_cast<uint32_t>(i)));
707
+ co_yield AnyValue::make_array(std::move(entry));
708
+ }
709
+ co_return Constants::UNDEFINED; },
710
+ "entries");
711
+ return fn;
712
+ }
713
+
714
+ AnyValue &get_map_fn()
715
+ {
716
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
717
+ {
718
+ auto self = thisVal.as_array();
719
+ if (args.empty() || !args[0].is_function()) throw Exception::make_exception("callback is not a function", "TypeError");
720
+ auto callback = args[0].as_function();
721
+ auto thisArg = (args.size() > 1) ? args[1] : Constants::UNDEFINED;
722
+
723
+ std::vector<AnyValue> result;
724
+ result.reserve(self->length);
725
+
726
+ for (uint64_t i = 0; i < self->length; ++i) {
727
+ if (self->has_property(std::to_string(i))) {
728
+ AnyValue val = self->get_property(static_cast<uint32_t>(i));
729
+ AnyValue kVal = AnyValue::make_number(i);
730
+ const AnyValue cbArgs[] = {val, kVal, thisVal};
731
+ result.push_back(callback->call(thisArg, std::span<const AnyValue>(cbArgs, 3)));
732
+ } else {
733
+ result.push_back(Constants::UNINITIALIZED);
734
+ }
735
+ }
736
+ return AnyValue::make_array(std::move(result)); },
737
+ "map");
738
+ return fn;
739
+ }
740
+
741
+ AnyValue &get_filter_fn()
742
+ {
743
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
744
+ {
745
+ auto self = thisVal.as_array();
746
+ if (args.empty() || !args[0].is_function()) throw Exception::make_exception("callback is not a function", "TypeError");
747
+ auto callback = args[0].as_function();
748
+ auto thisArg = (args.size() > 1) ? args[1] : Constants::UNDEFINED;
749
+
750
+ std::vector<AnyValue> result;
751
+
752
+ for (uint64_t i = 0; i < self->length; ++i) {
753
+ if (self->has_property(std::to_string(i))) {
754
+ AnyValue val = self->get_property(static_cast<uint32_t>(i));
755
+ AnyValue kVal = AnyValue::make_number(i);
756
+ const AnyValue cbArgs[] = {val, kVal, thisVal};
757
+ if (is_truthy(callback->call(thisArg, std::span<const AnyValue>(cbArgs, 3)))) {
758
+ result.push_back(val);
759
+ }
760
+ }
761
+ }
762
+ return AnyValue::make_array(std::move(result)); },
763
+ "filter");
764
+ return fn;
765
+ }
766
+
767
+ AnyValue &get_every_fn()
768
+ {
769
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
770
+ {
771
+ auto self = thisVal.as_array();
772
+ if (args.empty() || !args[0].is_function()) throw Exception::make_exception("callback is not a function", "TypeError");
773
+ auto callback = args[0].as_function();
774
+ auto thisArg = (args.size() > 1) ? args[1] : Constants::UNDEFINED;
775
+
776
+ for (uint64_t i = 0; i < self->length; ++i) {
777
+ if (self->has_property(std::to_string(i))) {
778
+ AnyValue val = self->get_property(static_cast<uint32_t>(i));
779
+ AnyValue kVal = AnyValue::make_number(i);
780
+ const AnyValue cbArgs[] = {val, kVal, thisVal};
781
+ if (!is_truthy(callback->call(thisArg, std::span<const AnyValue>(cbArgs, 3)))) {
782
+ return Constants::FALSE;
783
+ }
784
+ }
785
+ }
786
+ return Constants::TRUE; },
787
+ "every");
788
+ return fn;
789
+ }
790
+
791
+ AnyValue &get_some_fn()
792
+ {
793
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
794
+ {
795
+ auto self = thisVal.as_array();
796
+ if (args.empty() || !args[0].is_function()) throw Exception::make_exception("callback is not a function", "TypeError");
797
+ auto callback = args[0].as_function();
798
+ auto thisArg = (args.size() > 1) ? args[1] : Constants::UNDEFINED;
799
+
800
+ for (uint64_t i = 0; i < self->length; ++i) {
801
+ if (self->has_property(std::to_string(i))) {
802
+ AnyValue val = self->get_property(static_cast<uint32_t>(i));
803
+ AnyValue kVal = AnyValue::make_number(i);
804
+ const AnyValue cbArgs[] = {val, kVal, thisVal};
805
+ if (is_truthy(callback->call(thisArg, std::span<const AnyValue>(cbArgs, 3)))) {
806
+ return Constants::TRUE;
807
+ }
808
+ }
809
+ }
810
+ return Constants::FALSE; },
811
+ "some");
812
+ return fn;
813
+ }
814
+
815
+ AnyValue &get_reduce_fn()
816
+ {
817
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
818
+ {
819
+ auto self = thisVal.as_array();
820
+ if (args.empty() || !args[0].is_function()) throw Exception::make_exception("callback is not a function", "TypeError");
821
+ auto callback = args[0].as_function();
822
+
823
+ uint64_t i = 0;
824
+ AnyValue accumulator;
825
+
826
+ if (args.size() > 1) {
827
+ accumulator = args[1];
828
+ } else {
829
+ if (self->length == 0) throw Exception::make_exception("Reduce of empty array with no initial value", "TypeError");
830
+ bool found = false;
831
+ for (; i < self->length; ++i) {
832
+ if (self->has_property(std::to_string(i))) {
833
+ accumulator = self->get_property(static_cast<uint32_t>(i));
834
+ found = true;
835
+ i++;
836
+ break;
837
+ }
838
+ }
839
+ if (!found) throw Exception::make_exception("Reduce of empty array with no initial value", "TypeError");
840
+ }
841
+
842
+ for (; i < self->length; ++i) {
843
+ if (self->has_property(std::to_string(i))) {
844
+ AnyValue val = self->get_property(static_cast<uint32_t>(i));
845
+ AnyValue kVal = AnyValue::make_number(i);
846
+ const AnyValue cbArgs[] = {accumulator, val, kVal, thisVal};
847
+ accumulator = callback->call(Constants::UNDEFINED, std::span<const AnyValue>(cbArgs, 4));
848
+ }
849
+ }
850
+ return accumulator; },
851
+ "reduce");
852
+ return fn;
853
+ }
854
+
855
+ AnyValue &get_reduceRight_fn()
856
+ {
857
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
858
+ {
859
+ auto self = thisVal.as_array();
860
+ if (args.empty() || !args[0].is_function()) throw Exception::make_exception("callback is not a function", "TypeError");
861
+ auto callback = args[0].as_function();
862
+
863
+ int64_t i = self->length - 1;
864
+ AnyValue accumulator;
865
+
866
+ if (args.size() > 1) {
867
+ accumulator = args[1];
868
+ } else {
869
+ if (self->length == 0) throw Exception::make_exception("Reduce of empty array with no initial value", "TypeError");
870
+ bool found = false;
871
+ for (; i >= 0; --i) {
872
+ if (self->has_property(std::to_string(i))) {
873
+ accumulator = self->get_property(static_cast<uint32_t>(i));
874
+ found = true;
875
+ i--;
876
+ break;
877
+ }
878
+ }
879
+ if (!found) throw Exception::make_exception("Reduce of empty array with no initial value", "TypeError");
880
+ }
881
+
882
+ for (; i >= 0; --i) {
883
+ if (self->has_property(std::to_string(i))) {
884
+ AnyValue val = self->get_property(static_cast<uint32_t>(i));
885
+ AnyValue kVal = AnyValue::make_number(i);
886
+ const AnyValue cbArgs[] = {accumulator, val, kVal, thisVal};
887
+ accumulator = callback->call(Constants::UNDEFINED, std::span<const AnyValue>(cbArgs, 4));
888
+ }
889
+ }
890
+ return accumulator; },
891
+ "reduceRight");
892
+ return fn;
893
+ }
894
+
895
+ AnyValue &get_flat_fn()
896
+ {
897
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
898
+ {
899
+ auto self = thisVal.as_array();
900
+ double depthVal = (args.size() > 0 && !args[0].is_undefined()) ? Operators_Private::ToNumber(args[0]) : 1;
901
+ int depth = static_cast<int>(depthVal);
902
+ if (depth < 0) depth = 0;
903
+
904
+ std::vector<AnyValue> result;
905
+ std::function<void(const AnyValue&, int)> flatten;
906
+ flatten = [&result, &flatten](const AnyValue& item, int d) {
907
+ if (d > 0 && item.is_array()) {
908
+ auto arr = item.as_array();
909
+ for (uint64_t i = 0; i < arr->length; ++i) {
910
+ if (arr->has_property(std::to_string(i))) {
911
+ flatten(arr->get_property(static_cast<uint32_t>(i)), d - 1);
912
+ }
913
+ }
914
+ } else {
915
+ result.push_back(item);
916
+ }
917
+ };
918
+
919
+ for (uint64_t i = 0; i < self->length; ++i) {
920
+ if (self->has_property(std::to_string(i))) {
921
+ flatten(self->get_property(static_cast<uint32_t>(i)), depth);
922
+ }
923
+ }
924
+ return AnyValue::make_array(std::move(result)); },
925
+ "flat");
926
+ return fn;
927
+ }
928
+
929
+ AnyValue &get_flatMap_fn()
930
+ {
931
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
932
+ {
933
+ auto self = thisVal.as_array();
934
+ if (args.empty() || !args[0].is_function()) throw Exception::make_exception("callback is not a function", "TypeError");
935
+ auto callback = args[0].as_function();
936
+ auto thisArg = (args.size() > 1) ? args[1] : Constants::UNDEFINED;
937
+
938
+ std::vector<AnyValue> result;
939
+
940
+ for (uint64_t i = 0; i < self->length; ++i) {
941
+ if (self->has_property(std::to_string(i))) {
942
+ AnyValue val = self->get_property(static_cast<uint32_t>(i));
943
+ AnyValue kVal = AnyValue::make_number(i);
944
+ const AnyValue cbArgs[] = {val, kVal, thisVal};
945
+ AnyValue mapped = callback->call(thisArg, std::span<const AnyValue>(cbArgs, 3));
946
+
947
+ if (mapped.is_array()) {
948
+ auto arr = mapped.as_array();
949
+ for (uint64_t j = 0; j < arr->length; ++j) {
950
+ if (arr->has_property(std::to_string(j))) {
951
+ result.push_back(arr->get_property(static_cast<uint32_t>(j)));
952
+ }
953
+ }
954
+ } else {
955
+ result.push_back(mapped);
956
+ }
957
+ }
958
+ }
959
+ return AnyValue::make_array(std::move(result)); },
960
+ "flatMap");
961
+ return fn;
962
+ }
963
+
964
+ AnyValue &get_fill_fn()
965
+ {
966
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
967
+ {
968
+ auto self = thisVal.as_array();
969
+ AnyValue value = args.empty() ? Constants::UNDEFINED : args[0];
970
+ double len = static_cast<double>(self->length);
971
+ double start = (args.size() > 1) ? Operators_Private::ToNumber(args[1]) : 0;
972
+ double end = (args.size() > 2 && !args[2].is_undefined()) ? Operators_Private::ToNumber(args[2]) : len;
973
+
974
+ double k;
975
+ if (start >= 0) k = start; else k = len + start;
976
+ if (k < 0) k = 0;
977
+
978
+ double final;
979
+ if (end >= 0) final = end; else final = len + end;
980
+ if (final > len) final = len;
981
+
982
+ for (uint64_t i = static_cast<uint64_t>(k); i < static_cast<uint64_t>(final); ++i) {
983
+ self->set_property(static_cast<uint32_t>(i), value);
984
+ }
985
+ return thisVal; },
986
+ "fill");
987
+ return fn;
988
+ }
989
+
990
+ AnyValue &get_reverse_fn()
991
+ {
992
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
993
+ {
994
+ auto self = thisVal.as_array();
995
+ uint64_t len = self->length;
996
+ for (uint64_t i = 0; i < len / 2; ++i) {
997
+ uint64_t j = len - 1 - i;
998
+ bool hasI = self->has_property(std::to_string(i));
999
+ bool hasJ = self->has_property(std::to_string(j));
1000
+
1001
+ if (hasI && hasJ) {
1002
+ AnyValue valI = self->get_property(static_cast<uint32_t>(i));
1003
+ AnyValue valJ = self->get_property(static_cast<uint32_t>(j));
1004
+ self->set_property(static_cast<uint32_t>(i), valJ);
1005
+ self->set_property(static_cast<uint32_t>(j), valI);
1006
+ } else if (hasI && !hasJ) {
1007
+ AnyValue valI = self->get_property(static_cast<uint32_t>(i));
1008
+ self->set_property(static_cast<uint32_t>(j), valI);
1009
+ if (i < self->dense.size()) self->dense[i] = Constants::UNINITIALIZED;
1010
+ else self->sparse.erase(static_cast<uint32_t>(i));
1011
+ } else if (!hasI && hasJ) {
1012
+ AnyValue valJ = self->get_property(static_cast<uint32_t>(j));
1013
+ self->set_property(static_cast<uint32_t>(i), valJ);
1014
+ if (j < self->dense.size()) self->dense[j] = Constants::UNINITIALIZED;
1015
+ else self->sparse.erase(static_cast<uint32_t>(j));
1016
+ }
1017
+ }
1018
+ return thisVal; },
1019
+ "reverse");
1020
+ return fn;
1021
+ }
1022
+
1023
+ AnyValue &get_sort_fn()
1024
+ {
1025
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
1026
+ {
1027
+ auto self = thisVal.as_array();
1028
+ AnyValue compareFn = args.empty() ? Constants::UNDEFINED : args[0];
1029
+
1030
+ std::vector<AnyValue> items;
1031
+ for (uint64_t i = 0; i < self->length; ++i) {
1032
+ if (self->has_property(std::to_string(i))) {
1033
+ items.push_back(self->get_property(static_cast<uint32_t>(i)));
1034
+ }
1035
+ }
1036
+
1037
+ std::sort(items.begin(), items.end(), [&](const AnyValue& a, const AnyValue& b) {
1038
+ if (a.is_undefined() && b.is_undefined()) return false;
1039
+ if (a.is_undefined()) return false;
1040
+ if (b.is_undefined()) return true;
1041
+
1042
+ if (compareFn.is_function()) {
1043
+ const AnyValue cmpArgs[] = {a, b};
1044
+ double res = Operators_Private::ToNumber(compareFn.call(Constants::UNDEFINED, std::span<const AnyValue>(cmpArgs, 2)));
1045
+ return res < 0;
1046
+ } else {
1047
+ std::string sA = a.to_std_string();
1048
+ std::string sB = b.to_std_string();
1049
+ return sA < sB;
1050
+ }
1051
+ });
1052
+
1053
+ for (uint64_t i = 0; i < items.size(); ++i) {
1054
+ self->set_property(static_cast<uint32_t>(i), items[i]);
1055
+ }
1056
+ for (uint64_t i = items.size(); i < self->length; ++i) {
1057
+ if (i < self->dense.size()) self->dense[i] = Constants::UNINITIALIZED;
1058
+ else self->sparse.erase(static_cast<uint32_t>(i));
1059
+ }
1060
+
1061
+ return thisVal; },
1062
+ "sort");
1063
+ return fn;
1064
+ }
1065
+
1066
+ AnyValue &get_splice_fn()
1067
+ {
1068
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
1069
+ {
1070
+ auto self = thisVal.as_array();
1071
+ double len = static_cast<double>(self->length);
1072
+ double start = args.empty() ? 0 : Operators_Private::ToNumber(args[0]);
1073
+ double actualStart = (start < 0) ? std::max(len + start, 0.0) : std::min(start, len);
1074
+
1075
+ uint64_t startIdx = static_cast<uint64_t>(actualStart);
1076
+ uint64_t deleteCount = 0;
1077
+ if (args.size() >= 2) {
1078
+ double dc = Operators_Private::ToNumber(args[1]);
1079
+ deleteCount = static_cast<uint64_t>(std::max(0.0, std::min(dc, len - startIdx)));
1080
+ } else if (args.size() == 1) {
1081
+ deleteCount = len - startIdx;
1082
+ }
1083
+
1084
+ std::vector<AnyValue> deletedItems;
1085
+ for (uint64_t i = 0; i < deleteCount; ++i) {
1086
+ if (self->has_property(std::to_string(startIdx + i))) {
1087
+ deletedItems.push_back(self->get_property(static_cast<uint32_t>(startIdx + i)));
1088
+ } else {
1089
+ deletedItems.push_back(Constants::UNINITIALIZED);
1090
+ }
1091
+ }
1092
+
1093
+ std::vector<AnyValue> insertItems;
1094
+ for (size_t i = 2; i < args.size(); ++i) {
1095
+ insertItems.push_back(args[i]);
1096
+ }
1097
+ uint64_t insertCount = insertItems.size();
1098
+
1099
+ if (insertCount < deleteCount) {
1100
+ for (uint64_t i = startIdx; i < len - deleteCount; ++i) {
1101
+ uint64_t from = i + deleteCount;
1102
+ uint64_t to = i + insertCount;
1103
+ if (self->has_property(std::to_string(from))) {
1104
+ self->set_property(static_cast<uint32_t>(to), self->get_property(static_cast<uint32_t>(from)));
1105
+ } else {
1106
+ if (to < self->dense.size()) self->dense[to] = Constants::UNINITIALIZED;
1107
+ else self->sparse.erase(static_cast<uint32_t>(to));
1108
+ }
1109
+ }
1110
+ for (uint64_t i = len; i > len - deleteCount + insertCount; --i) {
1111
+ uint64_t idx = i - 1;
1112
+ if (idx < self->dense.size()) self->dense[idx] = Constants::UNINITIALIZED;
1113
+ else self->sparse.erase(static_cast<uint32_t>(idx));
1114
+ }
1115
+ } else if (insertCount > deleteCount) {
1116
+ for (uint64_t i = len; i > startIdx + deleteCount; --i) {
1117
+ uint64_t from = i - 1;
1118
+ uint64_t to = from - deleteCount + insertCount;
1119
+ if (self->has_property(std::to_string(from))) {
1120
+ self->set_property(static_cast<uint32_t>(to), self->get_property(static_cast<uint32_t>(from)));
1121
+ } else {
1122
+ if (to < self->dense.size()) self->dense[to] = Constants::UNINITIALIZED;
1123
+ else self->sparse.erase(static_cast<uint32_t>(to));
1124
+ }
1125
+ }
1126
+ }
1127
+
1128
+ for (uint64_t i = 0; i < insertCount; ++i) {
1129
+ self->set_property(static_cast<uint32_t>(startIdx + i), insertItems[i]);
1130
+ }
1131
+
1132
+ self->length = len - deleteCount + insertCount;
1133
+ return AnyValue::make_array(std::move(deletedItems)); },
1134
+ "splice");
1135
+ return fn;
1136
+ }
1137
+
1138
+ AnyValue &get_copyWithin_fn()
1139
+ {
1140
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
1141
+ {
1142
+ auto self = thisVal.as_array();
1143
+ double len = static_cast<double>(self->length);
1144
+ double target = args.empty() ? 0 : Operators_Private::ToNumber(args[0]);
1145
+ double start = (args.size() > 1) ? Operators_Private::ToNumber(args[1]) : 0;
1146
+ double end = (args.size() > 2 && !args[2].is_undefined()) ? Operators_Private::ToNumber(args[2]) : len;
1147
+
1148
+ double to;
1149
+ if (target >= 0) to = target; else to = len + target;
1150
+ if (to < 0) to = 0; else if (to > len) to = len;
1151
+
1152
+ double from;
1153
+ if (start >= 0) from = start; else from = len + start;
1154
+ if (from < 0) from = 0; else if (from > len) from = len;
1155
+
1156
+ double final;
1157
+ if (end >= 0) final = end; else final = len + end;
1158
+ if (final < 0) final = 0; else if (final > len) final = len;
1159
+
1160
+ double count = std::min(final - from, len - to);
1161
+
1162
+ if (from < to && to < from + count) {
1163
+ for (double i = count - 1; i >= 0; --i) {
1164
+ uint64_t f = static_cast<uint64_t>(from + i);
1165
+ uint64_t t = static_cast<uint64_t>(to + i);
1166
+ if (self->has_property(std::to_string(f))) {
1167
+ self->set_property(static_cast<uint32_t>(t), self->get_property(static_cast<uint32_t>(f)));
1168
+ } else {
1169
+ if (t < self->dense.size()) self->dense[t] = Constants::UNINITIALIZED;
1170
+ else self->sparse.erase(static_cast<uint32_t>(t));
1171
+ }
1172
+ }
1173
+ } else {
1174
+ for (double i = 0; i < count; ++i) {
1175
+ uint64_t f = static_cast<uint64_t>(from + i);
1176
+ uint64_t t = static_cast<uint64_t>(to + i);
1177
+ if (self->has_property(std::to_string(f))) {
1178
+ self->set_property(static_cast<uint32_t>(t), self->get_property(static_cast<uint32_t>(f)));
1179
+ } else {
1180
+ if (t < self->dense.size()) self->dense[t] = Constants::UNINITIALIZED;
1181
+ else self->sparse.erase(static_cast<uint32_t>(t));
1182
+ }
1183
+ }
1184
+ }
1185
+ return thisVal; },
1186
+ "copyWithin");
1187
+ return fn;
1188
+ }
1189
+
1190
+ AnyValue &get_concat_fn()
1191
+ {
1192
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
1193
+ {
1194
+ auto self = thisVal.as_array();
1195
+ std::vector<AnyValue> result;
1196
+ for (uint64_t i = 0; i < self->length; ++i) {
1197
+ if (self->has_property(std::to_string(i))) {
1198
+ result.push_back(self->get_property(static_cast<uint32_t>(i)));
1199
+ } else {
1200
+ result.push_back(Constants::UNINITIALIZED);
1201
+ }
1202
+ }
1203
+
1204
+ for (const auto& item : args) {
1205
+ bool spreadable = false;
1206
+ auto spreadableSym = AnyValue::from_symbol(WellKnownSymbols::isConcatSpreadable);
1207
+ if (item.is_array()) {
1208
+ spreadable = true;
1209
+ if (item.has_property(spreadableSym)) {
1210
+ spreadable = is_truthy(item.get_own_property(spreadableSym));
1211
+ }
1212
+ } else if (item.is_object()) {
1213
+ if (item.has_property(spreadableSym)) {
1214
+ spreadable = is_truthy(item.get_own_property(spreadableSym));
1215
+ }
1216
+ }
1217
+
1218
+ if (spreadable && item.is_array()) {
1219
+ auto arr = item.as_array();
1220
+ for (uint64_t i = 0; i < arr->length; ++i) {
1221
+ if (arr->has_property(std::to_string(i))) {
1222
+ result.push_back(arr->get_property(static_cast<uint32_t>(i)));
1223
+ } else {
1224
+ result.push_back(Constants::UNINITIALIZED);
1225
+ }
1226
+ }
1227
+ } else {
1228
+ result.push_back(item);
1229
+ }
1230
+ }
1231
+ return AnyValue::make_array(std::move(result)); },
1232
+ "concat");
1233
+ return fn;
1234
+ }
1235
+
1236
+ AnyValue &get_slice_fn()
1237
+ {
1238
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
1239
+ {
1240
+ auto self = thisVal.as_array();
1241
+ double len = static_cast<double>(self->length);
1242
+ double start = args.empty() ? 0 : Operators_Private::ToNumber(args[0]);
1243
+ double actualStart = (start < 0) ? std::max(len + start, 0.0) : std::min(start, len);
1244
+ double end = (args.size() < 2 || args[1].is_undefined()) ? len : Operators_Private::ToNumber(args[1]);
1245
+ double actualEnd = (end < 0) ? std::max(len + end, 0.0) : std::min(end, len);
1246
+
1247
+ std::vector<AnyValue> result;
1248
+ for (uint64_t i = static_cast<uint64_t>(actualStart); i < static_cast<uint64_t>(actualEnd); ++i) {
1249
+ if (self->has_property(std::to_string(i))) {
1250
+ result.push_back(self->get_property(static_cast<uint32_t>(i)));
1251
+ } else {
1252
+ result.push_back(Constants::UNINITIALIZED);
1253
+ }
1254
+ }
1255
+ return AnyValue::make_array(std::move(result)); },
1256
+ "slice");
1257
+ return fn;
1258
+ }
1259
+
1260
+ AnyValue &get_toReversed_fn()
1261
+ {
1262
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
1263
+ {
1264
+ auto copy = thisVal.get_property_with_receiver("slice", thisVal).call(thisVal, {});
1265
+ copy.get_own_property("reverse").call(copy, {});
1266
+ return copy; },
1267
+ "toReversed");
1268
+ return fn;
1269
+ }
1270
+
1271
+ AnyValue &get_toSorted_fn()
1272
+ {
1273
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
1274
+ {
1275
+ auto copy = thisVal.get_property_with_receiver("slice", thisVal).call(thisVal, {});
1276
+ copy.get_own_property("sort").call(copy, args);
1277
+ return copy; },
1278
+ "toSorted");
1279
+ return fn;
1280
+ }
1281
+
1282
+ AnyValue &get_toSpliced_fn()
1283
+ {
1284
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
1285
+ {
1286
+ auto copy = thisVal.get_property_with_receiver("slice", thisVal).call(thisVal, {});
1287
+ copy.get_own_property("splice").call(copy, args);
1288
+ return copy; },
1289
+ "toSpliced");
1290
+ return fn;
1291
+ }
1292
+
1293
+ AnyValue &get_with_fn()
1294
+ {
1295
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
1296
+ {
1297
+ auto self = thisVal.as_array();
1298
+ auto copy = thisVal.get_property_with_receiver("slice", thisVal).call(thisVal, {});
1299
+
1300
+ double len = static_cast<double>(self->length);
1301
+ double idx = args.empty() ? 0 : Operators_Private::ToNumber(args[0]);
1302
+ double k;
1303
+ if (idx >= 0) k = idx; else k = len + idx;
1304
+
1305
+ if (k < 0 || k >= len) throw Exception::make_exception("Invalid index", "RangeError");
1306
+
1307
+ AnyValue value = (args.size() > 1) ? args[1] : Constants::UNDEFINED;
1308
+ copy.set_own_property(static_cast<uint32_t>(k), value);
1309
+ return copy; },
1310
+ "with");
1311
+ return fn;
1312
+ }
1313
+
1314
+ AnyValue &get_toLocaleString_fn()
1315
+ {
1316
+ static AnyValue fn = AnyValue::make_function([](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
1317
+ {
1318
+ auto self = thisVal.as_array();
1319
+ std::string result = "";
1320
+ for (uint64_t i = 0; i < self->length; ++i) {
1321
+ if (i > 0) result += ",";
1322
+ AnyValue element = self->get_property(static_cast<uint32_t>(i));
1323
+ if (!element.is_null() && !element.is_undefined()) {
1324
+ if (element.has_property("toLocaleString")) {
1325
+ auto fn = element.get_property_with_receiver("toLocaleString", element);
1326
+ if (fn.is_function()) {
1327
+ result += fn.call(element, {}).to_std_string();
1328
+ continue;
1329
+ }
1330
+ }
1331
+ result += element.to_std_string();
1332
+ }
1333
+ }
1334
+ return AnyValue::make_string(result); },
1335
+ "toLocaleString");
1336
+ return fn;
1337
+ }
1338
+
1339
+ std::optional<AnyValue> get(const std::string &key)
1340
+ {
1341
+ if (key == "toString") return get_toString_fn();
1342
+ if (key == "length") return get_length_desc();
1343
+ if (key == "push") return get_push_fn();
1344
+ if (key == "pop") return get_pop_fn();
1345
+ if (key == "shift") return get_shift_fn();
1346
+ if (key == "unshift") return get_unshift_fn();
1347
+ if (key == "join") return get_join_fn();
1348
+ if (key == "forEach") return get_forEach_fn();
1349
+ if (key == "at") return get_at_fn();
1350
+ if (key == "includes") return get_includes_fn();
1351
+ if (key == "indexOf") return get_indexOf_fn();
1352
+ if (key == "lastIndexOf") return get_lastIndexOf_fn();
1353
+ if (key == "find") return get_find_fn();
1354
+ if (key == "findIndex") return get_findIndex_fn();
1355
+ if (key == "findLast") return get_findLast_fn();
1356
+ if (key == "findLastIndex") return get_findLastIndex_fn();
1357
+ if (key == "values") return get_values_fn();
1358
+ if (key == "keys") return get_keys_fn();
1359
+ if (key == "entries") return get_entries_fn();
1360
+ if (key == "map") return get_map_fn();
1361
+ if (key == "filter") return get_filter_fn();
1362
+ if (key == "every") return get_every_fn();
1363
+ if (key == "some") return get_some_fn();
1364
+ if (key == "reduce") return get_reduce_fn();
1365
+ if (key == "reduceRight") return get_reduceRight_fn();
1366
+ if (key == "flat") return get_flat_fn();
1367
+ if (key == "flatMap") return get_flatMap_fn();
1368
+ if (key == "fill") return get_fill_fn();
1369
+ if (key == "reverse") return get_reverse_fn();
1370
+ if (key == "sort") return get_sort_fn();
1371
+ if (key == "splice") return get_splice_fn();
1372
+ if (key == "copyWithin") return get_copyWithin_fn();
1373
+ if (key == "concat") return get_concat_fn();
1374
+ if (key == "slice") return get_slice_fn();
1375
+ if (key == "toReversed") return get_toReversed_fn();
1376
+ if (key == "toSorted") return get_toSorted_fn();
1377
+ if (key == "toSpliced") return get_toSpliced_fn();
1378
+ if (key == "with") return get_with_fn();
1379
+ if (key == "toLocaleString") return get_toLocaleString_fn();
1380
+ return std::nullopt;
1381
+ }
1382
+
1383
+ std::optional<AnyValue> get(const AnyValue &key)
1384
+ {
1385
+ if (key.is_string())
1386
+ return get(key.as_string()->value);
1387
+
1388
+ auto toStringTagSym = AnyValue::from_symbol(WellKnownSymbols::toStringTag);
1389
+ if (key == toStringTagSym) return get_toString_fn();
1390
+
1391
+ auto iteratorSym = AnyValue::from_symbol(WellKnownSymbols::iterator);
1392
+ if (key == iteratorSym) return get_iterator_fn();
1393
+
1394
+ return std::nullopt;
1395
+ }
1396
+
1397
+ } // namespace ArrayPrototypes
1398
+
1399
+ } // namespace jspp