@ugo-studio/jspp 0.1.0
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 +21 -0
- package/README.md +162 -0
- package/dist/analysis/scope.js +77 -0
- package/dist/analysis/typeAnalyzer.js +224 -0
- package/dist/ast/types.js +1 -0
- package/dist/cli.js +63 -0
- package/dist/core/codegen/declaration-handlers.js +49 -0
- package/dist/core/codegen/expression-handlers.js +333 -0
- package/dist/core/codegen/function-handlers.js +94 -0
- package/dist/core/codegen/helpers.js +83 -0
- package/dist/core/codegen/index.js +54 -0
- package/dist/core/codegen/literal-handlers.js +32 -0
- package/dist/core/codegen/statement-handlers.js +485 -0
- package/dist/core/codegen/visitor.js +86 -0
- package/dist/core/parser.js +6 -0
- package/dist/core/traverser.js +19 -0
- package/dist/index.js +16 -0
- package/package.json +41 -0
- package/src/prelude/access.hpp +86 -0
- package/src/prelude/any_value.hpp +734 -0
- package/src/prelude/descriptors.hpp +25 -0
- package/src/prelude/error.hpp +31 -0
- package/src/prelude/error_helpers.hpp +59 -0
- package/src/prelude/index.hpp +29 -0
- package/src/prelude/library/console.hpp +111 -0
- package/src/prelude/library/global.hpp +10 -0
- package/src/prelude/library/symbol.hpp +8 -0
- package/src/prelude/log_string.hpp +403 -0
- package/src/prelude/operators.hpp +256 -0
- package/src/prelude/types.hpp +50 -0
- package/src/prelude/values/array.hpp +50 -0
- package/src/prelude/values/function.hpp +19 -0
- package/src/prelude/values/non_values.hpp +20 -0
- package/src/prelude/values/object.hpp +17 -0
- package/src/prelude/values/operators/array.hpp +165 -0
- package/src/prelude/values/operators/function.hpp +34 -0
- package/src/prelude/values/operators/object.hpp +34 -0
- package/src/prelude/values/prototypes/array.hpp +228 -0
- package/src/prelude/values/prototypes/function.hpp +0 -0
- package/src/prelude/values/prototypes/object.hpp +0 -0
- package/src/prelude/values/prototypes/string.hpp +357 -0
- package/src/prelude/well_known_symbols.hpp +10 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "types.hpp"
|
|
4
|
+
#include "values/array.hpp"
|
|
5
|
+
#include "any_value.hpp"
|
|
6
|
+
#include "error.hpp"
|
|
7
|
+
#include "operators.hpp"
|
|
8
|
+
#include <algorithm>
|
|
9
|
+
#include <vector>
|
|
10
|
+
|
|
11
|
+
namespace jspp
|
|
12
|
+
{
|
|
13
|
+
namespace ArrayPrototypes
|
|
14
|
+
{
|
|
15
|
+
inline std::optional<AnyValue> get(const std::string &key, JsArray *self)
|
|
16
|
+
{
|
|
17
|
+
|
|
18
|
+
// --- toString() method ---
|
|
19
|
+
if (key == "toString")
|
|
20
|
+
{
|
|
21
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
22
|
+
{ return AnyValue::make_string(self->to_std_string()); },
|
|
23
|
+
key);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// --- length property ---
|
|
27
|
+
if (key == "length")
|
|
28
|
+
{
|
|
29
|
+
auto getter = [&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
30
|
+
{
|
|
31
|
+
return AnyValue::make_number(self->length);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
auto setter = [&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
35
|
+
{
|
|
36
|
+
if (args.empty())
|
|
37
|
+
{
|
|
38
|
+
return AnyValue::make_undefined();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const auto &new_len_val = args[0];
|
|
42
|
+
double new_len_double = Operators_Private::ToNumber(new_len_val);
|
|
43
|
+
|
|
44
|
+
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))
|
|
45
|
+
{
|
|
46
|
+
throw RuntimeError::make_error("Invalid array length", "RangeError");
|
|
47
|
+
}
|
|
48
|
+
uint64_t new_len = static_cast<uint64_t>(new_len_double);
|
|
49
|
+
|
|
50
|
+
// Truncate dense part
|
|
51
|
+
if (new_len < self->dense.size())
|
|
52
|
+
{
|
|
53
|
+
self->dense.resize(new_len);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Remove sparse elements beyond the new length
|
|
57
|
+
for (auto it = self->sparse.begin(); it != self->sparse.end();)
|
|
58
|
+
{
|
|
59
|
+
if (it->first >= new_len)
|
|
60
|
+
{
|
|
61
|
+
it = self->sparse.erase(it);
|
|
62
|
+
}
|
|
63
|
+
else
|
|
64
|
+
{
|
|
65
|
+
++it;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
self->length = new_len;
|
|
70
|
+
return new_len_val;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
return AnyValue::make_accessor_descriptor(getter,
|
|
74
|
+
setter,
|
|
75
|
+
false,
|
|
76
|
+
false);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// --- push() method ---
|
|
80
|
+
if (key == "push")
|
|
81
|
+
{
|
|
82
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
83
|
+
{
|
|
84
|
+
for (const auto &arg : args)
|
|
85
|
+
{
|
|
86
|
+
self->set_property(static_cast<uint32_t>(self->length), arg);
|
|
87
|
+
}
|
|
88
|
+
return AnyValue::make_number(self->length); },
|
|
89
|
+
key);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// --- pop() method ---
|
|
93
|
+
if (key == "pop")
|
|
94
|
+
{
|
|
95
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
96
|
+
{
|
|
97
|
+
if (self->length == 0)
|
|
98
|
+
{
|
|
99
|
+
return AnyValue::make_undefined();
|
|
100
|
+
}
|
|
101
|
+
uint64_t last_idx = self->length - 1;
|
|
102
|
+
AnyValue last_val = self->get_property(static_cast<uint32_t>(last_idx));
|
|
103
|
+
|
|
104
|
+
// Remove from dense
|
|
105
|
+
if (last_idx < self->dense.size())
|
|
106
|
+
{
|
|
107
|
+
self->dense.pop_back();
|
|
108
|
+
}
|
|
109
|
+
// Remove from sparse
|
|
110
|
+
self->sparse.erase(static_cast<uint32_t>(last_idx));
|
|
111
|
+
|
|
112
|
+
self->length--;
|
|
113
|
+
return last_val; },
|
|
114
|
+
key);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// --- shift() method ---
|
|
118
|
+
if (key == "shift")
|
|
119
|
+
{
|
|
120
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
121
|
+
{
|
|
122
|
+
if (self->length == 0)
|
|
123
|
+
{
|
|
124
|
+
return AnyValue::make_undefined();
|
|
125
|
+
}
|
|
126
|
+
AnyValue first_val = self->get_property(0u);
|
|
127
|
+
|
|
128
|
+
// Shift all elements to the left
|
|
129
|
+
for (uint64_t i = 0; i < self->length - 1; ++i)
|
|
130
|
+
{
|
|
131
|
+
self->set_property(static_cast<uint32_t>(i), self->get_property(static_cast<uint32_t>(i + 1)));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// remove last element
|
|
135
|
+
uint64_t last_idx = self->length - 1;
|
|
136
|
+
if (last_idx < self->dense.size())
|
|
137
|
+
{
|
|
138
|
+
self->dense.pop_back();
|
|
139
|
+
}
|
|
140
|
+
self->sparse.erase(static_cast<uint32_t>(last_idx));
|
|
141
|
+
|
|
142
|
+
self->length--;
|
|
143
|
+
|
|
144
|
+
return first_val; },
|
|
145
|
+
key);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// --- unshift() method ---
|
|
149
|
+
if (key == "unshift")
|
|
150
|
+
{
|
|
151
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
152
|
+
{
|
|
153
|
+
size_t args_count = args.size();
|
|
154
|
+
if (args_count == 0)
|
|
155
|
+
{
|
|
156
|
+
return AnyValue::make_number(self->length);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Shift existing elements to the right
|
|
160
|
+
for (uint64_t i = self->length; i > 0; --i)
|
|
161
|
+
{
|
|
162
|
+
self->set_property(static_cast<uint32_t>(i + args_count - 1), self->get_property(static_cast<uint32_t>(i - 1)));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Insert new elements at the beginning
|
|
166
|
+
for (size_t i = 0; i < args_count; ++i)
|
|
167
|
+
{
|
|
168
|
+
self->set_property(static_cast<uint32_t>(i), args[i]);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return AnyValue::make_number(self->length); },
|
|
172
|
+
key);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// --- join() method ---
|
|
176
|
+
if (key == "join")
|
|
177
|
+
{
|
|
178
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
179
|
+
{
|
|
180
|
+
std::string sep = ",";
|
|
181
|
+
if (!args.empty() && !args[0].is_undefined())
|
|
182
|
+
{
|
|
183
|
+
sep = args[0].to_std_string();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
std::string result = "";
|
|
187
|
+
for (uint64_t i = 0; i < self->length; ++i)
|
|
188
|
+
{
|
|
189
|
+
AnyValue item = self->get_property(static_cast<uint32_t>(i));
|
|
190
|
+
if (!item.is_undefined() && !item.is_null())
|
|
191
|
+
{
|
|
192
|
+
result += item.to_std_string();
|
|
193
|
+
}
|
|
194
|
+
if (i < self->length - 1)
|
|
195
|
+
{
|
|
196
|
+
result += sep;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return AnyValue::make_string(result); },
|
|
200
|
+
key);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// --- forEach() method ---
|
|
204
|
+
if (key == "forEach")
|
|
205
|
+
{
|
|
206
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
207
|
+
{
|
|
208
|
+
if (args.empty() || !args[0].is_function())
|
|
209
|
+
{
|
|
210
|
+
throw RuntimeError::make_error("callback is not a function", "TypeError");
|
|
211
|
+
}
|
|
212
|
+
auto callback = args[0].as_function();
|
|
213
|
+
for (uint64_t i = 0; i < self->length; ++i)
|
|
214
|
+
{
|
|
215
|
+
AnyValue val = self->get_property(static_cast<uint32_t>(i));
|
|
216
|
+
if (!val.is_undefined())
|
|
217
|
+
{ // forEach skips empty slots
|
|
218
|
+
callback->call({val, AnyValue::make_number(i)});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return AnyValue::make_undefined(); },
|
|
222
|
+
key);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return std::nullopt;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "types.hpp"
|
|
4
|
+
#include "any_value.hpp"
|
|
5
|
+
#include "operators.hpp"
|
|
6
|
+
#include <optional>
|
|
7
|
+
#include <string>
|
|
8
|
+
#include <vector>
|
|
9
|
+
#include <algorithm>
|
|
10
|
+
#include <cctype>
|
|
11
|
+
|
|
12
|
+
namespace jspp
|
|
13
|
+
{
|
|
14
|
+
namespace StringPrototypes
|
|
15
|
+
{
|
|
16
|
+
// This function retrieves a prototype method for a given string instance.
|
|
17
|
+
// It captures the string instance to act as the 'this' context for the method.
|
|
18
|
+
inline std::optional<AnyValue> get(const std::string &key, const std::unique_ptr<std::string> &self)
|
|
19
|
+
{
|
|
20
|
+
// --- toString() & valueOf() ---
|
|
21
|
+
if (key == "toString" || key == "valueOf")
|
|
22
|
+
{
|
|
23
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
24
|
+
{ return AnyValue::make_string(*self); },
|
|
25
|
+
key);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// --- length property ---
|
|
29
|
+
if (key == "length")
|
|
30
|
+
{
|
|
31
|
+
return AnyValue::make_accessor_descriptor([&self](const std::vector<AnyValue>) -> AnyValue
|
|
32
|
+
{ return AnyValue::make_number(self->length()); },
|
|
33
|
+
[&self](const std::vector<AnyValue>) -> AnyValue
|
|
34
|
+
{ return AnyValue::make_undefined(); },
|
|
35
|
+
false,
|
|
36
|
+
false);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// --- charAt(pos) ---
|
|
40
|
+
if (key == "charAt")
|
|
41
|
+
{
|
|
42
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
43
|
+
{
|
|
44
|
+
double pos = args.empty() ? 0 : Operators_Private::ToNumber(args[0]);
|
|
45
|
+
int index = static_cast<int>(pos);
|
|
46
|
+
if (index < 0 || index >= self->length()) {
|
|
47
|
+
return AnyValue::make_string("");
|
|
48
|
+
}
|
|
49
|
+
return AnyValue::make_string(std::string(1, (*self)[index])); },
|
|
50
|
+
key);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// --- concat(str1, str2, ...) ---
|
|
54
|
+
if (key == "concat")
|
|
55
|
+
{
|
|
56
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
57
|
+
{
|
|
58
|
+
std::string result = *self;
|
|
59
|
+
for (const auto& arg : args)
|
|
60
|
+
{
|
|
61
|
+
result += arg.to_std_string();
|
|
62
|
+
}
|
|
63
|
+
return AnyValue::make_string(result); },
|
|
64
|
+
key);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// --- endsWith(searchString, endPosition) ---
|
|
68
|
+
if (key == "endsWith")
|
|
69
|
+
{
|
|
70
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
71
|
+
{
|
|
72
|
+
if(args.empty()) return AnyValue::make_boolean(false);
|
|
73
|
+
std::string search = args[0].to_std_string();
|
|
74
|
+
size_t end_pos = (args.size() > 1 && !args[1].is_undefined()) ? static_cast<size_t>(Operators_Private::ToNumber(args[1])) : self->length();
|
|
75
|
+
|
|
76
|
+
if (end_pos > self->length()) end_pos = self->length();
|
|
77
|
+
if (search.length() > end_pos) return AnyValue::make_boolean(false);
|
|
78
|
+
|
|
79
|
+
return AnyValue::make_boolean(self->substr(end_pos - search.length(), search.length()) == search); },
|
|
80
|
+
key);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// --- includes(searchString, position) ---
|
|
84
|
+
if (key == "includes")
|
|
85
|
+
{
|
|
86
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
87
|
+
{
|
|
88
|
+
if(args.empty()) return AnyValue::make_boolean(false);
|
|
89
|
+
std::string search = args[0].to_std_string();
|
|
90
|
+
size_t pos = (args.size() > 1) ? static_cast<size_t>(Operators_Private::ToNumber(args[1])) : 0;
|
|
91
|
+
|
|
92
|
+
return AnyValue::make_boolean(self->find(search, pos) != std::string::npos); },
|
|
93
|
+
key);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// --- indexOf(searchString, position) ---
|
|
97
|
+
if (key == "indexOf")
|
|
98
|
+
{
|
|
99
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
100
|
+
{
|
|
101
|
+
if (args.empty()) return AnyValue::make_number(-1);
|
|
102
|
+
std::string search = args[0].to_std_string();
|
|
103
|
+
size_t pos = (args.size() > 1) ? static_cast<size_t>(Operators_Private::ToNumber(args[1])) : 0;
|
|
104
|
+
size_t result = self->find(search, pos);
|
|
105
|
+
return result == std::string::npos ? AnyValue::make_number(-1) : AnyValue::make_number(result); },
|
|
106
|
+
key);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// --- lastIndexOf(searchString, position) ---
|
|
110
|
+
if (key == "lastIndexOf")
|
|
111
|
+
{
|
|
112
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
113
|
+
{
|
|
114
|
+
if (args.empty()) return AnyValue::make_number(-1);
|
|
115
|
+
std::string search = args[0].to_std_string();
|
|
116
|
+
size_t pos = (args.size() > 1 && !args[1].is_undefined()) ? static_cast<size_t>(Operators_Private::ToNumber(args[1])) : std::string::npos;
|
|
117
|
+
size_t result = self->rfind(search, pos);
|
|
118
|
+
return result == std::string::npos ? AnyValue::make_number(-1) : AnyValue::make_number(result); },
|
|
119
|
+
key);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// --- padEnd(targetLength, padString) ---
|
|
123
|
+
if (key == "padEnd")
|
|
124
|
+
{
|
|
125
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
126
|
+
{
|
|
127
|
+
size_t target_length = args.empty() ? 0 : static_cast<size_t>(Operators_Private::ToNumber(args[0]));
|
|
128
|
+
if (self->length() >= target_length) return AnyValue::make_string(*self);
|
|
129
|
+
std::string pad_string = (args.size() > 1 && !args[1].is_undefined() && !args[1].to_std_string().empty()) ? args[1].to_std_string() : " ";
|
|
130
|
+
std::string result = *self;
|
|
131
|
+
while (result.length() < target_length)
|
|
132
|
+
{
|
|
133
|
+
result += pad_string;
|
|
134
|
+
}
|
|
135
|
+
return AnyValue::make_string(result.substr(0, target_length)); },
|
|
136
|
+
key);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// --- padStart(targetLength, padString) ---
|
|
140
|
+
if (key == "padStart")
|
|
141
|
+
{
|
|
142
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
143
|
+
{
|
|
144
|
+
size_t target_length = args.empty() ? 0 : static_cast<size_t>(Operators_Private::ToNumber(args[0]));
|
|
145
|
+
if (self->length() >= target_length) return AnyValue::make_string(*self);
|
|
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 padding;
|
|
148
|
+
while (padding.length() < target_length - self->length())
|
|
149
|
+
{
|
|
150
|
+
padding += pad_string;
|
|
151
|
+
}
|
|
152
|
+
return AnyValue::make_string(padding.substr(0, target_length - self->length()) + *self); },
|
|
153
|
+
key);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// --- repeat(count) ---
|
|
157
|
+
if (key == "repeat")
|
|
158
|
+
{
|
|
159
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
160
|
+
{
|
|
161
|
+
double count = args.empty() ? 0 : Operators_Private::ToNumber(args[0]);
|
|
162
|
+
if (count < 0) {
|
|
163
|
+
// In a real implementation, this should throw a RangeError.
|
|
164
|
+
return AnyValue::make_string("");
|
|
165
|
+
}
|
|
166
|
+
std::string result = "";
|
|
167
|
+
for (int i = 0; i < count; ++i)
|
|
168
|
+
{
|
|
169
|
+
result += *self;
|
|
170
|
+
}
|
|
171
|
+
return AnyValue::make_string(result); },
|
|
172
|
+
key);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// --- replace(substr, newSubstr) ---
|
|
176
|
+
if (key == "replace")
|
|
177
|
+
{
|
|
178
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
179
|
+
{
|
|
180
|
+
if (args.size() < 2) return AnyValue::make_string(*self);
|
|
181
|
+
std::string search = args[0].to_std_string();
|
|
182
|
+
std::string replacement = args[1].to_std_string();
|
|
183
|
+
std::string result = *self;
|
|
184
|
+
size_t pos = result.find(search);
|
|
185
|
+
if (pos != std::string::npos)
|
|
186
|
+
{
|
|
187
|
+
result.replace(pos, search.length(), replacement);
|
|
188
|
+
}
|
|
189
|
+
return AnyValue::make_string(result); },
|
|
190
|
+
key);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// --- replaceAll(substr, newSubstr) ---
|
|
194
|
+
if (key == "replaceAll")
|
|
195
|
+
{
|
|
196
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
197
|
+
{
|
|
198
|
+
if (args.size() < 2) return AnyValue::make_string(*self);
|
|
199
|
+
std::string search = args[0].to_std_string();
|
|
200
|
+
if (search.empty()) return AnyValue::make_string(*self);
|
|
201
|
+
std::string replacement = args[1].to_std_string();
|
|
202
|
+
std::string result = *self;
|
|
203
|
+
size_t pos = result.find(search);
|
|
204
|
+
while (pos != std::string::npos)
|
|
205
|
+
{
|
|
206
|
+
result.replace(pos, search.length(), replacement);
|
|
207
|
+
pos = result.find(search, pos + replacement.length());
|
|
208
|
+
}
|
|
209
|
+
return AnyValue::make_string(result); },
|
|
210
|
+
key);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// --- slice(beginIndex, endIndex) ---
|
|
214
|
+
if (key == "slice")
|
|
215
|
+
{
|
|
216
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
217
|
+
{
|
|
218
|
+
int len = self->length();
|
|
219
|
+
int start = args.empty() ? 0 : Operators_Private::ToInt32(args[0]);
|
|
220
|
+
int end = (args.size() < 2 || args[1].is_undefined()) ? len : Operators_Private::ToInt32(args[1]);
|
|
221
|
+
|
|
222
|
+
if (start < 0) start += len;
|
|
223
|
+
if (end < 0) end += len;
|
|
224
|
+
|
|
225
|
+
start = std::max(0, std::min(len, start));
|
|
226
|
+
end = std::max(0, std::min(len, end));
|
|
227
|
+
|
|
228
|
+
if (start >= end) return AnyValue::make_string("");
|
|
229
|
+
return AnyValue::make_string(self->substr(start, end - start)); },
|
|
230
|
+
key);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// --- split(separator) ---
|
|
234
|
+
if (key == "split")
|
|
235
|
+
{
|
|
236
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
237
|
+
{
|
|
238
|
+
std::string separator = (args.empty() || args[0].is_undefined()) ? "" : args[0].to_std_string();
|
|
239
|
+
std::vector<std::optional<AnyValue>> result_vec;
|
|
240
|
+
|
|
241
|
+
if (separator.empty()) {
|
|
242
|
+
for (char c : (*self)) {
|
|
243
|
+
result_vec.push_back(AnyValue::make_string(std::string(1, c)));
|
|
244
|
+
}
|
|
245
|
+
} else {
|
|
246
|
+
std::string temp = (*self);
|
|
247
|
+
size_t pos = 0;
|
|
248
|
+
while ((pos = temp.find(separator)) != std::string::npos) {
|
|
249
|
+
result_vec.push_back(AnyValue::make_string(temp.substr(0, pos)));
|
|
250
|
+
temp.erase(0, pos + separator.length());
|
|
251
|
+
}
|
|
252
|
+
result_vec.push_back(AnyValue::make_string(temp));
|
|
253
|
+
}
|
|
254
|
+
return AnyValue::make_array(result_vec); },
|
|
255
|
+
key);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// --- startsWith(searchString, position) ---
|
|
259
|
+
if (key == "startsWith")
|
|
260
|
+
{
|
|
261
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
262
|
+
{
|
|
263
|
+
if(args.empty()) return AnyValue::make_boolean(false);
|
|
264
|
+
std::string search = args[0].to_std_string();
|
|
265
|
+
size_t pos = (args.size() > 1) ? static_cast<size_t>(Operators_Private::ToNumber(args[1])) : 0;
|
|
266
|
+
if (pos > self->length()) pos = self->length();
|
|
267
|
+
|
|
268
|
+
return AnyValue::make_boolean(self->rfind(search, pos) == pos); },
|
|
269
|
+
key);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// --- substring(indexStart, indexEnd) ---
|
|
273
|
+
if (key == "substring")
|
|
274
|
+
{
|
|
275
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
276
|
+
{
|
|
277
|
+
int len = self->length();
|
|
278
|
+
int start = args.empty() ? 0 : Operators_Private::ToInt32(args[0]);
|
|
279
|
+
int end = (args.size() < 2 || args[1].is_undefined()) ? len : Operators_Private::ToInt32(args[1]);
|
|
280
|
+
|
|
281
|
+
start = std::max(0, start);
|
|
282
|
+
end = std::max(0, end);
|
|
283
|
+
|
|
284
|
+
if (start > end) std::swap(start, end);
|
|
285
|
+
|
|
286
|
+
start = std::min(len, start);
|
|
287
|
+
end = std::min(len, end);
|
|
288
|
+
|
|
289
|
+
return AnyValue::make_string(self->substr(start, end - start)); },
|
|
290
|
+
key);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// --- toLowerCase() ---
|
|
294
|
+
if (key == "toLowerCase")
|
|
295
|
+
{
|
|
296
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
297
|
+
{
|
|
298
|
+
std::string result = *self;
|
|
299
|
+
std::transform(result.begin(), result.end(), result.begin(),
|
|
300
|
+
[](unsigned char c){ return std::tolower(c); });
|
|
301
|
+
return AnyValue::make_string(result); },
|
|
302
|
+
key);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// --- toUpperCase() ---
|
|
306
|
+
if (key == "toUpperCase")
|
|
307
|
+
{
|
|
308
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
309
|
+
{
|
|
310
|
+
std::string result = *self;
|
|
311
|
+
std::transform(result.begin(), result.end(), result.begin(),
|
|
312
|
+
[](unsigned char c){ return std::toupper(c); });
|
|
313
|
+
return AnyValue::make_string(result); },
|
|
314
|
+
key);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// --- trim() ---
|
|
318
|
+
if (key == "trim")
|
|
319
|
+
{
|
|
320
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
321
|
+
{
|
|
322
|
+
const char* whitespace = " \t\n\r\f\v";
|
|
323
|
+
std::string result = *self;
|
|
324
|
+
result.erase(0, result.find_first_not_of(whitespace));
|
|
325
|
+
result.erase(result.find_last_not_of(whitespace) + 1);
|
|
326
|
+
return AnyValue::make_string(result); },
|
|
327
|
+
key);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// --- trimEnd() ---
|
|
331
|
+
if (key == "trimEnd")
|
|
332
|
+
{
|
|
333
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
334
|
+
{
|
|
335
|
+
const char* whitespace = " \t\n\r\f\v";
|
|
336
|
+
std::string result = *self;
|
|
337
|
+
result.erase(result.find_last_not_of(whitespace) + 1);
|
|
338
|
+
return AnyValue::make_string(result); },
|
|
339
|
+
key);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// --- trimStart() ---
|
|
343
|
+
if (key == "trimStart")
|
|
344
|
+
{
|
|
345
|
+
return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
|
|
346
|
+
{
|
|
347
|
+
const char* whitespace = " \t\n\r\f\v";
|
|
348
|
+
std::string result = *self;
|
|
349
|
+
result.erase(0, result.find_first_not_of(whitespace));
|
|
350
|
+
return AnyValue::make_string(result); },
|
|
351
|
+
key);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return std::nullopt;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|