@ugo-studio/jspp 0.1.4 → 0.1.5
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.
- package/dist/analysis/scope.js +17 -0
- package/dist/analysis/typeAnalyzer.js +7 -1
- package/dist/ast/symbols.js +29 -0
- package/dist/ast/types.js +0 -6
- package/dist/cli-utils/args.js +57 -0
- package/dist/cli-utils/colors.js +9 -0
- package/dist/cli-utils/file-utils.js +20 -0
- package/dist/cli-utils/spinner.js +55 -0
- package/dist/cli.js +105 -30
- package/dist/core/codegen/class-handlers.js +10 -6
- package/dist/core/codegen/control-flow-handlers.js +31 -21
- package/dist/core/codegen/declaration-handlers.js +10 -6
- package/dist/core/codegen/expression-handlers.js +202 -60
- package/dist/core/codegen/function-handlers.js +179 -70
- package/dist/core/codegen/helpers.js +107 -17
- package/dist/core/codegen/index.js +9 -8
- package/dist/core/codegen/literal-handlers.js +15 -6
- package/dist/core/codegen/statement-handlers.js +67 -53
- package/dist/core/codegen/visitor.js +3 -1
- package/package.json +1 -1
- package/src/prelude/any_value.hpp +195 -342
- package/src/prelude/any_value_access.hpp +78 -30
- package/src/prelude/any_value_defines.hpp +74 -35
- package/src/prelude/any_value_helpers.hpp +73 -180
- package/src/prelude/exception.hpp +1 -0
- package/src/prelude/exception_helpers.hpp +4 -4
- package/src/prelude/index.hpp +9 -2
- package/src/prelude/library/array.hpp +190 -0
- package/src/prelude/library/console.hpp +6 -5
- package/src/prelude/library/error.hpp +10 -8
- package/src/prelude/library/function.hpp +10 -0
- package/src/prelude/library/global.hpp +20 -0
- package/src/prelude/library/math.hpp +308 -0
- package/src/prelude/library/object.hpp +288 -0
- package/src/prelude/library/performance.hpp +1 -1
- package/src/prelude/library/process.hpp +39 -0
- package/src/prelude/library/promise.hpp +53 -43
- package/src/prelude/library/symbol.hpp +45 -57
- package/src/prelude/library/timer.hpp +6 -6
- package/src/prelude/types.hpp +48 -0
- package/src/prelude/utils/access.hpp +182 -11
- package/src/prelude/utils/assignment_operators.hpp +99 -0
- package/src/prelude/utils/log_any_value/array.hpp +8 -8
- package/src/prelude/utils/log_any_value/function.hpp +6 -4
- package/src/prelude/utils/log_any_value/object.hpp +41 -24
- package/src/prelude/utils/log_any_value/primitives.hpp +3 -1
- package/src/prelude/utils/operators.hpp +750 -274
- package/src/prelude/utils/well_known_symbols.hpp +12 -0
- package/src/prelude/values/array.hpp +8 -6
- package/src/prelude/values/descriptors.hpp +2 -2
- package/src/prelude/values/function.hpp +71 -62
- package/src/prelude/values/helpers/array.hpp +64 -28
- package/src/prelude/values/helpers/function.hpp +77 -92
- package/src/prelude/values/helpers/iterator.hpp +3 -3
- package/src/prelude/values/helpers/object.hpp +54 -9
- package/src/prelude/values/helpers/promise.hpp +3 -3
- package/src/prelude/values/iterator.hpp +1 -1
- package/src/prelude/values/object.hpp +10 -3
- package/src/prelude/values/promise.hpp +3 -3
- package/src/prelude/values/prototypes/array.hpp +851 -12
- package/src/prelude/values/prototypes/function.hpp +2 -2
- package/src/prelude/values/prototypes/iterator.hpp +5 -5
- package/src/prelude/values/prototypes/number.hpp +153 -0
- package/src/prelude/values/prototypes/object.hpp +2 -2
- package/src/prelude/values/prototypes/promise.hpp +40 -30
- package/src/prelude/values/prototypes/string.hpp +28 -28
- package/src/prelude/values/prototypes/symbol.hpp +20 -3
- package/src/prelude/values/shape.hpp +52 -0
|
@@ -15,9 +15,9 @@ namespace jspp
|
|
|
15
15
|
inline std::optional<AnyValue> get(const std::string &key, JsArray *self)
|
|
16
16
|
{
|
|
17
17
|
// --- toString() method ---
|
|
18
|
-
if (key == "toString" )
|
|
18
|
+
if (key == "toString" || key == WellKnownSymbols::toStringTag->key)
|
|
19
19
|
{
|
|
20
|
-
return AnyValue::make_function([self](const AnyValue &thisVal,
|
|
20
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> _) -> AnyValue
|
|
21
21
|
{ return AnyValue::make_string(self->to_std_string()); },
|
|
22
22
|
key);
|
|
23
23
|
}
|
|
@@ -25,7 +25,7 @@ namespace jspp
|
|
|
25
25
|
// --- [Symbol.iterator]() method ---
|
|
26
26
|
if (key == WellKnownSymbols::iterator->key)
|
|
27
27
|
{
|
|
28
|
-
return AnyValue::make_generator([self](const AnyValue &thisVal,
|
|
28
|
+
return AnyValue::make_generator([self](const AnyValue &thisVal, std::span<const AnyValue> _) -> AnyValue
|
|
29
29
|
{ return AnyValue::from_iterator(self->get_iterator()); },
|
|
30
30
|
key);
|
|
31
31
|
}
|
|
@@ -33,12 +33,12 @@ namespace jspp
|
|
|
33
33
|
// --- length property ---
|
|
34
34
|
if (key == "length")
|
|
35
35
|
{
|
|
36
|
-
auto getter = [self](const AnyValue &thisVal,
|
|
36
|
+
auto getter = [self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
37
37
|
{
|
|
38
38
|
return AnyValue::make_number(self->length);
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
-
auto setter = [self](const AnyValue &thisVal,
|
|
41
|
+
auto setter = [self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
42
42
|
{
|
|
43
43
|
if (args.empty())
|
|
44
44
|
{
|
|
@@ -86,7 +86,7 @@ namespace jspp
|
|
|
86
86
|
// --- push() method ---
|
|
87
87
|
if (key == "push")
|
|
88
88
|
{
|
|
89
|
-
return AnyValue::make_function([self](const AnyValue &thisVal,
|
|
89
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
90
90
|
{
|
|
91
91
|
for (const auto &arg : args)
|
|
92
92
|
{
|
|
@@ -99,7 +99,7 @@ namespace jspp
|
|
|
99
99
|
// --- pop() method ---
|
|
100
100
|
if (key == "pop")
|
|
101
101
|
{
|
|
102
|
-
return AnyValue::make_function([self](const AnyValue &thisVal,
|
|
102
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
103
103
|
{
|
|
104
104
|
if (self->length == 0)
|
|
105
105
|
{
|
|
@@ -124,7 +124,7 @@ namespace jspp
|
|
|
124
124
|
// --- shift() method ---
|
|
125
125
|
if (key == "shift")
|
|
126
126
|
{
|
|
127
|
-
return AnyValue::make_function([self](const AnyValue &thisVal,
|
|
127
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
128
128
|
{
|
|
129
129
|
if (self->length == 0)
|
|
130
130
|
{
|
|
@@ -155,7 +155,7 @@ namespace jspp
|
|
|
155
155
|
// --- unshift() method ---
|
|
156
156
|
if (key == "unshift")
|
|
157
157
|
{
|
|
158
|
-
return AnyValue::make_function([self](const AnyValue &thisVal,
|
|
158
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
159
159
|
{
|
|
160
160
|
size_t args_count = args.size();
|
|
161
161
|
if (args_count == 0)
|
|
@@ -182,7 +182,7 @@ namespace jspp
|
|
|
182
182
|
// --- join() method ---
|
|
183
183
|
if (key == "join")
|
|
184
184
|
{
|
|
185
|
-
return AnyValue::make_function([self](const AnyValue &thisVal,
|
|
185
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
186
186
|
{
|
|
187
187
|
std::string sep = ",";
|
|
188
188
|
if (!args.empty() && !args[0].is_undefined())
|
|
@@ -210,7 +210,7 @@ namespace jspp
|
|
|
210
210
|
// --- forEach() method ---
|
|
211
211
|
if (key == "forEach")
|
|
212
212
|
{
|
|
213
|
-
return AnyValue::make_function([self](const AnyValue &thisVal,
|
|
213
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
214
214
|
{
|
|
215
215
|
if (args.empty() || !args[0].is_function())
|
|
216
216
|
{
|
|
@@ -222,13 +222,852 @@ namespace jspp
|
|
|
222
222
|
AnyValue val = self->get_property(static_cast<uint32_t>(i));
|
|
223
223
|
if (!val.is_undefined())
|
|
224
224
|
{ // forEach skips empty slots
|
|
225
|
-
|
|
225
|
+
AnyValue iVal = AnyValue::make_number(i);
|
|
226
|
+
const AnyValue cbArgs[] = {val, iVal, thisVal};
|
|
227
|
+
callback->call(thisVal, cbArgs);
|
|
226
228
|
}
|
|
227
229
|
}
|
|
228
230
|
return AnyValue::make_undefined(); },
|
|
229
231
|
key);
|
|
230
232
|
}
|
|
231
233
|
|
|
234
|
+
// --- at(index) ---
|
|
235
|
+
if (key == "at")
|
|
236
|
+
{
|
|
237
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
238
|
+
{
|
|
239
|
+
double len = static_cast<double>(self->length);
|
|
240
|
+
double relativeIndex = args.empty() ? 0 : Operators_Private::ToNumber(args[0]);
|
|
241
|
+
double k;
|
|
242
|
+
if (relativeIndex >= 0) k = relativeIndex;
|
|
243
|
+
else k = len + relativeIndex;
|
|
244
|
+
if (k < 0 || k >= len) return AnyValue::make_undefined();
|
|
245
|
+
return self->get_property(static_cast<uint32_t>(k)); },
|
|
246
|
+
key);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// --- includes(searchElement, fromIndex) ---
|
|
250
|
+
if (key == "includes")
|
|
251
|
+
{
|
|
252
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
253
|
+
{
|
|
254
|
+
AnyValue searchElement = args.empty() ? AnyValue::make_undefined() : args[0];
|
|
255
|
+
double len = static_cast<double>(self->length);
|
|
256
|
+
if (len == 0) return AnyValue::make_boolean(false);
|
|
257
|
+
double n = (args.size() > 1) ? Operators_Private::ToNumber(args[1]) : 0;
|
|
258
|
+
double k;
|
|
259
|
+
if (n >= 0) k = n;
|
|
260
|
+
else k = len + n;
|
|
261
|
+
if (k < 0) k = 0;
|
|
262
|
+
|
|
263
|
+
for (uint64_t i = static_cast<uint64_t>(k); i < self->length; ++i)
|
|
264
|
+
{
|
|
265
|
+
AnyValue element = self->get_property(static_cast<uint32_t>(i));
|
|
266
|
+
// SameValueZero algorithm (includes handles NaN)
|
|
267
|
+
if (element.is_number() && searchElement.is_number() && std::isnan(element.as_double()) && std::isnan(searchElement.as_double())) return AnyValue::make_boolean(true);
|
|
268
|
+
if (is_strictly_equal_to_primitive(element, searchElement)) return AnyValue::make_boolean(true);
|
|
269
|
+
}
|
|
270
|
+
return AnyValue::make_boolean(false); },
|
|
271
|
+
key);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// --- indexOf(searchElement, fromIndex) ---
|
|
275
|
+
if (key == "indexOf")
|
|
276
|
+
{
|
|
277
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
278
|
+
{
|
|
279
|
+
AnyValue searchElement = args.empty() ? AnyValue::make_undefined() : args[0];
|
|
280
|
+
double len = static_cast<double>(self->length);
|
|
281
|
+
if (len == 0) return AnyValue::make_number(-1);
|
|
282
|
+
double n = (args.size() > 1) ? Operators_Private::ToNumber(args[1]) : 0;
|
|
283
|
+
double k;
|
|
284
|
+
if (n >= 0) k = n;
|
|
285
|
+
else k = len + n;
|
|
286
|
+
if (k < 0) k = 0;
|
|
287
|
+
|
|
288
|
+
for (uint64_t i = static_cast<uint64_t>(k); i < self->length; ++i)
|
|
289
|
+
{
|
|
290
|
+
if (self->has_property(std::to_string(i))) {
|
|
291
|
+
AnyValue element = self->get_property(static_cast<uint32_t>(i));
|
|
292
|
+
if (is_strictly_equal_to_primitive(element, searchElement)) return AnyValue::make_number(i);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return AnyValue::make_number(-1); },
|
|
296
|
+
key);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// --- lastIndexOf(searchElement, fromIndex) ---
|
|
300
|
+
if (key == "lastIndexOf")
|
|
301
|
+
{
|
|
302
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
303
|
+
{
|
|
304
|
+
AnyValue searchElement = args.empty() ? AnyValue::make_undefined() : args[0];
|
|
305
|
+
double len = static_cast<double>(self->length);
|
|
306
|
+
if (len == 0) return AnyValue::make_number(-1);
|
|
307
|
+
double n = (args.size() > 1) ? Operators_Private::ToNumber(args[1]) : len - 1;
|
|
308
|
+
double k;
|
|
309
|
+
if (n >= 0) k = std::min(n, len - 1);
|
|
310
|
+
else k = len + n;
|
|
311
|
+
|
|
312
|
+
if (k < 0) return AnyValue::make_number(-1);
|
|
313
|
+
|
|
314
|
+
for (int64_t i = static_cast<int64_t>(k); i >= 0; --i)
|
|
315
|
+
{
|
|
316
|
+
if (self->has_property(std::to_string(i))) {
|
|
317
|
+
AnyValue element = self->get_property(static_cast<uint32_t>(i));
|
|
318
|
+
if (is_strictly_equal_to_primitive(element, searchElement)) return AnyValue::make_number(i);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return AnyValue::make_number(-1); },
|
|
322
|
+
key);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// --- find(callback, thisArg) ---
|
|
326
|
+
if (key == "find")
|
|
327
|
+
{
|
|
328
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
329
|
+
{
|
|
330
|
+
if (args.empty() || !args[0].is_function()) throw Exception::make_exception("callback is not a function", "TypeError");
|
|
331
|
+
auto callback = args[0].as_function();
|
|
332
|
+
auto thisArg = (args.size() > 1) ? args[1] : Constants::UNDEFINED;
|
|
333
|
+
|
|
334
|
+
for (uint64_t i = 0; i < self->length; ++i)
|
|
335
|
+
{
|
|
336
|
+
AnyValue element = self->get_property(static_cast<uint32_t>(i));
|
|
337
|
+
AnyValue kVal = AnyValue::make_number(i);
|
|
338
|
+
const AnyValue cbArgs[] = {element, kVal, thisVal};
|
|
339
|
+
|
|
340
|
+
if (is_truthy(callback->call(thisArg, std::span<const AnyValue>(cbArgs, 3)))) {
|
|
341
|
+
return element;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return AnyValue::make_undefined(); },
|
|
345
|
+
key);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// --- findIndex(callback, thisArg) ---
|
|
349
|
+
if (key == "findIndex")
|
|
350
|
+
{
|
|
351
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
352
|
+
{
|
|
353
|
+
if (args.empty() || !args[0].is_function()) throw Exception::make_exception("callback is not a function", "TypeError");
|
|
354
|
+
auto callback = args[0].as_function();
|
|
355
|
+
auto thisArg = (args.size() > 1) ? args[1] : Constants::UNDEFINED;
|
|
356
|
+
|
|
357
|
+
for (uint64_t i = 0; i < self->length; ++i)
|
|
358
|
+
{
|
|
359
|
+
AnyValue element = self->get_property(static_cast<uint32_t>(i));
|
|
360
|
+
AnyValue kVal = AnyValue::make_number(i);
|
|
361
|
+
const AnyValue cbArgs[] = {element, kVal, thisVal};
|
|
362
|
+
|
|
363
|
+
if (is_truthy(callback->call(thisArg, std::span<const AnyValue>(cbArgs, 3)))) {
|
|
364
|
+
return AnyValue::make_number(i);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return AnyValue::make_number(-1); },
|
|
368
|
+
key);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// --- findLast(callback, thisArg) ---
|
|
372
|
+
if (key == "findLast")
|
|
373
|
+
{
|
|
374
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
375
|
+
{
|
|
376
|
+
if (args.empty() || !args[0].is_function()) throw Exception::make_exception("callback is not a function", "TypeError");
|
|
377
|
+
auto callback = args[0].as_function();
|
|
378
|
+
auto thisArg = (args.size() > 1) ? args[1] : Constants::UNDEFINED;
|
|
379
|
+
|
|
380
|
+
for (int64_t i = self->length - 1; i >= 0; --i)
|
|
381
|
+
{
|
|
382
|
+
AnyValue element = self->get_property(static_cast<uint32_t>(i));
|
|
383
|
+
AnyValue kVal = AnyValue::make_number(i);
|
|
384
|
+
const AnyValue cbArgs[] = {element, kVal, thisVal};
|
|
385
|
+
|
|
386
|
+
if (is_truthy(callback->call(thisArg, std::span<const AnyValue>(cbArgs, 3)))) {
|
|
387
|
+
return element;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
return AnyValue::make_undefined(); },
|
|
391
|
+
key);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// --- findLastIndex(callback, thisArg) ---
|
|
395
|
+
if (key == "findLastIndex")
|
|
396
|
+
{
|
|
397
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
398
|
+
{
|
|
399
|
+
if (args.empty() || !args[0].is_function()) throw Exception::make_exception("callback is not a function", "TypeError");
|
|
400
|
+
auto callback = args[0].as_function();
|
|
401
|
+
auto thisArg = (args.size() > 1) ? args[1] : Constants::UNDEFINED;
|
|
402
|
+
|
|
403
|
+
for (int64_t i = self->length - 1; i >= 0; --i)
|
|
404
|
+
{
|
|
405
|
+
AnyValue element = self->get_property(static_cast<uint32_t>(i));
|
|
406
|
+
AnyValue kVal = AnyValue::make_number(i);
|
|
407
|
+
const AnyValue cbArgs[] = {element, kVal, thisVal};
|
|
408
|
+
|
|
409
|
+
if (is_truthy(callback->call(thisArg, std::span<const AnyValue>(cbArgs, 3)))) {
|
|
410
|
+
return AnyValue::make_number(i);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return AnyValue::make_number(-1); },
|
|
414
|
+
key);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// --- values() ---
|
|
418
|
+
if (key == "values")
|
|
419
|
+
{
|
|
420
|
+
return AnyValue::make_generator([self](const AnyValue &thisVal, std::span<const AnyValue> _) -> jspp::JsIterator<jspp::AnyValue>
|
|
421
|
+
{ return self->get_iterator(); },
|
|
422
|
+
key);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// --- keys() ---
|
|
426
|
+
if (key == "keys")
|
|
427
|
+
{
|
|
428
|
+
return AnyValue::make_generator([self](const AnyValue &thisVal, std::span<const AnyValue> _) -> jspp::JsIterator<jspp::AnyValue>
|
|
429
|
+
{
|
|
430
|
+
// Generator for keys
|
|
431
|
+
for (uint64_t i = 0; i < self->length; ++i) {
|
|
432
|
+
co_yield AnyValue::make_number(i);
|
|
433
|
+
}
|
|
434
|
+
co_return AnyValue::make_undefined(); },
|
|
435
|
+
key);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// --- entries() ---
|
|
439
|
+
if (key == "entries")
|
|
440
|
+
{
|
|
441
|
+
return AnyValue::make_generator([self](const AnyValue &thisVal, std::span<const AnyValue> _) -> jspp::JsIterator<jspp::AnyValue>
|
|
442
|
+
{
|
|
443
|
+
// Generator for [key, value]
|
|
444
|
+
for (uint64_t i = 0; i < self->length; ++i) {
|
|
445
|
+
std::vector<AnyValue> entry;
|
|
446
|
+
entry.push_back(AnyValue::make_number(i));
|
|
447
|
+
entry.push_back(self->get_property(static_cast<uint32_t>(i)));
|
|
448
|
+
co_yield AnyValue::make_array(std::move(entry));
|
|
449
|
+
}
|
|
450
|
+
co_return AnyValue::make_undefined(); },
|
|
451
|
+
key);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// --- map(callback, thisArg) ---
|
|
455
|
+
if (key == "map")
|
|
456
|
+
{
|
|
457
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
458
|
+
{
|
|
459
|
+
if (args.empty() || !args[0].is_function()) throw Exception::make_exception("callback is not a function", "TypeError");
|
|
460
|
+
auto callback = args[0].as_function();
|
|
461
|
+
auto thisArg = (args.size() > 1) ? args[1] : Constants::UNDEFINED;
|
|
462
|
+
|
|
463
|
+
std::vector<AnyValue> result;
|
|
464
|
+
result.reserve(self->length);
|
|
465
|
+
|
|
466
|
+
for (uint64_t i = 0; i < self->length; ++i) {
|
|
467
|
+
if (self->has_property(std::to_string(i))) {
|
|
468
|
+
AnyValue val = self->get_property(static_cast<uint32_t>(i));
|
|
469
|
+
AnyValue kVal = AnyValue::make_number(i);
|
|
470
|
+
const AnyValue cbArgs[] = {val, kVal, thisVal};
|
|
471
|
+
result.push_back(callback->call(thisArg, std::span<const AnyValue>(cbArgs, 3)));
|
|
472
|
+
} else {
|
|
473
|
+
result.push_back(Constants::UNINITIALIZED);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
return AnyValue::make_array(std::move(result)); },
|
|
477
|
+
key);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// --- filter(callback, thisArg) ---
|
|
481
|
+
if (key == "filter")
|
|
482
|
+
{
|
|
483
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
484
|
+
{
|
|
485
|
+
if (args.empty() || !args[0].is_function()) throw Exception::make_exception("callback is not a function", "TypeError");
|
|
486
|
+
auto callback = args[0].as_function();
|
|
487
|
+
auto thisArg = (args.size() > 1) ? args[1] : Constants::UNDEFINED;
|
|
488
|
+
|
|
489
|
+
std::vector<AnyValue> result;
|
|
490
|
+
|
|
491
|
+
for (uint64_t i = 0; i < self->length; ++i) {
|
|
492
|
+
if (self->has_property(std::to_string(i))) {
|
|
493
|
+
AnyValue val = self->get_property(static_cast<uint32_t>(i));
|
|
494
|
+
AnyValue kVal = AnyValue::make_number(i);
|
|
495
|
+
const AnyValue cbArgs[] = {val, kVal, thisVal};
|
|
496
|
+
if (is_truthy(callback->call(thisArg, std::span<const AnyValue>(cbArgs, 3)))) {
|
|
497
|
+
result.push_back(val);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
return AnyValue::make_array(std::move(result)); },
|
|
502
|
+
key);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// --- every(callback, thisArg) ---
|
|
506
|
+
if (key == "every")
|
|
507
|
+
{
|
|
508
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
509
|
+
{
|
|
510
|
+
if (args.empty() || !args[0].is_function()) throw Exception::make_exception("callback is not a function", "TypeError");
|
|
511
|
+
auto callback = args[0].as_function();
|
|
512
|
+
auto thisArg = (args.size() > 1) ? args[1] : Constants::UNDEFINED;
|
|
513
|
+
|
|
514
|
+
for (uint64_t i = 0; i < self->length; ++i) {
|
|
515
|
+
if (self->has_property(std::to_string(i))) {
|
|
516
|
+
AnyValue val = self->get_property(static_cast<uint32_t>(i));
|
|
517
|
+
AnyValue kVal = AnyValue::make_number(i);
|
|
518
|
+
const AnyValue cbArgs[] = {val, kVal, thisVal};
|
|
519
|
+
if (!is_truthy(callback->call(thisArg, std::span<const AnyValue>(cbArgs, 3)))) {
|
|
520
|
+
return AnyValue::make_boolean(false);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
return AnyValue::make_boolean(true); },
|
|
525
|
+
key);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// --- some(callback, thisArg) ---
|
|
529
|
+
if (key == "some")
|
|
530
|
+
{
|
|
531
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
532
|
+
{
|
|
533
|
+
if (args.empty() || !args[0].is_function()) throw Exception::make_exception("callback is not a function", "TypeError");
|
|
534
|
+
auto callback = args[0].as_function();
|
|
535
|
+
auto thisArg = (args.size() > 1) ? args[1] : Constants::UNDEFINED;
|
|
536
|
+
|
|
537
|
+
for (uint64_t i = 0; i < self->length; ++i) {
|
|
538
|
+
if (self->has_property(std::to_string(i))) {
|
|
539
|
+
AnyValue val = self->get_property(static_cast<uint32_t>(i));
|
|
540
|
+
AnyValue kVal = AnyValue::make_number(i);
|
|
541
|
+
const AnyValue cbArgs[] = {val, kVal, thisVal};
|
|
542
|
+
if (is_truthy(callback->call(thisArg, std::span<const AnyValue>(cbArgs, 3)))) {
|
|
543
|
+
return AnyValue::make_boolean(true);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
return AnyValue::make_boolean(false); },
|
|
548
|
+
key);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// --- reduce(callback, initialValue) ---
|
|
552
|
+
if (key == "reduce")
|
|
553
|
+
{
|
|
554
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
555
|
+
{
|
|
556
|
+
if (args.empty() || !args[0].is_function()) throw Exception::make_exception("callback is not a function", "TypeError");
|
|
557
|
+
auto callback = args[0].as_function();
|
|
558
|
+
|
|
559
|
+
uint64_t i = 0;
|
|
560
|
+
AnyValue accumulator;
|
|
561
|
+
|
|
562
|
+
if (args.size() > 1) {
|
|
563
|
+
accumulator = args[1];
|
|
564
|
+
} else {
|
|
565
|
+
if (self->length == 0) throw Exception::make_exception("Reduce of empty array with no initial value", "TypeError");
|
|
566
|
+
bool found = false;
|
|
567
|
+
for (; i < self->length; ++i) {
|
|
568
|
+
if (self->has_property(std::to_string(i))) {
|
|
569
|
+
accumulator = self->get_property(static_cast<uint32_t>(i));
|
|
570
|
+
found = true;
|
|
571
|
+
i++;
|
|
572
|
+
break;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
if (!found) throw Exception::make_exception("Reduce of empty array with no initial value", "TypeError");
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
for (; i < self->length; ++i) {
|
|
579
|
+
if (self->has_property(std::to_string(i))) {
|
|
580
|
+
AnyValue val = self->get_property(static_cast<uint32_t>(i));
|
|
581
|
+
AnyValue kVal = AnyValue::make_number(i);
|
|
582
|
+
const AnyValue cbArgs[] = {accumulator, val, kVal, thisVal};
|
|
583
|
+
accumulator = callback->call(Constants::UNDEFINED, std::span<const AnyValue>(cbArgs, 4));
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
return accumulator; },
|
|
587
|
+
key);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// --- reduceRight(callback, initialValue) ---
|
|
591
|
+
if (key == "reduceRight")
|
|
592
|
+
{
|
|
593
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
594
|
+
{
|
|
595
|
+
if (args.empty() || !args[0].is_function()) throw Exception::make_exception("callback is not a function", "TypeError");
|
|
596
|
+
auto callback = args[0].as_function();
|
|
597
|
+
|
|
598
|
+
int64_t i = self->length - 1;
|
|
599
|
+
AnyValue accumulator;
|
|
600
|
+
|
|
601
|
+
if (args.size() > 1) {
|
|
602
|
+
accumulator = args[1];
|
|
603
|
+
} else {
|
|
604
|
+
if (self->length == 0) throw Exception::make_exception("Reduce of empty array with no initial value", "TypeError");
|
|
605
|
+
bool found = false;
|
|
606
|
+
for (; i >= 0; --i) {
|
|
607
|
+
if (self->has_property(std::to_string(i))) {
|
|
608
|
+
accumulator = self->get_property(static_cast<uint32_t>(i));
|
|
609
|
+
found = true;
|
|
610
|
+
i--;
|
|
611
|
+
break;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
if (!found) throw Exception::make_exception("Reduce of empty array with no initial value", "TypeError");
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
for (; i >= 0; --i) {
|
|
618
|
+
if (self->has_property(std::to_string(i))) {
|
|
619
|
+
AnyValue val = self->get_property(static_cast<uint32_t>(i));
|
|
620
|
+
AnyValue kVal = AnyValue::make_number(i);
|
|
621
|
+
const AnyValue cbArgs[] = {accumulator, val, kVal, thisVal};
|
|
622
|
+
accumulator = callback->call(Constants::UNDEFINED, std::span<const AnyValue>(cbArgs, 4));
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
return accumulator; },
|
|
626
|
+
key);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
// --- flat(depth) ---
|
|
630
|
+
if (key == "flat")
|
|
631
|
+
{
|
|
632
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
633
|
+
{
|
|
634
|
+
double depthVal = (args.size() > 0 && !args[0].is_undefined()) ? Operators_Private::ToNumber(args[0]) : 1;
|
|
635
|
+
int depth = static_cast<int>(depthVal);
|
|
636
|
+
if (depth < 0) depth = 0;
|
|
637
|
+
|
|
638
|
+
std::vector<AnyValue> result;
|
|
639
|
+
std::function<void(const AnyValue&, int)> flatten;
|
|
640
|
+
flatten = [&result, &flatten](const AnyValue& item, int d) {
|
|
641
|
+
if (d > 0 && item.is_array()) {
|
|
642
|
+
auto arr = item.as_array();
|
|
643
|
+
for (uint64_t i = 0; i < arr->length; ++i) {
|
|
644
|
+
if (arr->has_property(std::to_string(i))) {
|
|
645
|
+
flatten(arr->get_property(static_cast<uint32_t>(i)), d - 1);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
} else {
|
|
649
|
+
result.push_back(item);
|
|
650
|
+
}
|
|
651
|
+
};
|
|
652
|
+
|
|
653
|
+
for (uint64_t i = 0; i < self->length; ++i) {
|
|
654
|
+
if (self->has_property(std::to_string(i))) {
|
|
655
|
+
flatten(self->get_property(static_cast<uint32_t>(i)), depth);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
return AnyValue::make_array(std::move(result)); },
|
|
659
|
+
key);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
// --- flatMap(callback, thisArg) ---
|
|
663
|
+
if (key == "flatMap")
|
|
664
|
+
{
|
|
665
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
666
|
+
{
|
|
667
|
+
if (args.empty() || !args[0].is_function()) throw Exception::make_exception("callback is not a function", "TypeError");
|
|
668
|
+
auto callback = args[0].as_function();
|
|
669
|
+
auto thisArg = (args.size() > 1) ? args[1] : Constants::UNDEFINED;
|
|
670
|
+
|
|
671
|
+
std::vector<AnyValue> result;
|
|
672
|
+
|
|
673
|
+
for (uint64_t i = 0; i < self->length; ++i) {
|
|
674
|
+
if (self->has_property(std::to_string(i))) {
|
|
675
|
+
AnyValue val = self->get_property(static_cast<uint32_t>(i));
|
|
676
|
+
AnyValue kVal = AnyValue::make_number(i);
|
|
677
|
+
const AnyValue cbArgs[] = {val, kVal, thisVal};
|
|
678
|
+
AnyValue mapped = callback->call(thisArg, std::span<const AnyValue>(cbArgs, 3));
|
|
679
|
+
|
|
680
|
+
if (mapped.is_array()) {
|
|
681
|
+
auto arr = mapped.as_array();
|
|
682
|
+
for (uint64_t j = 0; j < arr->length; ++j) {
|
|
683
|
+
if (arr->has_property(std::to_string(j))) {
|
|
684
|
+
result.push_back(arr->get_property(static_cast<uint32_t>(j)));
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
} else {
|
|
688
|
+
result.push_back(mapped);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
return AnyValue::make_array(std::move(result)); },
|
|
693
|
+
key);
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// --- fill(value, start, end) ---
|
|
697
|
+
if (key == "fill")
|
|
698
|
+
{
|
|
699
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
700
|
+
{
|
|
701
|
+
AnyValue value = args.empty() ? AnyValue::make_undefined() : args[0];
|
|
702
|
+
double len = static_cast<double>(self->length);
|
|
703
|
+
double start = (args.size() > 1) ? Operators_Private::ToNumber(args[1]) : 0;
|
|
704
|
+
double end = (args.size() > 2 && !args[2].is_undefined()) ? Operators_Private::ToNumber(args[2]) : len;
|
|
705
|
+
|
|
706
|
+
double k;
|
|
707
|
+
if (start >= 0) k = start; else k = len + start;
|
|
708
|
+
if (k < 0) k = 0;
|
|
709
|
+
|
|
710
|
+
double final;
|
|
711
|
+
if (end >= 0) final = end; else final = len + end;
|
|
712
|
+
if (final > len) final = len;
|
|
713
|
+
|
|
714
|
+
for (uint64_t i = static_cast<uint64_t>(k); i < static_cast<uint64_t>(final); ++i) {
|
|
715
|
+
self->set_property(static_cast<uint32_t>(i), value);
|
|
716
|
+
}
|
|
717
|
+
return thisVal; },
|
|
718
|
+
key);
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
// --- reverse() ---
|
|
722
|
+
if (key == "reverse")
|
|
723
|
+
{
|
|
724
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
725
|
+
{
|
|
726
|
+
uint64_t len = self->length;
|
|
727
|
+
for (uint64_t i = 0; i < len / 2; ++i) {
|
|
728
|
+
uint64_t j = len - 1 - i;
|
|
729
|
+
bool hasI = self->has_property(std::to_string(i));
|
|
730
|
+
bool hasJ = self->has_property(std::to_string(j));
|
|
731
|
+
|
|
732
|
+
if (hasI && hasJ) {
|
|
733
|
+
AnyValue valI = self->get_property(static_cast<uint32_t>(i));
|
|
734
|
+
AnyValue valJ = self->get_property(static_cast<uint32_t>(j));
|
|
735
|
+
self->set_property(static_cast<uint32_t>(i), valJ);
|
|
736
|
+
self->set_property(static_cast<uint32_t>(j), valI);
|
|
737
|
+
} else if (hasI && !hasJ) {
|
|
738
|
+
AnyValue valI = self->get_property(static_cast<uint32_t>(i));
|
|
739
|
+
self->set_property(static_cast<uint32_t>(j), valI);
|
|
740
|
+
if (i < self->dense.size()) self->dense[i] = Constants::UNINITIALIZED;
|
|
741
|
+
else self->sparse.erase(static_cast<uint32_t>(i));
|
|
742
|
+
} else if (!hasI && hasJ) {
|
|
743
|
+
AnyValue valJ = self->get_property(static_cast<uint32_t>(j));
|
|
744
|
+
self->set_property(static_cast<uint32_t>(i), valJ);
|
|
745
|
+
if (j < self->dense.size()) self->dense[j] = Constants::UNINITIALIZED;
|
|
746
|
+
else self->sparse.erase(static_cast<uint32_t>(j));
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
return thisVal; },
|
|
750
|
+
key);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
// --- sort(compareFn) ---
|
|
754
|
+
if (key == "sort")
|
|
755
|
+
{
|
|
756
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
757
|
+
{
|
|
758
|
+
AnyValue compareFn = args.empty() ? AnyValue::make_undefined() : args[0];
|
|
759
|
+
|
|
760
|
+
std::vector<AnyValue> items;
|
|
761
|
+
for (uint64_t i = 0; i < self->length; ++i) {
|
|
762
|
+
if (self->has_property(std::to_string(i))) {
|
|
763
|
+
items.push_back(self->get_property(static_cast<uint32_t>(i)));
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
std::sort(items.begin(), items.end(), [&](const AnyValue& a, const AnyValue& b) {
|
|
768
|
+
if (a.is_undefined() && b.is_undefined()) return false;
|
|
769
|
+
if (a.is_undefined()) return false;
|
|
770
|
+
if (b.is_undefined()) return true;
|
|
771
|
+
|
|
772
|
+
if (compareFn.is_function()) {
|
|
773
|
+
const AnyValue cmpArgs[] = {a, b};
|
|
774
|
+
double res = Operators_Private::ToNumber(compareFn.call(Constants::UNDEFINED, std::span<const AnyValue>(cmpArgs, 2)));
|
|
775
|
+
return res < 0;
|
|
776
|
+
} else {
|
|
777
|
+
std::string sA = a.to_std_string();
|
|
778
|
+
std::string sB = b.to_std_string();
|
|
779
|
+
return sA < sB;
|
|
780
|
+
}
|
|
781
|
+
});
|
|
782
|
+
|
|
783
|
+
for (uint64_t i = 0; i < items.size(); ++i) {
|
|
784
|
+
self->set_property(static_cast<uint32_t>(i), items[i]);
|
|
785
|
+
}
|
|
786
|
+
for (uint64_t i = items.size(); i < self->length; ++i) {
|
|
787
|
+
if (i < self->dense.size()) self->dense[i] = Constants::UNINITIALIZED;
|
|
788
|
+
else self->sparse.erase(static_cast<uint32_t>(i));
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
return thisVal; },
|
|
792
|
+
key);
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// --- splice(start, deleteCount, ...items) ---
|
|
796
|
+
if (key == "splice")
|
|
797
|
+
{
|
|
798
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
799
|
+
{
|
|
800
|
+
double len = static_cast<double>(self->length);
|
|
801
|
+
double start = args.empty() ? 0 : Operators_Private::ToNumber(args[0]);
|
|
802
|
+
double actualStart = (start < 0) ? std::max(len + start, 0.0) : std::min(start, len);
|
|
803
|
+
|
|
804
|
+
uint64_t startIdx = static_cast<uint64_t>(actualStart);
|
|
805
|
+
uint64_t deleteCount = 0;
|
|
806
|
+
if (args.size() >= 2) {
|
|
807
|
+
double dc = Operators_Private::ToNumber(args[1]);
|
|
808
|
+
deleteCount = static_cast<uint64_t>(std::max(0.0, std::min(dc, len - startIdx)));
|
|
809
|
+
} else if (args.size() == 1) {
|
|
810
|
+
deleteCount = len - startIdx;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
std::vector<AnyValue> deletedItems;
|
|
814
|
+
for (uint64_t i = 0; i < deleteCount; ++i) {
|
|
815
|
+
if (self->has_property(std::to_string(startIdx + i))) {
|
|
816
|
+
deletedItems.push_back(self->get_property(static_cast<uint32_t>(startIdx + i)));
|
|
817
|
+
} else {
|
|
818
|
+
deletedItems.push_back(Constants::UNINITIALIZED);
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
std::vector<AnyValue> insertItems;
|
|
823
|
+
for (size_t i = 2; i < args.size(); ++i) {
|
|
824
|
+
insertItems.push_back(args[i]);
|
|
825
|
+
}
|
|
826
|
+
uint64_t insertCount = insertItems.size();
|
|
827
|
+
|
|
828
|
+
if (insertCount < deleteCount) {
|
|
829
|
+
for (uint64_t i = startIdx; i < len - deleteCount; ++i) {
|
|
830
|
+
uint64_t from = i + deleteCount;
|
|
831
|
+
uint64_t to = i + insertCount;
|
|
832
|
+
if (self->has_property(std::to_string(from))) {
|
|
833
|
+
self->set_property(static_cast<uint32_t>(to), self->get_property(static_cast<uint32_t>(from)));
|
|
834
|
+
} else {
|
|
835
|
+
if (to < self->dense.size()) self->dense[to] = Constants::UNINITIALIZED;
|
|
836
|
+
else self->sparse.erase(static_cast<uint32_t>(to));
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
for (uint64_t i = len; i > len - deleteCount + insertCount; --i) {
|
|
840
|
+
uint64_t idx = i - 1;
|
|
841
|
+
if (idx < self->dense.size()) self->dense[idx] = Constants::UNINITIALIZED;
|
|
842
|
+
else self->sparse.erase(static_cast<uint32_t>(idx));
|
|
843
|
+
}
|
|
844
|
+
} else if (insertCount > deleteCount) {
|
|
845
|
+
for (uint64_t i = len; i > startIdx + deleteCount; --i) {
|
|
846
|
+
uint64_t from = i - 1;
|
|
847
|
+
uint64_t to = from - deleteCount + insertCount;
|
|
848
|
+
if (self->has_property(std::to_string(from))) {
|
|
849
|
+
self->set_property(static_cast<uint32_t>(to), self->get_property(static_cast<uint32_t>(from)));
|
|
850
|
+
} else {
|
|
851
|
+
if (to < self->dense.size()) self->dense[to] = Constants::UNINITIALIZED;
|
|
852
|
+
else self->sparse.erase(static_cast<uint32_t>(to));
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
for (uint64_t i = 0; i < insertCount; ++i) {
|
|
858
|
+
self->set_property(static_cast<uint32_t>(startIdx + i), insertItems[i]);
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
self->length = len - deleteCount + insertCount;
|
|
862
|
+
return AnyValue::make_array(std::move(deletedItems)); },
|
|
863
|
+
key);
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// --- copyWithin(target, start, end) ---
|
|
867
|
+
if (key == "copyWithin")
|
|
868
|
+
{
|
|
869
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
870
|
+
{
|
|
871
|
+
double len = static_cast<double>(self->length);
|
|
872
|
+
double target = args.empty() ? 0 : Operators_Private::ToNumber(args[0]);
|
|
873
|
+
double start = (args.size() > 1) ? Operators_Private::ToNumber(args[1]) : 0;
|
|
874
|
+
double end = (args.size() > 2 && !args[2].is_undefined()) ? Operators_Private::ToNumber(args[2]) : len;
|
|
875
|
+
|
|
876
|
+
double to;
|
|
877
|
+
if (target >= 0) to = target; else to = len + target;
|
|
878
|
+
if (to < 0) to = 0; else if (to > len) to = len;
|
|
879
|
+
|
|
880
|
+
double from;
|
|
881
|
+
if (start >= 0) from = start; else from = len + start;
|
|
882
|
+
if (from < 0) from = 0; else if (from > len) from = len;
|
|
883
|
+
|
|
884
|
+
double final;
|
|
885
|
+
if (end >= 0) final = end; else final = len + end;
|
|
886
|
+
if (final < 0) final = 0; else if (final > len) final = len;
|
|
887
|
+
|
|
888
|
+
double count = std::min(final - from, len - to);
|
|
889
|
+
|
|
890
|
+
if (from < to && to < from + count) {
|
|
891
|
+
for (double i = count - 1; i >= 0; --i) {
|
|
892
|
+
uint64_t f = static_cast<uint64_t>(from + i);
|
|
893
|
+
uint64_t t = static_cast<uint64_t>(to + i);
|
|
894
|
+
if (self->has_property(std::to_string(f))) {
|
|
895
|
+
self->set_property(static_cast<uint32_t>(t), self->get_property(static_cast<uint32_t>(f)));
|
|
896
|
+
} else {
|
|
897
|
+
if (t < self->dense.size()) self->dense[t] = Constants::UNINITIALIZED;
|
|
898
|
+
else self->sparse.erase(static_cast<uint32_t>(t));
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
} else {
|
|
902
|
+
for (double i = 0; i < count; ++i) {
|
|
903
|
+
uint64_t f = static_cast<uint64_t>(from + i);
|
|
904
|
+
uint64_t t = static_cast<uint64_t>(to + i);
|
|
905
|
+
if (self->has_property(std::to_string(f))) {
|
|
906
|
+
self->set_property(static_cast<uint32_t>(t), self->get_property(static_cast<uint32_t>(f)));
|
|
907
|
+
} else {
|
|
908
|
+
if (t < self->dense.size()) self->dense[t] = Constants::UNINITIALIZED;
|
|
909
|
+
else self->sparse.erase(static_cast<uint32_t>(t));
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
return thisVal; },
|
|
914
|
+
key);
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
// --- concat(...items) ---
|
|
918
|
+
if (key == "concat")
|
|
919
|
+
{
|
|
920
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
921
|
+
{
|
|
922
|
+
std::vector<AnyValue> result;
|
|
923
|
+
for (uint64_t i = 0; i < self->length; ++i) {
|
|
924
|
+
if (self->has_property(std::to_string(i))) {
|
|
925
|
+
result.push_back(self->get_property(static_cast<uint32_t>(i)));
|
|
926
|
+
} else {
|
|
927
|
+
result.push_back(Constants::UNINITIALIZED);
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
for (const auto& item : args) {
|
|
932
|
+
bool spreadable = false;
|
|
933
|
+
if (item.is_array()) {
|
|
934
|
+
spreadable = true;
|
|
935
|
+
auto sym = WellKnownSymbols::isConcatSpreadable;
|
|
936
|
+
if (item.has_property(sym->key)) {
|
|
937
|
+
spreadable = is_truthy(item.get_property_with_receiver(sym->key, item));
|
|
938
|
+
}
|
|
939
|
+
} else if (item.is_object()) {
|
|
940
|
+
auto sym = WellKnownSymbols::isConcatSpreadable;
|
|
941
|
+
if (item.has_property(sym->key)) {
|
|
942
|
+
spreadable = is_truthy(item.get_property_with_receiver(sym->key, item));
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
if (spreadable && item.is_array()) {
|
|
947
|
+
auto arr = item.as_array();
|
|
948
|
+
for (uint64_t i = 0; i < arr->length; ++i) {
|
|
949
|
+
if (arr->has_property(std::to_string(i))) {
|
|
950
|
+
result.push_back(arr->get_property(static_cast<uint32_t>(i)));
|
|
951
|
+
} else {
|
|
952
|
+
result.push_back(Constants::UNINITIALIZED);
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
} else {
|
|
956
|
+
result.push_back(item);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
return AnyValue::make_array(std::move(result)); },
|
|
960
|
+
key);
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
// --- slice(start, end) ---
|
|
964
|
+
if (key == "slice")
|
|
965
|
+
{
|
|
966
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
967
|
+
{
|
|
968
|
+
double len = static_cast<double>(self->length);
|
|
969
|
+
double start = args.empty() ? 0 : Operators_Private::ToNumber(args[0]);
|
|
970
|
+
double end = (args.size() < 2 || args[1].is_undefined()) ? len : Operators_Private::ToNumber(args[1]);
|
|
971
|
+
|
|
972
|
+
double k;
|
|
973
|
+
if (start >= 0) k = start; else k = len + start;
|
|
974
|
+
if (k < 0) k = 0;
|
|
975
|
+
|
|
976
|
+
double final;
|
|
977
|
+
if (end >= 0) final = end; else final = len + end;
|
|
978
|
+
if (final > len) final = len;
|
|
979
|
+
|
|
980
|
+
if (final < k) final = k;
|
|
981
|
+
|
|
982
|
+
std::vector<AnyValue> result;
|
|
983
|
+
for (uint64_t i = static_cast<uint64_t>(k); i < static_cast<uint64_t>(final); ++i) {
|
|
984
|
+
if (self->has_property(std::to_string(i))) {
|
|
985
|
+
result.push_back(self->get_property(static_cast<uint32_t>(i)));
|
|
986
|
+
} else {
|
|
987
|
+
result.push_back(Constants::UNINITIALIZED);
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
return AnyValue::make_array(std::move(result)); },
|
|
991
|
+
key);
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
// --- toReversed() ---
|
|
995
|
+
if (key == "toReversed")
|
|
996
|
+
{
|
|
997
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
998
|
+
{
|
|
999
|
+
auto copy = self->get_property("slice", thisVal).call(thisVal, {});
|
|
1000
|
+
copy.get_own_property("reverse").call(copy, {});
|
|
1001
|
+
return copy; },
|
|
1002
|
+
key);
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
// --- toSorted(compareFn) ---
|
|
1006
|
+
if (key == "toSorted")
|
|
1007
|
+
{
|
|
1008
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
1009
|
+
{
|
|
1010
|
+
auto copy = self->get_property("slice", thisVal).call(thisVal, {});
|
|
1011
|
+
copy.get_own_property("sort").call(copy, args);
|
|
1012
|
+
return copy; },
|
|
1013
|
+
key);
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
// --- toSpliced(start, deleteCount, ...items) ---
|
|
1017
|
+
if (key == "toSpliced")
|
|
1018
|
+
{
|
|
1019
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
1020
|
+
{
|
|
1021
|
+
auto copy = self->get_property("slice", thisVal).call(thisVal, {});
|
|
1022
|
+
copy.get_own_property("splice").call(copy, args);
|
|
1023
|
+
return copy; },
|
|
1024
|
+
key);
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
// --- with(index, value) ---
|
|
1028
|
+
if (key == "with")
|
|
1029
|
+
{
|
|
1030
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
1031
|
+
{
|
|
1032
|
+
auto copy = self->get_property("slice", thisVal).call(thisVal, {});
|
|
1033
|
+
|
|
1034
|
+
double len = static_cast<double>(self->length);
|
|
1035
|
+
double idx = args.empty() ? 0 : Operators_Private::ToNumber(args[0]);
|
|
1036
|
+
double k;
|
|
1037
|
+
if (idx >= 0) k = idx; else k = len + idx;
|
|
1038
|
+
|
|
1039
|
+
if (k < 0 || k >= len) throw Exception::make_exception("Invalid index", "RangeError");
|
|
1040
|
+
|
|
1041
|
+
AnyValue value = (args.size() > 1) ? args[1] : Constants::UNDEFINED;
|
|
1042
|
+
copy.set_own_property(static_cast<uint32_t>(k), value);
|
|
1043
|
+
return copy; },
|
|
1044
|
+
key);
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
// --- toLocaleString() ---
|
|
1048
|
+
if (key == "toLocaleString")
|
|
1049
|
+
{
|
|
1050
|
+
return AnyValue::make_function([self](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
1051
|
+
{
|
|
1052
|
+
std::string result = "";
|
|
1053
|
+
for (uint64_t i = 0; i < self->length; ++i) {
|
|
1054
|
+
if (i > 0) result += ",";
|
|
1055
|
+
AnyValue element = self->get_property(static_cast<uint32_t>(i));
|
|
1056
|
+
if (!element.is_null() && !element.is_undefined()) {
|
|
1057
|
+
if (element.has_property("toLocaleString")) {
|
|
1058
|
+
auto fn = element.get_property_with_receiver("toLocaleString", element);
|
|
1059
|
+
if (fn.is_function()) {
|
|
1060
|
+
result += fn.call(element, {}).to_std_string();
|
|
1061
|
+
continue;
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
result += element.to_std_string();
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
return AnyValue::make_string(result); },
|
|
1068
|
+
key);
|
|
1069
|
+
}
|
|
1070
|
+
|
|
232
1071
|
return std::nullopt;
|
|
233
1072
|
}
|
|
234
1073
|
}
|