@ugo-studio/jspp 0.2.9 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +25 -25
- package/README.md +20 -12
- package/dist/analysis/scope.js +5 -3
- package/dist/analysis/typeAnalyzer.js +21 -25
- package/dist/cli/index.js +14 -4
- package/dist/cli/utils.js +61 -0
- package/dist/core/codegen/class-handlers.js +6 -6
- package/dist/core/codegen/control-flow-handlers.js +10 -9
- package/dist/core/codegen/declaration-handlers.js +10 -3
- package/dist/core/codegen/destructuring-handlers.js +9 -4
- package/dist/core/codegen/expression-handlers.js +40 -29
- package/dist/core/codegen/function-handlers.js +78 -12
- package/dist/core/codegen/helpers.js +91 -14
- package/dist/core/codegen/index.js +4 -2
- package/dist/core/codegen/statement-handlers.js +9 -7
- package/package.json +2 -2
- package/scripts/precompile-headers.ts +249 -50
- package/scripts/setup-compiler.ts +63 -63
- package/src/prelude/any_value.cpp +636 -0
- package/src/prelude/any_value.hpp +369 -362
- 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} +10 -16
- package/src/prelude/library/array.cpp +191 -0
- package/src/prelude/library/array.hpp +13 -186
- package/src/prelude/library/console.cpp +125 -0
- package/src/prelude/library/console.hpp +24 -112
- package/src/prelude/library/error.cpp +100 -0
- package/src/prelude/library/error.hpp +13 -113
- package/src/prelude/library/function.cpp +69 -0
- package/src/prelude/library/function.hpp +11 -10
- package/src/prelude/library/global.cpp +96 -0
- package/src/prelude/library/global.hpp +12 -28
- package/src/prelude/library/global_usings.hpp +15 -0
- package/src/prelude/library/math.cpp +258 -0
- package/src/prelude/library/math.hpp +26 -308
- package/src/prelude/library/object.cpp +379 -0
- package/src/prelude/library/object.hpp +14 -276
- 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 +11 -39
- package/src/prelude/library/promise.cpp +131 -0
- package/src/prelude/library/promise.hpp +12 -123
- package/src/prelude/library/symbol.cpp +56 -0
- package/src/prelude/library/symbol.hpp +11 -52
- package/src/prelude/library/timer.cpp +88 -0
- package/src/prelude/library/timer.hpp +16 -92
- package/src/prelude/runtime.cpp +19 -0
- package/src/prelude/types.hpp +184 -179
- package/src/prelude/utils/access.hpp +502 -411
- package/src/prelude/utils/assignment_operators.hpp +99 -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/object.hpp +60 -3
- package/src/prelude/utils/operators.hpp +351 -336
- package/src/prelude/utils/operators_primitive.hpp +336 -336
- 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 -1
- package/src/prelude/values/async_iterator.cpp +251 -0
- package/src/prelude/values/async_iterator.hpp +111 -83
- package/src/prelude/values/function.cpp +262 -0
- package/src/prelude/values/function.hpp +62 -82
- package/src/prelude/values/iterator.cpp +309 -0
- package/src/prelude/values/iterator.hpp +33 -64
- package/src/prelude/values/number.cpp +176 -0
- package/src/prelude/values/object.cpp +159 -0
- package/src/prelude/values/object.hpp +4 -0
- package/src/prelude/values/promise.cpp +479 -0
- package/src/prelude/values/promise.hpp +79 -72
- package/src/prelude/values/prototypes/array.hpp +46 -1336
- package/src/prelude/values/prototypes/async_iterator.hpp +19 -61
- package/src/prelude/values/prototypes/function.hpp +7 -46
- package/src/prelude/values/prototypes/iterator.hpp +25 -201
- package/src/prelude/values/prototypes/number.hpp +23 -210
- package/src/prelude/values/prototypes/object.hpp +7 -23
- package/src/prelude/values/prototypes/promise.hpp +18 -196
- package/src/prelude/values/prototypes/string.hpp +39 -542
- 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/string.hpp +25 -26
- package/src/prelude/values/symbol.cpp +89 -0
- package/src/prelude/values/symbol.hpp +101 -101
- 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/values/helpers/array.hpp +0 -209
- 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 -61
- package/src/prelude/values/helpers/symbol.hpp +0 -21
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
#include "jspp.hpp"
|
|
2
|
+
#include "values/string.hpp"
|
|
3
|
+
#include "values/prototypes/string.hpp"
|
|
4
|
+
|
|
5
|
+
namespace jspp {
|
|
6
|
+
|
|
7
|
+
// --- JsString Implementation ---
|
|
8
|
+
|
|
9
|
+
std::string JsString::to_std_string() const
|
|
10
|
+
{
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
AnyValue JsString::get_property(const std::string &key, const AnyValue &thisVal)
|
|
15
|
+
{
|
|
16
|
+
auto proto_fn = StringPrototypes::get(key);
|
|
17
|
+
if (proto_fn.has_value())
|
|
18
|
+
{
|
|
19
|
+
return AnyValue::resolve_property_for_read(proto_fn.value(), thisVal, key);
|
|
20
|
+
}
|
|
21
|
+
if (JsArray::is_array_index(key))
|
|
22
|
+
{
|
|
23
|
+
uint32_t idx = static_cast<uint32_t>(std::stoull(key));
|
|
24
|
+
return get_property(idx);
|
|
25
|
+
}
|
|
26
|
+
return Constants::UNDEFINED;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
AnyValue JsString::get_property(uint32_t idx)
|
|
30
|
+
{
|
|
31
|
+
if (idx < value.length())
|
|
32
|
+
{
|
|
33
|
+
return AnyValue::make_string(std::string(1, value[idx]));
|
|
34
|
+
}
|
|
35
|
+
return Constants::UNDEFINED;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// --- StringPrototypes Implementation ---
|
|
39
|
+
|
|
40
|
+
namespace StringPrototypes {
|
|
41
|
+
|
|
42
|
+
AnyValue &get_toString_fn()
|
|
43
|
+
{
|
|
44
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
45
|
+
{ return AnyValue::make_string(thisVal.as_string()->value); },
|
|
46
|
+
"toString");
|
|
47
|
+
return fn;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
AnyValue &get_iterator_fn()
|
|
51
|
+
{
|
|
52
|
+
static AnyValue fn = AnyValue::make_generator([](AnyValue thisVal, std::vector<AnyValue> _) -> jspp::JsIterator<jspp::AnyValue>
|
|
53
|
+
{
|
|
54
|
+
auto self = thisVal.as_string();
|
|
55
|
+
const std::string &value = self->value;
|
|
56
|
+
for (size_t i = 0; i < value.length();)
|
|
57
|
+
{
|
|
58
|
+
unsigned char c = static_cast<unsigned char>(value[i]);
|
|
59
|
+
size_t len = 1;
|
|
60
|
+
if ((c & 0x80) == 0)
|
|
61
|
+
len = 1;
|
|
62
|
+
else if ((c & 0xE0) == 0xC0)
|
|
63
|
+
len = 2;
|
|
64
|
+
else if ((c & 0xF0) == 0xE0)
|
|
65
|
+
len = 3;
|
|
66
|
+
else if ((c & 0xF8) == 0xF0)
|
|
67
|
+
len = 4;
|
|
68
|
+
|
|
69
|
+
if (i + len > value.length())
|
|
70
|
+
len = value.length() - i;
|
|
71
|
+
|
|
72
|
+
co_yield AnyValue::make_string(value.substr(i, len));
|
|
73
|
+
i += len;
|
|
74
|
+
}
|
|
75
|
+
co_return AnyValue::make_undefined(); },
|
|
76
|
+
"Symbol.iterator");
|
|
77
|
+
return fn;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
AnyValue &get_length_desc()
|
|
81
|
+
{
|
|
82
|
+
static auto getter = [](const AnyValue &thisVal, std::span<const AnyValue>) -> AnyValue
|
|
83
|
+
{ return AnyValue::make_number(thisVal.as_string()->value.length()); };
|
|
84
|
+
static auto setter = [](const AnyValue &thisVal, std::span<const AnyValue>) -> AnyValue
|
|
85
|
+
{ return Constants::UNDEFINED; };
|
|
86
|
+
static AnyValue desc = AnyValue::make_accessor_descriptor(getter, setter, false, false);
|
|
87
|
+
return desc;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
AnyValue &get_charAt_fn()
|
|
91
|
+
{
|
|
92
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
93
|
+
{
|
|
94
|
+
auto self = thisVal.as_string();
|
|
95
|
+
double pos = args.empty() ? 0 : Operators_Private::ToNumber(args[0]);
|
|
96
|
+
int index = static_cast<int>(pos);
|
|
97
|
+
if (index < 0 || index >= self->value.length())
|
|
98
|
+
{
|
|
99
|
+
return AnyValue::make_string("");
|
|
100
|
+
}
|
|
101
|
+
return AnyValue::make_string(std::string(1, self->value[index])); },
|
|
102
|
+
"charAt");
|
|
103
|
+
return fn;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
AnyValue &get_concat_fn()
|
|
107
|
+
{
|
|
108
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
109
|
+
{
|
|
110
|
+
std::string result = thisVal.as_string()->value;
|
|
111
|
+
for (const auto &arg : args)
|
|
112
|
+
{
|
|
113
|
+
result += arg.to_std_string();
|
|
114
|
+
}
|
|
115
|
+
return AnyValue::make_string(result); },
|
|
116
|
+
"concat");
|
|
117
|
+
return fn;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
AnyValue &get_endsWith_fn()
|
|
121
|
+
{
|
|
122
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
123
|
+
{
|
|
124
|
+
auto self = thisVal.as_string();
|
|
125
|
+
if (args.empty())
|
|
126
|
+
return Constants::FALSE;
|
|
127
|
+
std::string search = args[0].to_std_string();
|
|
128
|
+
size_t end_pos = (args.size() > 1 && !args[1].is_undefined()) ? static_cast<size_t>(Operators_Private::ToNumber(args[1])) : self->value.length();
|
|
129
|
+
|
|
130
|
+
if (end_pos > self->value.length())
|
|
131
|
+
end_pos = self->value.length();
|
|
132
|
+
if (search.length() > end_pos)
|
|
133
|
+
return Constants::FALSE;
|
|
134
|
+
|
|
135
|
+
return AnyValue::make_boolean(self->value.substr(end_pos - search.length(), search.length()) == search); },
|
|
136
|
+
"endsWith");
|
|
137
|
+
return fn;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
AnyValue &get_includes_fn()
|
|
141
|
+
{
|
|
142
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
143
|
+
{
|
|
144
|
+
auto self = thisVal.as_string();
|
|
145
|
+
if (args.empty())
|
|
146
|
+
return Constants::FALSE;
|
|
147
|
+
std::string search = args[0].to_std_string();
|
|
148
|
+
size_t pos = (args.size() > 1) ? static_cast<size_t>(Operators_Private::ToNumber(args[1])) : 0;
|
|
149
|
+
|
|
150
|
+
return AnyValue::make_boolean(self->value.find(search, pos) != std::string::npos); },
|
|
151
|
+
"includes");
|
|
152
|
+
return fn;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
AnyValue &get_indexOf_fn()
|
|
156
|
+
{
|
|
157
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
158
|
+
{
|
|
159
|
+
auto self = thisVal.as_string();
|
|
160
|
+
if (args.empty())
|
|
161
|
+
return AnyValue::make_number(-1);
|
|
162
|
+
std::string search = args[0].to_std_string();
|
|
163
|
+
size_t pos = (args.size() > 1) ? static_cast<size_t>(Operators_Private::ToNumber(args[1])) : 0;
|
|
164
|
+
size_t result = self->value.find(search, pos);
|
|
165
|
+
return result == std::string::npos ? AnyValue::make_number(-1) : AnyValue::make_number(result); },
|
|
166
|
+
"indexOf");
|
|
167
|
+
return fn;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
AnyValue &get_lastIndexOf_fn()
|
|
171
|
+
{
|
|
172
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
173
|
+
{
|
|
174
|
+
auto self = thisVal.as_string();
|
|
175
|
+
if (args.empty())
|
|
176
|
+
return AnyValue::make_number(-1);
|
|
177
|
+
std::string search = args[0].to_std_string();
|
|
178
|
+
size_t pos = (args.size() > 1 && !args[1].is_undefined()) ? static_cast<size_t>(Operators_Private::ToNumber(args[1])) : std::string::npos;
|
|
179
|
+
size_t result = self->value.rfind(search, pos);
|
|
180
|
+
return result == std::string::npos ? AnyValue::make_number(-1) : AnyValue::make_number(result); },
|
|
181
|
+
"lastIndexOf");
|
|
182
|
+
return fn;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
AnyValue &get_padEnd_fn()
|
|
186
|
+
{
|
|
187
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
188
|
+
{
|
|
189
|
+
auto self = thisVal.as_string();
|
|
190
|
+
size_t target_length = args.empty() ? 0 : static_cast<size_t>(Operators_Private::ToNumber(args[0]));
|
|
191
|
+
if (self->value.length() >= target_length)
|
|
192
|
+
return AnyValue::make_string(self->value);
|
|
193
|
+
std::string pad_string = (args.size() > 1 && !args[1].is_undefined() && !args[1].to_std_string().empty()) ? args[1].to_std_string() : " ";
|
|
194
|
+
std::string result = self->value;
|
|
195
|
+
while (result.length() < target_length)
|
|
196
|
+
{
|
|
197
|
+
result += pad_string;
|
|
198
|
+
}
|
|
199
|
+
return AnyValue::make_string(result.substr(0, target_length)); },
|
|
200
|
+
"padEnd");
|
|
201
|
+
return fn;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
AnyValue &get_padStart_fn()
|
|
205
|
+
{
|
|
206
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
207
|
+
{
|
|
208
|
+
auto self = thisVal.as_string();
|
|
209
|
+
size_t target_length = args.empty() ? 0 : static_cast<size_t>(Operators_Private::ToNumber(args[0]));
|
|
210
|
+
if (self->value.length() >= target_length)
|
|
211
|
+
return AnyValue::make_string(self->value);
|
|
212
|
+
std::string pad_string = (args.size() > 1 && !args[1].is_undefined() && !args[1].to_std_string().empty()) ? args[1].to_std_string() : " ";
|
|
213
|
+
std::string padding;
|
|
214
|
+
while (padding.length() < target_length - self->value.length())
|
|
215
|
+
{
|
|
216
|
+
padding += pad_string;
|
|
217
|
+
}
|
|
218
|
+
return AnyValue::make_string(padding.substr(0, target_length - self->value.length()) + self->value); },
|
|
219
|
+
"padStart");
|
|
220
|
+
return fn;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
AnyValue &get_repeat_fn()
|
|
224
|
+
{
|
|
225
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
226
|
+
{
|
|
227
|
+
auto self = thisVal.as_string();
|
|
228
|
+
double count = args.empty() ? 0 : Operators_Private::ToNumber(args[0]);
|
|
229
|
+
if (count < 0)
|
|
230
|
+
{
|
|
231
|
+
// In a real implementation, this should throw a RangeError.
|
|
232
|
+
return AnyValue::make_string("");
|
|
233
|
+
}
|
|
234
|
+
std::string result = "";
|
|
235
|
+
for (int i = 0; i < count; ++i)
|
|
236
|
+
{
|
|
237
|
+
result += self->value;
|
|
238
|
+
}
|
|
239
|
+
return AnyValue::make_string(result); },
|
|
240
|
+
"repeat");
|
|
241
|
+
return fn;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
AnyValue &get_replace_fn()
|
|
245
|
+
{
|
|
246
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
247
|
+
{
|
|
248
|
+
auto self = thisVal.as_string();
|
|
249
|
+
if (args.size() < 2)
|
|
250
|
+
return AnyValue::make_string(self->value);
|
|
251
|
+
std::string search = args[0].to_std_string();
|
|
252
|
+
std::string replacement = args[1].to_std_string();
|
|
253
|
+
std::string result = self->value;
|
|
254
|
+
size_t pos = result.find(search);
|
|
255
|
+
if (pos != std::string::npos)
|
|
256
|
+
{
|
|
257
|
+
result.replace(pos, search.length(), replacement);
|
|
258
|
+
}
|
|
259
|
+
return AnyValue::make_string(result); },
|
|
260
|
+
"replace");
|
|
261
|
+
return fn;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
AnyValue &get_replaceAll_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
|
+
if (args.size() < 2)
|
|
270
|
+
return AnyValue::make_string(self->value);
|
|
271
|
+
std::string search = args[0].to_std_string();
|
|
272
|
+
if (search.empty())
|
|
273
|
+
return AnyValue::make_string(self->value);
|
|
274
|
+
std::string replacement = args[1].to_std_string();
|
|
275
|
+
std::string result = self->value;
|
|
276
|
+
size_t pos = result.find(search);
|
|
277
|
+
while (pos != std::string::npos)
|
|
278
|
+
{
|
|
279
|
+
result.replace(pos, search.length(), replacement);
|
|
280
|
+
pos = result.find(search, pos + replacement.length());
|
|
281
|
+
}
|
|
282
|
+
return AnyValue::make_string(result); },
|
|
283
|
+
"replaceAll");
|
|
284
|
+
return fn;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
AnyValue &get_slice_fn()
|
|
288
|
+
{
|
|
289
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
290
|
+
{
|
|
291
|
+
auto self = thisVal.as_string();
|
|
292
|
+
int len = self->value.length();
|
|
293
|
+
int start = args.empty() ? 0 : Operators_Private::ToInt32(args[0]);
|
|
294
|
+
int end = (args.size() < 2 || args[1].is_undefined()) ? len : Operators_Private::ToInt32(args[1]);
|
|
295
|
+
|
|
296
|
+
if (start < 0)
|
|
297
|
+
start += len;
|
|
298
|
+
if (end < 0)
|
|
299
|
+
end += len;
|
|
300
|
+
|
|
301
|
+
start = std::max(0, std::min(len, start));
|
|
302
|
+
end = std::max(0, std::min(len, end));
|
|
303
|
+
|
|
304
|
+
if (start >= end)
|
|
305
|
+
return AnyValue::make_string("");
|
|
306
|
+
return AnyValue::make_string(self->value.substr(start, end - start)); },
|
|
307
|
+
"slice");
|
|
308
|
+
return fn;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
AnyValue &get_split_fn()
|
|
312
|
+
{
|
|
313
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
314
|
+
{
|
|
315
|
+
auto self = thisVal.as_string();
|
|
316
|
+
std::string separator = (args.empty() || args[0].is_undefined()) ? "" : args[0].to_std_string();
|
|
317
|
+
std::vector<jspp::AnyValue> result_vec;
|
|
318
|
+
|
|
319
|
+
if (separator.empty())
|
|
320
|
+
{
|
|
321
|
+
for (char c : (self->value))
|
|
322
|
+
{
|
|
323
|
+
result_vec.push_back(AnyValue::make_string(std::string(1, c)));
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
else
|
|
327
|
+
{
|
|
328
|
+
std::string temp = (self->value);
|
|
329
|
+
size_t pos = 0;
|
|
330
|
+
while ((pos = temp.find(separator)) != std::string::npos)
|
|
331
|
+
{
|
|
332
|
+
result_vec.push_back(AnyValue::make_string(temp.substr(0, pos)));
|
|
333
|
+
temp.erase(0, pos + separator.length());
|
|
334
|
+
}
|
|
335
|
+
result_vec.push_back(AnyValue::make_string(temp));
|
|
336
|
+
}
|
|
337
|
+
return AnyValue::make_array(std::move(result_vec)); },
|
|
338
|
+
"split");
|
|
339
|
+
return fn;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
AnyValue &get_startsWith_fn()
|
|
343
|
+
{
|
|
344
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
345
|
+
{
|
|
346
|
+
auto self = thisVal.as_string();
|
|
347
|
+
if (args.empty())
|
|
348
|
+
return Constants::FALSE;
|
|
349
|
+
std::string search = args[0].to_std_string();
|
|
350
|
+
size_t pos = (args.size() > 1) ? static_cast<size_t>(Operators_Private::ToNumber(args[1])) : 0;
|
|
351
|
+
if (pos > self->value.length())
|
|
352
|
+
pos = self->value.length();
|
|
353
|
+
|
|
354
|
+
return AnyValue::make_boolean(self->value.rfind(search, pos) == pos); },
|
|
355
|
+
"startsWith");
|
|
356
|
+
return fn;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
AnyValue &get_substring_fn()
|
|
360
|
+
{
|
|
361
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
362
|
+
{
|
|
363
|
+
auto self = thisVal.as_string();
|
|
364
|
+
int len = self->value.length();
|
|
365
|
+
int start = args.empty() ? 0 : Operators_Private::ToInt32(args[0]);
|
|
366
|
+
int end = (args.size() < 2 || args[1].is_undefined()) ? len : Operators_Private::ToInt32(args[1]);
|
|
367
|
+
|
|
368
|
+
start = std::max(0, start);
|
|
369
|
+
end = std::max(0, end);
|
|
370
|
+
|
|
371
|
+
if (start > end)
|
|
372
|
+
std::swap(start, end);
|
|
373
|
+
|
|
374
|
+
start = std::min(len, start);
|
|
375
|
+
end = std::min(len, end);
|
|
376
|
+
|
|
377
|
+
return AnyValue::make_string(self->value.substr(start, end - start)); },
|
|
378
|
+
"substring");
|
|
379
|
+
return fn;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
AnyValue &get_toLowerCase_fn()
|
|
383
|
+
{
|
|
384
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
385
|
+
{
|
|
386
|
+
std::string result = thisVal.as_string()->value;
|
|
387
|
+
std::transform(result.begin(), result.end(), result.begin(),
|
|
388
|
+
[](unsigned char c)
|
|
389
|
+
{ return std::tolower(c); });
|
|
390
|
+
return AnyValue::make_string(result); },
|
|
391
|
+
"toLowerCase");
|
|
392
|
+
return fn;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
AnyValue &get_toUpperCase_fn()
|
|
396
|
+
{
|
|
397
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
398
|
+
{
|
|
399
|
+
std::string result = thisVal.as_string()->value;
|
|
400
|
+
std::transform(result.begin(), result.end(), result.begin(),
|
|
401
|
+
[](unsigned char c)
|
|
402
|
+
{ return std::toupper(c); });
|
|
403
|
+
return AnyValue::make_string(result); },
|
|
404
|
+
"toUpperCase");
|
|
405
|
+
return fn;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
AnyValue &get_trim_fn()
|
|
409
|
+
{
|
|
410
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
411
|
+
{
|
|
412
|
+
const char *whitespace = " \t\n\r\f\v";
|
|
413
|
+
std::string result = thisVal.as_string()->value;
|
|
414
|
+
result.erase(0, result.find_first_not_of(whitespace));
|
|
415
|
+
result.erase(result.find_last_not_of(whitespace) + 1);
|
|
416
|
+
return AnyValue::make_string(result); },
|
|
417
|
+
"trim");
|
|
418
|
+
return fn;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
AnyValue &get_trimEnd_fn()
|
|
422
|
+
{
|
|
423
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
424
|
+
{
|
|
425
|
+
const char *whitespace = " \t\n\r\f\v";
|
|
426
|
+
std::string result = thisVal.as_string()->value;
|
|
427
|
+
result.erase(result.find_last_not_of(whitespace) + 1);
|
|
428
|
+
return AnyValue::make_string(result); },
|
|
429
|
+
"trimEnd");
|
|
430
|
+
return fn;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
AnyValue &get_trimStart_fn()
|
|
434
|
+
{
|
|
435
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
|
|
436
|
+
{
|
|
437
|
+
const char *whitespace = " \t\n\r\f\v";
|
|
438
|
+
std::string result = thisVal.as_string()->value;
|
|
439
|
+
result.erase(0, result.find_first_not_of(whitespace));
|
|
440
|
+
return AnyValue::make_string(result); },
|
|
441
|
+
"trimStart");
|
|
442
|
+
return fn;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
std::optional<AnyValue> get(const std::string &key)
|
|
446
|
+
{
|
|
447
|
+
if (key == "toString" || key == "valueOf") return get_toString_fn();
|
|
448
|
+
if (key == "length") return get_length_desc();
|
|
449
|
+
if (key == "charAt") return get_charAt_fn();
|
|
450
|
+
if (key == "concat") return get_concat_fn();
|
|
451
|
+
if (key == "endsWith") return get_endsWith_fn();
|
|
452
|
+
if (key == "includes") return get_includes_fn();
|
|
453
|
+
if (key == "indexOf") return get_indexOf_fn();
|
|
454
|
+
if (key == "lastIndexOf") return get_lastIndexOf_fn();
|
|
455
|
+
if (key == "padEnd") return get_padEnd_fn();
|
|
456
|
+
if (key == "padStart") return get_padStart_fn();
|
|
457
|
+
if (key == "repeat") return get_repeat_fn();
|
|
458
|
+
if (key == "replace") return get_replace_fn();
|
|
459
|
+
if (key == "replaceAll") return get_replaceAll_fn();
|
|
460
|
+
if (key == "slice") return get_slice_fn();
|
|
461
|
+
if (key == "split") return get_split_fn();
|
|
462
|
+
if (key == "startsWith") return get_startsWith_fn();
|
|
463
|
+
if (key == "substring") return get_substring_fn();
|
|
464
|
+
if (key == "toLowerCase") return get_toLowerCase_fn();
|
|
465
|
+
if (key == "toUpperCase") return get_toUpperCase_fn();
|
|
466
|
+
if (key == "trim") return get_trim_fn();
|
|
467
|
+
if (key == "trimEnd") return get_trimEnd_fn();
|
|
468
|
+
if (key == "trimStart") return get_trimStart_fn();
|
|
469
|
+
return std::nullopt;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
std::optional<AnyValue> get(const AnyValue &key)
|
|
473
|
+
{
|
|
474
|
+
if (key.is_string())
|
|
475
|
+
return get(key.as_string()->value);
|
|
476
|
+
|
|
477
|
+
if (key == AnyValue::from_symbol(WellKnownSymbols::toStringTag)) return get_toString_fn();
|
|
478
|
+
if (key == AnyValue::from_symbol(WellKnownSymbols::iterator)) return get_iterator_fn();
|
|
479
|
+
|
|
480
|
+
return std::nullopt;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
} // namespace StringPrototypes
|
|
484
|
+
|
|
485
|
+
} // namespace jspp
|
|
@@ -1,27 +1,26 @@
|
|
|
1
|
-
#pragma once
|
|
2
|
-
|
|
3
|
-
#include "types.hpp"
|
|
4
|
-
#include <string>
|
|
5
|
-
#include <unordered_map>
|
|
6
|
-
|
|
7
|
-
namespace jspp
|
|
8
|
-
{
|
|
9
|
-
// Forward declaration of AnyValue
|
|
10
|
-
class AnyValue;
|
|
11
|
-
|
|
12
|
-
struct JsString : HeapObject
|
|
13
|
-
{
|
|
14
|
-
std::string value;
|
|
15
|
-
|
|
16
|
-
JsString() = default;
|
|
17
|
-
explicit JsString(const std::string &s) : value(s) {}
|
|
18
|
-
|
|
19
|
-
JsType get_heap_type() const override { return JsType::String; }
|
|
20
|
-
|
|
21
|
-
std::string to_std_string() const;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
AnyValue get_property(
|
|
25
|
-
|
|
26
|
-
};
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "types.hpp"
|
|
4
|
+
#include <string>
|
|
5
|
+
#include <unordered_map>
|
|
6
|
+
|
|
7
|
+
namespace jspp
|
|
8
|
+
{
|
|
9
|
+
// Forward declaration of AnyValue
|
|
10
|
+
class AnyValue;
|
|
11
|
+
|
|
12
|
+
struct JsString : HeapObject
|
|
13
|
+
{
|
|
14
|
+
std::string value;
|
|
15
|
+
|
|
16
|
+
JsString() = default;
|
|
17
|
+
explicit JsString(const std::string &s) : value(s) {}
|
|
18
|
+
|
|
19
|
+
JsType get_heap_type() const override { return JsType::String; }
|
|
20
|
+
|
|
21
|
+
std::string to_std_string() const;
|
|
22
|
+
|
|
23
|
+
AnyValue get_property(const std::string &key, const AnyValue &thisVal);
|
|
24
|
+
AnyValue get_property(uint32_t idx);
|
|
25
|
+
};
|
|
27
26
|
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#include "jspp.hpp"
|
|
2
|
+
#include "values/symbol.hpp"
|
|
3
|
+
#include "values/prototypes/symbol.hpp"
|
|
4
|
+
|
|
5
|
+
namespace jspp {
|
|
6
|
+
|
|
7
|
+
// --- JsSymbol Implementation ---
|
|
8
|
+
|
|
9
|
+
std::string JsSymbol::to_std_string() const
|
|
10
|
+
{
|
|
11
|
+
return "Symbol(" + description + ")";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
AnyValue JsSymbol::get_property(const std::string &key, const AnyValue &thisVal)
|
|
15
|
+
{
|
|
16
|
+
auto proto_it = SymbolPrototypes::get(key);
|
|
17
|
+
if (proto_it.has_value())
|
|
18
|
+
{
|
|
19
|
+
return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key);
|
|
20
|
+
}
|
|
21
|
+
return Constants::UNDEFINED;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// --- SymbolPrototypes Implementation ---
|
|
25
|
+
|
|
26
|
+
namespace SymbolPrototypes {
|
|
27
|
+
|
|
28
|
+
AnyValue &get_toString_fn()
|
|
29
|
+
{
|
|
30
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue>) -> AnyValue
|
|
31
|
+
{ return AnyValue::make_string(thisVal.as_symbol()->to_std_string()); },
|
|
32
|
+
"toString");
|
|
33
|
+
return fn;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
AnyValue &get_valueOf_fn()
|
|
37
|
+
{
|
|
38
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue>) -> AnyValue
|
|
39
|
+
{ return thisVal; },
|
|
40
|
+
"valueOf");
|
|
41
|
+
return fn;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
AnyValue &get_toPrimitive_fn()
|
|
45
|
+
{
|
|
46
|
+
static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue>) -> AnyValue
|
|
47
|
+
{ return thisVal; },
|
|
48
|
+
"[Symbol.toPrimitive]");
|
|
49
|
+
return fn;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
AnyValue &get_description_desc()
|
|
53
|
+
{
|
|
54
|
+
static auto getter = [](const AnyValue &thisVal, std::span<const AnyValue>) -> AnyValue
|
|
55
|
+
{
|
|
56
|
+
auto self = thisVal.as_symbol();
|
|
57
|
+
if (self->description.empty())
|
|
58
|
+
{
|
|
59
|
+
return Constants::UNDEFINED;
|
|
60
|
+
}
|
|
61
|
+
return AnyValue::make_string(self->description);
|
|
62
|
+
};
|
|
63
|
+
static AnyValue desc = AnyValue::make_accessor_descriptor(getter, std::nullopt, false, true);
|
|
64
|
+
return desc;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
std::optional<AnyValue> get(const std::string &key)
|
|
68
|
+
{
|
|
69
|
+
if (key == "toString") return get_toString_fn();
|
|
70
|
+
if (key == "valueOf") return get_valueOf_fn();
|
|
71
|
+
if (key == "description") return get_description_desc();
|
|
72
|
+
return std::nullopt;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
std::optional<AnyValue> get(const AnyValue &key)
|
|
76
|
+
{
|
|
77
|
+
if (key.is_string())
|
|
78
|
+
return get(key.as_string()->value);
|
|
79
|
+
|
|
80
|
+
if (key == AnyValue::from_symbol(WellKnownSymbols::toStringTag)) return get_toString_fn();
|
|
81
|
+
if (key == "valueOf") return get_valueOf_fn();
|
|
82
|
+
if (key == AnyValue::from_symbol(WellKnownSymbols::toPrimitive)) return get_toPrimitive_fn();
|
|
83
|
+
|
|
84
|
+
return std::nullopt;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
} // namespace SymbolPrototypes
|
|
88
|
+
|
|
89
|
+
} // namespace jspp
|