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