@ugo-studio/jspp 0.2.5 → 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/README.md +51 -36
- package/dist/analysis/scope.js +7 -0
- package/dist/analysis/typeAnalyzer.js +96 -43
- package/dist/ast/symbols.js +34 -24
- package/dist/cli/args.js +59 -0
- package/dist/cli/colors.js +9 -0
- package/dist/cli/file-utils.js +20 -0
- package/dist/cli/index.js +160 -0
- package/dist/cli/spinner.js +55 -0
- package/dist/core/codegen/class-handlers.js +8 -8
- package/dist/core/codegen/control-flow-handlers.js +19 -9
- package/dist/core/codegen/declaration-handlers.js +30 -10
- package/dist/core/codegen/expression-handlers.js +649 -161
- package/dist/core/codegen/function-handlers.js +107 -103
- package/dist/core/codegen/helpers.js +61 -14
- package/dist/core/codegen/index.js +13 -9
- package/dist/core/codegen/literal-handlers.js +4 -2
- package/dist/core/codegen/statement-handlers.js +147 -55
- package/dist/core/codegen/visitor.js +22 -2
- package/dist/core/constants.js +16 -0
- package/dist/core/error.js +58 -0
- package/dist/index.js +6 -3
- package/package.json +3 -3
- 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/scheduler.hpp +144 -144
- 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/object.hpp +12 -10
- 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
|
@@ -14,353 +14,529 @@ namespace jspp
|
|
|
14
14
|
{
|
|
15
15
|
namespace StringPrototypes
|
|
16
16
|
{
|
|
17
|
+
inline AnyValue &get_toString_fn()
|
|
18
|
+
{
|
|
19
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
20
|
+
{ return AnyValue::make_string(thisVal.as_string()->value); },
|
|
21
|
+
"toString");
|
|
22
|
+
return fn;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
inline AnyValue &get_iterator_fn()
|
|
26
|
+
{
|
|
27
|
+
static AnyValue fn = AnyValue::make_generator([](const AnyValue &thisVal, std::span<const AnyValue> _) -> AnyValue
|
|
28
|
+
{ return AnyValue::from_iterator(thisVal.as_string()->get_iterator()); },
|
|
29
|
+
"Symbol.iterator");
|
|
30
|
+
return fn;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
inline AnyValue &get_length_desc()
|
|
34
|
+
{
|
|
35
|
+
static auto getter = [](const AnyValue &thisVal, std::span<const AnyValue>) -> AnyValue
|
|
36
|
+
{ return AnyValue::make_number(thisVal.as_string()->value.length()); };
|
|
37
|
+
static auto setter = [](const AnyValue &thisVal, std::span<const AnyValue>) -> AnyValue
|
|
38
|
+
{ return Constants::UNDEFINED; };
|
|
39
|
+
static AnyValue desc = AnyValue::make_accessor_descriptor(getter, setter, false, false);
|
|
40
|
+
return desc;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
inline AnyValue &get_charAt_fn()
|
|
44
|
+
{
|
|
45
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
46
|
+
{
|
|
47
|
+
auto self = thisVal.as_string();
|
|
48
|
+
double pos = args.empty() ? 0 : Operators_Private::ToNumber(args[0]);
|
|
49
|
+
int index = static_cast<int>(pos);
|
|
50
|
+
if (index < 0 || index >= self->value.length())
|
|
51
|
+
{
|
|
52
|
+
return AnyValue::make_string("");
|
|
53
|
+
}
|
|
54
|
+
return AnyValue::make_string(std::string(1, self->value[index])); },
|
|
55
|
+
"charAt");
|
|
56
|
+
return fn;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
inline AnyValue &get_concat_fn()
|
|
60
|
+
{
|
|
61
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
62
|
+
{
|
|
63
|
+
std::string result = thisVal.as_string()->value;
|
|
64
|
+
for (const auto &arg : args)
|
|
65
|
+
{
|
|
66
|
+
result += arg.to_std_string();
|
|
67
|
+
}
|
|
68
|
+
return AnyValue::make_string(result); },
|
|
69
|
+
"concat");
|
|
70
|
+
return fn;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
inline AnyValue &get_endsWith_fn()
|
|
74
|
+
{
|
|
75
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
76
|
+
{
|
|
77
|
+
auto self = thisVal.as_string();
|
|
78
|
+
if (args.empty())
|
|
79
|
+
return Constants::FALSE;
|
|
80
|
+
std::string search = args[0].to_std_string();
|
|
81
|
+
size_t end_pos = (args.size() > 1 && !args[1].is_undefined()) ? static_cast<size_t>(Operators_Private::ToNumber(args[1])) : self->value.length();
|
|
82
|
+
|
|
83
|
+
if (end_pos > self->value.length())
|
|
84
|
+
end_pos = self->value.length();
|
|
85
|
+
if (search.length() > end_pos)
|
|
86
|
+
return Constants::FALSE;
|
|
87
|
+
|
|
88
|
+
return AnyValue::make_boolean(self->value.substr(end_pos - search.length(), search.length()) == search); },
|
|
89
|
+
"endsWith");
|
|
90
|
+
return fn;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
inline AnyValue &get_includes_fn()
|
|
94
|
+
{
|
|
95
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
96
|
+
{
|
|
97
|
+
auto self = thisVal.as_string();
|
|
98
|
+
if (args.empty())
|
|
99
|
+
return Constants::FALSE;
|
|
100
|
+
std::string search = args[0].to_std_string();
|
|
101
|
+
size_t pos = (args.size() > 1) ? static_cast<size_t>(Operators_Private::ToNumber(args[1])) : 0;
|
|
102
|
+
|
|
103
|
+
return AnyValue::make_boolean(self->value.find(search, pos) != std::string::npos); },
|
|
104
|
+
"includes");
|
|
105
|
+
return fn;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
inline AnyValue &get_indexOf_fn()
|
|
109
|
+
{
|
|
110
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
111
|
+
{
|
|
112
|
+
auto self = thisVal.as_string();
|
|
113
|
+
if (args.empty())
|
|
114
|
+
return AnyValue::make_number(-1);
|
|
115
|
+
std::string search = args[0].to_std_string();
|
|
116
|
+
size_t pos = (args.size() > 1) ? static_cast<size_t>(Operators_Private::ToNumber(args[1])) : 0;
|
|
117
|
+
size_t result = self->value.find(search, pos);
|
|
118
|
+
return result == std::string::npos ? AnyValue::make_number(-1) : AnyValue::make_number(result); },
|
|
119
|
+
"indexOf");
|
|
120
|
+
return fn;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
inline AnyValue &get_lastIndexOf_fn()
|
|
124
|
+
{
|
|
125
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
126
|
+
{
|
|
127
|
+
auto self = thisVal.as_string();
|
|
128
|
+
if (args.empty())
|
|
129
|
+
return AnyValue::make_number(-1);
|
|
130
|
+
std::string search = args[0].to_std_string();
|
|
131
|
+
size_t pos = (args.size() > 1 && !args[1].is_undefined()) ? static_cast<size_t>(Operators_Private::ToNumber(args[1])) : std::string::npos;
|
|
132
|
+
size_t result = self->value.rfind(search, pos);
|
|
133
|
+
return result == std::string::npos ? AnyValue::make_number(-1) : AnyValue::make_number(result); },
|
|
134
|
+
"lastIndexOf");
|
|
135
|
+
return fn;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
inline AnyValue &get_padEnd_fn()
|
|
139
|
+
{
|
|
140
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
141
|
+
{
|
|
142
|
+
auto self = thisVal.as_string();
|
|
143
|
+
size_t target_length = args.empty() ? 0 : static_cast<size_t>(Operators_Private::ToNumber(args[0]));
|
|
144
|
+
if (self->value.length() >= target_length)
|
|
145
|
+
return AnyValue::make_string(self->value);
|
|
146
|
+
std::string pad_string = (args.size() > 1 && !args[1].is_undefined() && !args[1].to_std_string().empty()) ? args[1].to_std_string() : " ";
|
|
147
|
+
std::string result = self->value;
|
|
148
|
+
while (result.length() < target_length)
|
|
149
|
+
{
|
|
150
|
+
result += pad_string;
|
|
151
|
+
}
|
|
152
|
+
return AnyValue::make_string(result.substr(0, target_length)); },
|
|
153
|
+
"padEnd");
|
|
154
|
+
return fn;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
inline AnyValue &get_padStart_fn()
|
|
158
|
+
{
|
|
159
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
160
|
+
{
|
|
161
|
+
auto self = thisVal.as_string();
|
|
162
|
+
size_t target_length = args.empty() ? 0 : static_cast<size_t>(Operators_Private::ToNumber(args[0]));
|
|
163
|
+
if (self->value.length() >= target_length)
|
|
164
|
+
return AnyValue::make_string(self->value);
|
|
165
|
+
std::string pad_string = (args.size() > 1 && !args[1].is_undefined() && !args[1].to_std_string().empty()) ? args[1].to_std_string() : " ";
|
|
166
|
+
std::string padding;
|
|
167
|
+
while (padding.length() < target_length - self->value.length())
|
|
168
|
+
{
|
|
169
|
+
padding += pad_string;
|
|
170
|
+
}
|
|
171
|
+
return AnyValue::make_string(padding.substr(0, target_length - self->value.length()) + self->value); },
|
|
172
|
+
"padStart");
|
|
173
|
+
return fn;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
inline AnyValue &get_repeat_fn()
|
|
177
|
+
{
|
|
178
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
179
|
+
{
|
|
180
|
+
auto self = thisVal.as_string();
|
|
181
|
+
double count = args.empty() ? 0 : Operators_Private::ToNumber(args[0]);
|
|
182
|
+
if (count < 0)
|
|
183
|
+
{
|
|
184
|
+
// In a real implementation, this should throw a RangeError.
|
|
185
|
+
return AnyValue::make_string("");
|
|
186
|
+
}
|
|
187
|
+
std::string result = "";
|
|
188
|
+
for (int i = 0; i < count; ++i)
|
|
189
|
+
{
|
|
190
|
+
result += self->value;
|
|
191
|
+
}
|
|
192
|
+
return AnyValue::make_string(result); },
|
|
193
|
+
"repeat");
|
|
194
|
+
return fn;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
inline AnyValue &get_replace_fn()
|
|
198
|
+
{
|
|
199
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
200
|
+
{
|
|
201
|
+
auto self = thisVal.as_string();
|
|
202
|
+
if (args.size() < 2)
|
|
203
|
+
return AnyValue::make_string(self->value);
|
|
204
|
+
std::string search = args[0].to_std_string();
|
|
205
|
+
std::string replacement = args[1].to_std_string();
|
|
206
|
+
std::string result = self->value;
|
|
207
|
+
size_t pos = result.find(search);
|
|
208
|
+
if (pos != std::string::npos)
|
|
209
|
+
{
|
|
210
|
+
result.replace(pos, search.length(), replacement);
|
|
211
|
+
}
|
|
212
|
+
return AnyValue::make_string(result); },
|
|
213
|
+
"replace");
|
|
214
|
+
return fn;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
inline AnyValue &get_replaceAll_fn()
|
|
218
|
+
{
|
|
219
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
220
|
+
{
|
|
221
|
+
auto self = thisVal.as_string();
|
|
222
|
+
if (args.size() < 2)
|
|
223
|
+
return AnyValue::make_string(self->value);
|
|
224
|
+
std::string search = args[0].to_std_string();
|
|
225
|
+
if (search.empty())
|
|
226
|
+
return AnyValue::make_string(self->value);
|
|
227
|
+
std::string replacement = args[1].to_std_string();
|
|
228
|
+
std::string result = self->value;
|
|
229
|
+
size_t pos = result.find(search);
|
|
230
|
+
while (pos != std::string::npos)
|
|
231
|
+
{
|
|
232
|
+
result.replace(pos, search.length(), replacement);
|
|
233
|
+
pos = result.find(search, pos + replacement.length());
|
|
234
|
+
}
|
|
235
|
+
return AnyValue::make_string(result); },
|
|
236
|
+
"replaceAll");
|
|
237
|
+
return fn;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
inline AnyValue &get_slice_fn()
|
|
241
|
+
{
|
|
242
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
243
|
+
{
|
|
244
|
+
auto self = thisVal.as_string();
|
|
245
|
+
int len = self->value.length();
|
|
246
|
+
int start = args.empty() ? 0 : Operators_Private::ToInt32(args[0]);
|
|
247
|
+
int end = (args.size() < 2 || args[1].is_undefined()) ? len : Operators_Private::ToInt32(args[1]);
|
|
248
|
+
|
|
249
|
+
if (start < 0)
|
|
250
|
+
start += len;
|
|
251
|
+
if (end < 0)
|
|
252
|
+
end += len;
|
|
253
|
+
|
|
254
|
+
start = std::max(0, std::min(len, start));
|
|
255
|
+
end = std::max(0, std::min(len, end));
|
|
256
|
+
|
|
257
|
+
if (start >= end)
|
|
258
|
+
return AnyValue::make_string("");
|
|
259
|
+
return AnyValue::make_string(self->value.substr(start, end - start)); },
|
|
260
|
+
"slice");
|
|
261
|
+
return fn;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
inline AnyValue &get_split_fn()
|
|
265
|
+
{
|
|
266
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
267
|
+
{
|
|
268
|
+
auto self = thisVal.as_string();
|
|
269
|
+
std::string separator = (args.empty() || args[0].is_undefined()) ? "" : args[0].to_std_string();
|
|
270
|
+
std::vector<jspp::AnyValue> result_vec;
|
|
271
|
+
|
|
272
|
+
if (separator.empty())
|
|
273
|
+
{
|
|
274
|
+
for (char c : (self->value))
|
|
275
|
+
{
|
|
276
|
+
result_vec.push_back(AnyValue::make_string(std::string(1, c)));
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
else
|
|
280
|
+
{
|
|
281
|
+
std::string temp = (self->value);
|
|
282
|
+
size_t pos = 0;
|
|
283
|
+
while ((pos = temp.find(separator)) != std::string::npos)
|
|
284
|
+
{
|
|
285
|
+
result_vec.push_back(AnyValue::make_string(temp.substr(0, pos)));
|
|
286
|
+
temp.erase(0, pos + separator.length());
|
|
287
|
+
}
|
|
288
|
+
result_vec.push_back(AnyValue::make_string(temp));
|
|
289
|
+
}
|
|
290
|
+
return AnyValue::make_array(std::move(result_vec)); },
|
|
291
|
+
"split");
|
|
292
|
+
return fn;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
inline AnyValue &get_startsWith_fn()
|
|
296
|
+
{
|
|
297
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
298
|
+
{
|
|
299
|
+
auto self = thisVal.as_string();
|
|
300
|
+
if (args.empty())
|
|
301
|
+
return Constants::FALSE;
|
|
302
|
+
std::string search = args[0].to_std_string();
|
|
303
|
+
size_t pos = (args.size() > 1) ? static_cast<size_t>(Operators_Private::ToNumber(args[1])) : 0;
|
|
304
|
+
if (pos > self->value.length())
|
|
305
|
+
pos = self->value.length();
|
|
306
|
+
|
|
307
|
+
return AnyValue::make_boolean(self->value.rfind(search, pos) == pos); },
|
|
308
|
+
"startsWith");
|
|
309
|
+
return fn;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
inline AnyValue &get_substring_fn()
|
|
313
|
+
{
|
|
314
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
315
|
+
{
|
|
316
|
+
auto self = thisVal.as_string();
|
|
317
|
+
int len = self->value.length();
|
|
318
|
+
int start = args.empty() ? 0 : Operators_Private::ToInt32(args[0]);
|
|
319
|
+
int end = (args.size() < 2 || args[1].is_undefined()) ? len : Operators_Private::ToInt32(args[1]);
|
|
320
|
+
|
|
321
|
+
start = std::max(0, start);
|
|
322
|
+
end = std::max(0, end);
|
|
323
|
+
|
|
324
|
+
if (start > end)
|
|
325
|
+
std::swap(start, end);
|
|
326
|
+
|
|
327
|
+
start = std::min(len, start);
|
|
328
|
+
end = std::min(len, end);
|
|
329
|
+
|
|
330
|
+
return AnyValue::make_string(self->value.substr(start, end - start)); },
|
|
331
|
+
"substring");
|
|
332
|
+
return fn;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
inline AnyValue &get_toLowerCase_fn()
|
|
336
|
+
{
|
|
337
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
338
|
+
{
|
|
339
|
+
std::string result = thisVal.as_string()->value;
|
|
340
|
+
std::transform(result.begin(), result.end(), result.begin(),
|
|
341
|
+
[](unsigned char c)
|
|
342
|
+
{ return std::tolower(c); });
|
|
343
|
+
return AnyValue::make_string(result); },
|
|
344
|
+
"toLowerCase");
|
|
345
|
+
return fn;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
inline AnyValue &get_toUpperCase_fn()
|
|
349
|
+
{
|
|
350
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
351
|
+
{
|
|
352
|
+
std::string result = thisVal.as_string()->value;
|
|
353
|
+
std::transform(result.begin(), result.end(), result.begin(),
|
|
354
|
+
[](unsigned char c)
|
|
355
|
+
{ return std::toupper(c); });
|
|
356
|
+
return AnyValue::make_string(result); },
|
|
357
|
+
"toUpperCase");
|
|
358
|
+
return fn;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
inline AnyValue &get_trim_fn()
|
|
362
|
+
{
|
|
363
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
364
|
+
{
|
|
365
|
+
const char *whitespace = " \t\n\r\f\v";
|
|
366
|
+
std::string result = thisVal.as_string()->value;
|
|
367
|
+
result.erase(0, result.find_first_not_of(whitespace));
|
|
368
|
+
result.erase(result.find_last_not_of(whitespace) + 1);
|
|
369
|
+
return AnyValue::make_string(result); },
|
|
370
|
+
"trim");
|
|
371
|
+
return fn;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
inline AnyValue &get_trimEnd_fn()
|
|
375
|
+
{
|
|
376
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
377
|
+
{
|
|
378
|
+
const char *whitespace = " \t\n\r\f\v";
|
|
379
|
+
std::string result = thisVal.as_string()->value;
|
|
380
|
+
result.erase(result.find_last_not_of(whitespace) + 1);
|
|
381
|
+
return AnyValue::make_string(result); },
|
|
382
|
+
"trimEnd");
|
|
383
|
+
return fn;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
inline AnyValue &get_trimStart_fn()
|
|
387
|
+
{
|
|
388
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
389
|
+
{
|
|
390
|
+
const char *whitespace = " \t\n\r\f\v";
|
|
391
|
+
std::string result = thisVal.as_string()->value;
|
|
392
|
+
result.erase(0, result.find_first_not_of(whitespace));
|
|
393
|
+
return AnyValue::make_string(result); },
|
|
394
|
+
"trimStart");
|
|
395
|
+
return fn;
|
|
396
|
+
}
|
|
397
|
+
|
|
17
398
|
// This function retrieves a prototype method for a given string instance.
|
|
18
|
-
|
|
19
|
-
inline std::optional<AnyValue> get(const std::string &key, JsString *self)
|
|
399
|
+
inline std::optional<AnyValue> get(const std::string &key)
|
|
20
400
|
{
|
|
21
401
|
// --- toString() & valueOf() ---
|
|
22
|
-
if (key == "toString"
|
|
402
|
+
if (key == "toString" || key == "valueOf" || key == WellKnownSymbols::toStringTag->key)
|
|
23
403
|
{
|
|
24
|
-
return
|
|
25
|
-
{ return AnyValue::make_string(self->value); },
|
|
26
|
-
key);
|
|
404
|
+
return get_toString_fn();
|
|
27
405
|
}
|
|
28
406
|
|
|
29
407
|
// --- [Symbol.iterator]() method ---
|
|
30
408
|
if (key == WellKnownSymbols::iterator->key)
|
|
31
409
|
{
|
|
32
|
-
return
|
|
33
|
-
{ return AnyValue::from_iterator(self->get_iterator()); },
|
|
34
|
-
key);
|
|
410
|
+
return get_iterator_fn();
|
|
35
411
|
}
|
|
36
412
|
|
|
37
413
|
// --- length property ---
|
|
38
414
|
if (key == "length")
|
|
39
415
|
{
|
|
40
|
-
return
|
|
41
|
-
{ return AnyValue::make_number(self->value.length()); },
|
|
42
|
-
[self](const AnyValue &thisVal, std::span<const AnyValue>) -> AnyValue
|
|
43
|
-
{ return Constants::UNDEFINED; },
|
|
44
|
-
false,
|
|
45
|
-
false);
|
|
416
|
+
return get_length_desc();
|
|
46
417
|
}
|
|
47
418
|
|
|
48
419
|
// --- charAt(pos) ---
|
|
49
420
|
if (key == "charAt")
|
|
50
421
|
{
|
|
51
|
-
return
|
|
52
|
-
{
|
|
53
|
-
double pos = args.empty() ? 0 : Operators_Private::ToNumber(args[0]);
|
|
54
|
-
int index = static_cast<int>(pos);
|
|
55
|
-
if (index < 0 || index >= self->value.length()) {
|
|
56
|
-
return AnyValue::make_string("");
|
|
57
|
-
}
|
|
58
|
-
return AnyValue::make_string(std::string(1, self->value[index])); },
|
|
59
|
-
key);
|
|
422
|
+
return get_charAt_fn();
|
|
60
423
|
}
|
|
61
424
|
|
|
62
425
|
// --- concat(str1, str2, ...) ---
|
|
63
426
|
if (key == "concat")
|
|
64
427
|
{
|
|
65
|
-
return
|
|
66
|
-
{
|
|
67
|
-
std::string result = self->value;
|
|
68
|
-
for (const auto& arg : args)
|
|
69
|
-
{
|
|
70
|
-
result += arg.to_std_string();
|
|
71
|
-
}
|
|
72
|
-
return AnyValue::make_string(result); },
|
|
73
|
-
key);
|
|
428
|
+
return get_concat_fn();
|
|
74
429
|
}
|
|
75
430
|
|
|
76
431
|
// --- endsWith(searchString, endPosition) ---
|
|
77
432
|
if (key == "endsWith")
|
|
78
433
|
{
|
|
79
|
-
return
|
|
80
|
-
{
|
|
81
|
-
if(args.empty()) return Constants::FALSE;
|
|
82
|
-
std::string search = args[0].to_std_string();
|
|
83
|
-
size_t end_pos = (args.size() > 1 && !args[1].is_undefined()) ? static_cast<size_t>(Operators_Private::ToNumber(args[1])) : self->value.length();
|
|
84
|
-
|
|
85
|
-
if (end_pos > self->value.length()) end_pos = self->value.length();
|
|
86
|
-
if (search.length() > end_pos) return Constants::FALSE;
|
|
87
|
-
|
|
88
|
-
return AnyValue::make_boolean(self->value.substr(end_pos - search.length(), search.length()) == search); },
|
|
89
|
-
key);
|
|
434
|
+
return get_endsWith_fn();
|
|
90
435
|
}
|
|
91
436
|
|
|
92
437
|
// --- includes(searchString, position) ---
|
|
93
438
|
if (key == "includes")
|
|
94
439
|
{
|
|
95
|
-
return
|
|
96
|
-
{
|
|
97
|
-
if(args.empty()) return Constants::FALSE;
|
|
98
|
-
std::string search = args[0].to_std_string();
|
|
99
|
-
size_t pos = (args.size() > 1) ? static_cast<size_t>(Operators_Private::ToNumber(args[1])) : 0;
|
|
100
|
-
|
|
101
|
-
return AnyValue::make_boolean(self->value.find(search, pos) != std::string::npos); },
|
|
102
|
-
key);
|
|
440
|
+
return get_includes_fn();
|
|
103
441
|
}
|
|
104
442
|
|
|
105
443
|
// --- indexOf(searchString, position) ---
|
|
106
444
|
if (key == "indexOf")
|
|
107
445
|
{
|
|
108
|
-
return
|
|
109
|
-
{
|
|
110
|
-
if (args.empty()) return AnyValue::make_number(-1);
|
|
111
|
-
std::string search = args[0].to_std_string();
|
|
112
|
-
size_t pos = (args.size() > 1) ? static_cast<size_t>(Operators_Private::ToNumber(args[1])) : 0;
|
|
113
|
-
size_t result = self->value.find(search, pos);
|
|
114
|
-
return result == std::string::npos ? AnyValue::make_number(-1) : AnyValue::make_number(result); },
|
|
115
|
-
key);
|
|
446
|
+
return get_indexOf_fn();
|
|
116
447
|
}
|
|
117
448
|
|
|
118
449
|
// --- lastIndexOf(searchString, position) ---
|
|
119
450
|
if (key == "lastIndexOf")
|
|
120
451
|
{
|
|
121
|
-
return
|
|
122
|
-
{
|
|
123
|
-
if (args.empty()) return AnyValue::make_number(-1);
|
|
124
|
-
std::string search = args[0].to_std_string();
|
|
125
|
-
size_t pos = (args.size() > 1 && !args[1].is_undefined()) ? static_cast<size_t>(Operators_Private::ToNumber(args[1])) : std::string::npos;
|
|
126
|
-
size_t result = self->value.rfind(search, pos);
|
|
127
|
-
return result == std::string::npos ? AnyValue::make_number(-1) : AnyValue::make_number(result); },
|
|
128
|
-
key);
|
|
452
|
+
return get_lastIndexOf_fn();
|
|
129
453
|
}
|
|
130
454
|
|
|
131
455
|
// --- padEnd(targetLength, padString) ---
|
|
132
456
|
if (key == "padEnd")
|
|
133
457
|
{
|
|
134
|
-
return
|
|
135
|
-
{
|
|
136
|
-
size_t target_length = args.empty() ? 0 : static_cast<size_t>(Operators_Private::ToNumber(args[0]));
|
|
137
|
-
if (self->value.length() >= target_length) return AnyValue::make_string(self->value);
|
|
138
|
-
std::string pad_string = (args.size() > 1 && !args[1].is_undefined() && !args[1].to_std_string().empty()) ? args[1].to_std_string() : " ";
|
|
139
|
-
std::string result = self->value;
|
|
140
|
-
while (result.length() < target_length)
|
|
141
|
-
{
|
|
142
|
-
result += pad_string;
|
|
143
|
-
}
|
|
144
|
-
return AnyValue::make_string(result.substr(0, target_length)); },
|
|
145
|
-
key);
|
|
458
|
+
return get_padEnd_fn();
|
|
146
459
|
}
|
|
147
460
|
|
|
148
461
|
// --- padStart(targetLength, padString) ---
|
|
149
462
|
if (key == "padStart")
|
|
150
463
|
{
|
|
151
|
-
return
|
|
152
|
-
{
|
|
153
|
-
size_t target_length = args.empty() ? 0 : static_cast<size_t>(Operators_Private::ToNumber(args[0]));
|
|
154
|
-
if (self->value.length() >= target_length) return AnyValue::make_string(self->value);
|
|
155
|
-
std::string pad_string = (args.size() > 1 && !args[1].is_undefined() && !args[1].to_std_string().empty()) ? args[1].to_std_string() : " ";
|
|
156
|
-
std::string padding;
|
|
157
|
-
while (padding.length() < target_length - self->value.length())
|
|
158
|
-
{
|
|
159
|
-
padding += pad_string;
|
|
160
|
-
}
|
|
161
|
-
return AnyValue::make_string(padding.substr(0, target_length - self->value.length()) + self->value); },
|
|
162
|
-
key);
|
|
464
|
+
return get_padStart_fn();
|
|
163
465
|
}
|
|
164
466
|
|
|
165
467
|
// --- repeat(count) ---
|
|
166
468
|
if (key == "repeat")
|
|
167
469
|
{
|
|
168
|
-
return
|
|
169
|
-
{
|
|
170
|
-
double count = args.empty() ? 0 : Operators_Private::ToNumber(args[0]);
|
|
171
|
-
if (count < 0) {
|
|
172
|
-
// In a real implementation, this should throw a RangeError.
|
|
173
|
-
return AnyValue::make_string("");
|
|
174
|
-
}
|
|
175
|
-
std::string result = "";
|
|
176
|
-
for (int i = 0; i < count; ++i)
|
|
177
|
-
{
|
|
178
|
-
result += self->value;
|
|
179
|
-
}
|
|
180
|
-
return AnyValue::make_string(result); },
|
|
181
|
-
key);
|
|
470
|
+
return get_repeat_fn();
|
|
182
471
|
}
|
|
183
472
|
|
|
184
473
|
// --- replace(substr, newSubstr) ---
|
|
185
474
|
if (key == "replace")
|
|
186
475
|
{
|
|
187
|
-
return
|
|
188
|
-
{
|
|
189
|
-
if (args.size() < 2) return AnyValue::make_string(self->value);
|
|
190
|
-
std::string search = args[0].to_std_string();
|
|
191
|
-
std::string replacement = args[1].to_std_string();
|
|
192
|
-
std::string result = self->value;
|
|
193
|
-
size_t pos = result.find(search);
|
|
194
|
-
if (pos != std::string::npos)
|
|
195
|
-
{
|
|
196
|
-
result.replace(pos, search.length(), replacement);
|
|
197
|
-
}
|
|
198
|
-
return AnyValue::make_string(result); },
|
|
199
|
-
key);
|
|
476
|
+
return get_replace_fn();
|
|
200
477
|
}
|
|
201
478
|
|
|
202
479
|
// --- replaceAll(substr, newSubstr) ---
|
|
203
480
|
if (key == "replaceAll")
|
|
204
481
|
{
|
|
205
|
-
return
|
|
206
|
-
{
|
|
207
|
-
if (args.size() < 2) return AnyValue::make_string(self->value);
|
|
208
|
-
std::string search = args[0].to_std_string();
|
|
209
|
-
if (search.empty()) return AnyValue::make_string(self->value);
|
|
210
|
-
std::string replacement = args[1].to_std_string();
|
|
211
|
-
std::string result = self->value;
|
|
212
|
-
size_t pos = result.find(search);
|
|
213
|
-
while (pos != std::string::npos)
|
|
214
|
-
{
|
|
215
|
-
result.replace(pos, search.length(), replacement);
|
|
216
|
-
pos = result.find(search, pos + replacement.length());
|
|
217
|
-
}
|
|
218
|
-
return AnyValue::make_string(result); },
|
|
219
|
-
key);
|
|
482
|
+
return get_replaceAll_fn();
|
|
220
483
|
}
|
|
221
484
|
|
|
222
485
|
// --- slice(beginIndex, endIndex) ---
|
|
223
486
|
if (key == "slice")
|
|
224
487
|
{
|
|
225
|
-
return
|
|
226
|
-
{
|
|
227
|
-
int len = self->value.length();
|
|
228
|
-
int start = args.empty() ? 0 : Operators_Private::ToInt32(args[0]);
|
|
229
|
-
int end = (args.size() < 2 || args[1].is_undefined()) ? len : Operators_Private::ToInt32(args[1]);
|
|
230
|
-
|
|
231
|
-
if (start < 0) start += len;
|
|
232
|
-
if (end < 0) end += len;
|
|
233
|
-
|
|
234
|
-
start = std::max(0, std::min(len, start));
|
|
235
|
-
end = std::max(0, std::min(len, end));
|
|
236
|
-
|
|
237
|
-
if (start >= end) return AnyValue::make_string("");
|
|
238
|
-
return AnyValue::make_string(self->value.substr(start, end - start)); },
|
|
239
|
-
key);
|
|
488
|
+
return get_slice_fn();
|
|
240
489
|
}
|
|
241
490
|
|
|
242
491
|
// --- split(separator) ---
|
|
243
492
|
if (key == "split")
|
|
244
493
|
{
|
|
245
|
-
return
|
|
246
|
-
{
|
|
247
|
-
std::string separator = (args.empty() || args[0].is_undefined()) ? "" : args[0].to_std_string();
|
|
248
|
-
std::vector<jspp::AnyValue> result_vec;
|
|
249
|
-
|
|
250
|
-
if (separator.empty()) {
|
|
251
|
-
for (char c : (self->value)) {
|
|
252
|
-
result_vec.push_back(AnyValue::make_string(std::string(1, c)));
|
|
253
|
-
}
|
|
254
|
-
} else {
|
|
255
|
-
std::string temp = (self->value);
|
|
256
|
-
size_t pos = 0;
|
|
257
|
-
while ((pos = temp.find(separator)) != std::string::npos) {
|
|
258
|
-
result_vec.push_back(AnyValue::make_string(temp.substr(0, pos)));
|
|
259
|
-
temp.erase(0, pos + separator.length());
|
|
260
|
-
}
|
|
261
|
-
result_vec.push_back(AnyValue::make_string(temp));
|
|
262
|
-
}
|
|
263
|
-
return AnyValue::make_array(std::move(result_vec)); },
|
|
264
|
-
key);
|
|
494
|
+
return get_split_fn();
|
|
265
495
|
}
|
|
266
496
|
|
|
267
497
|
// --- startsWith(searchString, position) ---
|
|
268
498
|
if (key == "startsWith")
|
|
269
499
|
{
|
|
270
|
-
return
|
|
271
|
-
{
|
|
272
|
-
if(args.empty()) return Constants::FALSE;
|
|
273
|
-
std::string search = args[0].to_std_string();
|
|
274
|
-
size_t pos = (args.size() > 1) ? static_cast<size_t>(Operators_Private::ToNumber(args[1])) : 0;
|
|
275
|
-
if (pos > self->value.length()) pos = self->value.length();
|
|
276
|
-
|
|
277
|
-
return AnyValue::make_boolean(self->value.rfind(search, pos) == pos); },
|
|
278
|
-
key);
|
|
500
|
+
return get_startsWith_fn();
|
|
279
501
|
}
|
|
280
502
|
|
|
281
503
|
// --- substring(indexStart, indexEnd) ---
|
|
282
504
|
if (key == "substring")
|
|
283
505
|
{
|
|
284
|
-
return
|
|
285
|
-
{
|
|
286
|
-
int len = self->value.length();
|
|
287
|
-
int start = args.empty() ? 0 : Operators_Private::ToInt32(args[0]);
|
|
288
|
-
int end = (args.size() < 2 || args[1].is_undefined()) ? len : Operators_Private::ToInt32(args[1]);
|
|
289
|
-
|
|
290
|
-
start = std::max(0, start);
|
|
291
|
-
end = std::max(0, end);
|
|
292
|
-
|
|
293
|
-
if (start > end) std::swap(start, end);
|
|
294
|
-
|
|
295
|
-
start = std::min(len, start);
|
|
296
|
-
end = std::min(len, end);
|
|
297
|
-
|
|
298
|
-
return AnyValue::make_string(self->value.substr(start, end - start)); },
|
|
299
|
-
key);
|
|
506
|
+
return get_substring_fn();
|
|
300
507
|
}
|
|
301
508
|
|
|
302
509
|
// --- toLowerCase() ---
|
|
303
510
|
if (key == "toLowerCase")
|
|
304
511
|
{
|
|
305
|
-
return
|
|
306
|
-
{
|
|
307
|
-
std::string result = self->value;
|
|
308
|
-
std::transform(result.begin(), result.end(), result.begin(),
|
|
309
|
-
[](unsigned char c){ return std::tolower(c); });
|
|
310
|
-
return AnyValue::make_string(result); },
|
|
311
|
-
key);
|
|
512
|
+
return get_toLowerCase_fn();
|
|
312
513
|
}
|
|
313
514
|
|
|
314
515
|
// --- toUpperCase() ---
|
|
315
516
|
if (key == "toUpperCase")
|
|
316
517
|
{
|
|
317
|
-
return
|
|
318
|
-
{
|
|
319
|
-
std::string result = self->value;
|
|
320
|
-
std::transform(result.begin(), result.end(), result.begin(),
|
|
321
|
-
[](unsigned char c){ return std::toupper(c); });
|
|
322
|
-
return AnyValue::make_string(result); },
|
|
323
|
-
key);
|
|
518
|
+
return get_toUpperCase_fn();
|
|
324
519
|
}
|
|
325
520
|
|
|
326
521
|
// --- trim() ---
|
|
327
522
|
if (key == "trim")
|
|
328
523
|
{
|
|
329
|
-
return
|
|
330
|
-
{
|
|
331
|
-
const char* whitespace = " \t\n\r\f\v";
|
|
332
|
-
std::string result = self->value;
|
|
333
|
-
result.erase(0, result.find_first_not_of(whitespace));
|
|
334
|
-
result.erase(result.find_last_not_of(whitespace) + 1);
|
|
335
|
-
return AnyValue::make_string(result); },
|
|
336
|
-
key);
|
|
524
|
+
return get_trim_fn();
|
|
337
525
|
}
|
|
338
526
|
|
|
339
527
|
// --- trimEnd() ---
|
|
340
528
|
if (key == "trimEnd")
|
|
341
529
|
{
|
|
342
|
-
return
|
|
343
|
-
{
|
|
344
|
-
const char* whitespace = " \t\n\r\f\v";
|
|
345
|
-
std::string result = self->value;
|
|
346
|
-
result.erase(result.find_last_not_of(whitespace) + 1);
|
|
347
|
-
return AnyValue::make_string(result); },
|
|
348
|
-
key);
|
|
530
|
+
return get_trimEnd_fn();
|
|
349
531
|
}
|
|
350
532
|
|
|
351
533
|
// --- trimStart() ---
|
|
352
534
|
if (key == "trimStart")
|
|
353
535
|
{
|
|
354
|
-
return
|
|
355
|
-
{
|
|
356
|
-
const char* whitespace = " \t\n\r\f\v";
|
|
357
|
-
std::string result = self->value;
|
|
358
|
-
result.erase(0, result.find_first_not_of(whitespace));
|
|
359
|
-
return AnyValue::make_string(result); },
|
|
360
|
-
key);
|
|
536
|
+
return get_trimStart_fn();
|
|
361
537
|
}
|
|
362
538
|
|
|
363
539
|
return std::nullopt;
|
|
364
540
|
}
|
|
365
541
|
}
|
|
366
|
-
}
|
|
542
|
+
}
|