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