@ugo-studio/jspp 0.2.9 → 0.3.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/dist/core/codegen/class-handlers.js +6 -6
- package/dist/core/codegen/statement-handlers.js +1 -1
- package/package.json +1 -1
- package/src/prelude/any_value.hpp +362 -362
- package/src/prelude/any_value_access.hpp +170 -170
- package/src/prelude/any_value_defines.hpp +189 -189
- package/src/prelude/any_value_helpers.hpp +374 -374
- package/src/prelude/library/array.hpp +185 -185
- package/src/prelude/library/console.hpp +111 -111
- package/src/prelude/library/error.hpp +112 -112
- package/src/prelude/library/function.hpp +10 -10
- package/src/prelude/library/math.hpp +307 -307
- package/src/prelude/library/object.hpp +275 -275
- package/src/prelude/library/process.hpp +39 -39
- package/src/prelude/library/promise.hpp +123 -123
- package/src/prelude/library/symbol.hpp +52 -52
- package/src/prelude/library/timer.hpp +91 -91
- package/src/prelude/types.hpp +178 -178
- package/src/prelude/utils/access.hpp +411 -411
- package/src/prelude/utils/operators.hpp +336 -336
- package/src/prelude/values/array.hpp +0 -1
- package/src/prelude/values/async_iterator.hpp +83 -83
- package/src/prelude/values/function.hpp +82 -82
- package/src/prelude/values/helpers/array.hpp +198 -208
- package/src/prelude/values/helpers/async_iterator.hpp +275 -275
- package/src/prelude/values/helpers/function.hpp +108 -108
- package/src/prelude/values/helpers/iterator.hpp +144 -144
- package/src/prelude/values/helpers/promise.hpp +253 -253
- package/src/prelude/values/helpers/string.hpp +37 -61
- package/src/prelude/values/promise.hpp +72 -72
- package/src/prelude/values/prototypes/array.hpp +14 -2
- package/src/prelude/values/prototypes/iterator.hpp +201 -201
- package/src/prelude/values/prototypes/promise.hpp +196 -196
- package/src/prelude/values/prototypes/string.hpp +564 -542
- package/src/prelude/values/string.hpp +25 -26
|
@@ -1,374 +1,374 @@
|
|
|
1
|
-
#pragma once
|
|
2
|
-
|
|
3
|
-
#include "types.hpp"
|
|
4
|
-
#include "any_value.hpp"
|
|
5
|
-
#include "values/string.hpp"
|
|
6
|
-
#include "values/object.hpp"
|
|
7
|
-
#include "values/array.hpp"
|
|
8
|
-
#include "values/function.hpp"
|
|
9
|
-
#include "values/iterator.hpp"
|
|
10
|
-
#include "values/async_iterator.hpp"
|
|
11
|
-
#include "values/promise.hpp"
|
|
12
|
-
#include "values/symbol.hpp"
|
|
13
|
-
#include "values/descriptors.hpp"
|
|
14
|
-
#include "exception.hpp"
|
|
15
|
-
|
|
16
|
-
namespace jspp
|
|
17
|
-
{
|
|
18
|
-
// --- AnyValue GETTERS ---
|
|
19
|
-
inline JsString *AnyValue::as_string() const noexcept { return static_cast<JsString *>(get_ptr()); }
|
|
20
|
-
inline JsObject *AnyValue::as_object() const noexcept { return static_cast<JsObject *>(get_ptr()); }
|
|
21
|
-
inline JsArray *AnyValue::as_array() const noexcept { return static_cast<JsArray *>(get_ptr()); }
|
|
22
|
-
inline JsFunction *AnyValue::as_function() const noexcept { return static_cast<JsFunction *>(get_ptr()); }
|
|
23
|
-
inline JsSymbol *AnyValue::as_symbol() const noexcept { return static_cast<JsSymbol *>(get_ptr()); }
|
|
24
|
-
inline JsPromise *AnyValue::as_promise() const noexcept { return static_cast<JsPromise *>(get_ptr()); }
|
|
25
|
-
inline JsIterator<AnyValue> *AnyValue::as_iterator() const noexcept { return static_cast<JsIterator<AnyValue> *>(get_ptr()); }
|
|
26
|
-
inline JsAsyncIterator<AnyValue> *AnyValue::as_async_iterator() const noexcept { return static_cast<JsAsyncIterator<AnyValue> *>(get_ptr()); }
|
|
27
|
-
inline DataDescriptor *AnyValue::as_data_descriptor() const noexcept { return static_cast<DataDescriptor *>(get_ptr()); }
|
|
28
|
-
inline AccessorDescriptor *AnyValue::as_accessor_descriptor() const noexcept { return static_cast<AccessorDescriptor *>(get_ptr()); }
|
|
29
|
-
|
|
30
|
-
inline bool AnyValue::is_generator() const noexcept { return is_function() && as_function()->is_generator; }
|
|
31
|
-
|
|
32
|
-
// --- AnyValue FACTORIES ---
|
|
33
|
-
inline AnyValue AnyValue::make_string(const std::string &raw_s) noexcept
|
|
34
|
-
{
|
|
35
|
-
return from_ptr(new JsString(raw_s));
|
|
36
|
-
}
|
|
37
|
-
inline AnyValue AnyValue::make_object(std::initializer_list<std::pair<std::string, AnyValue>> props) noexcept
|
|
38
|
-
{
|
|
39
|
-
return from_ptr(new JsObject(props, make_null()));
|
|
40
|
-
}
|
|
41
|
-
inline AnyValue AnyValue::make_object(const std::map<std::string, AnyValue> &props) noexcept
|
|
42
|
-
{
|
|
43
|
-
return from_ptr(new JsObject(props, make_null()));
|
|
44
|
-
}
|
|
45
|
-
inline AnyValue AnyValue::make_object_with_proto(std::initializer_list<std::pair<std::string, AnyValue>> props, AnyValue proto) noexcept
|
|
46
|
-
{
|
|
47
|
-
return from_ptr(new JsObject(props, proto));
|
|
48
|
-
}
|
|
49
|
-
inline AnyValue AnyValue::make_object_with_proto(const std::map<std::string, AnyValue> &props, AnyValue proto) noexcept
|
|
50
|
-
{
|
|
51
|
-
return from_ptr(new JsObject(props, proto));
|
|
52
|
-
}
|
|
53
|
-
inline AnyValue AnyValue::make_array(std::span<const AnyValue> dense) noexcept
|
|
54
|
-
{
|
|
55
|
-
std::vector<AnyValue> vec;
|
|
56
|
-
vec.reserve(dense.size());
|
|
57
|
-
for (const auto &item : dense)
|
|
58
|
-
vec.push_back(item);
|
|
59
|
-
return from_ptr(new JsArray(std::move(vec)));
|
|
60
|
-
}
|
|
61
|
-
inline AnyValue AnyValue::make_array(const std::vector<AnyValue> &dense) noexcept
|
|
62
|
-
{
|
|
63
|
-
return from_ptr(new JsArray(dense));
|
|
64
|
-
}
|
|
65
|
-
inline AnyValue AnyValue::make_array(std::vector<AnyValue> &&dense) noexcept
|
|
66
|
-
{
|
|
67
|
-
return from_ptr(new JsArray(std::move(dense)));
|
|
68
|
-
}
|
|
69
|
-
inline AnyValue AnyValue::make_array_with_proto(std::span<const AnyValue> dense, AnyValue proto) noexcept
|
|
70
|
-
{
|
|
71
|
-
auto arr = new JsArray();
|
|
72
|
-
arr->dense.reserve(dense.size());
|
|
73
|
-
for (const auto &item : dense)
|
|
74
|
-
arr->dense.push_back(item);
|
|
75
|
-
arr->length = dense.size();
|
|
76
|
-
arr->proto = proto;
|
|
77
|
-
return from_ptr(arr);
|
|
78
|
-
}
|
|
79
|
-
inline AnyValue AnyValue::make_array_with_proto(const std::vector<AnyValue> &dense, AnyValue proto) noexcept
|
|
80
|
-
{
|
|
81
|
-
auto arr = new JsArray(dense);
|
|
82
|
-
arr->proto = proto;
|
|
83
|
-
return from_ptr(arr);
|
|
84
|
-
}
|
|
85
|
-
inline AnyValue AnyValue::make_array_with_proto(std::vector<AnyValue> &&dense, AnyValue proto) noexcept
|
|
86
|
-
{
|
|
87
|
-
auto arr = new JsArray(std::move(dense));
|
|
88
|
-
arr->proto = proto;
|
|
89
|
-
return from_ptr(arr);
|
|
90
|
-
}
|
|
91
|
-
inline AnyValue AnyValue::make_function(const JsFunctionCallable &call, const std::optional<std::string> &name, bool is_constructor) noexcept
|
|
92
|
-
{
|
|
93
|
-
auto v = from_ptr(new JsFunction(call, name, {}, false, is_constructor));
|
|
94
|
-
auto proto = make_object({});
|
|
95
|
-
proto.define_data_property("constructor", AnyValue::make_data_descriptor(v, true, false, false));
|
|
96
|
-
v.define_data_property("prototype", AnyValue::make_data_descriptor(proto, false, false, false));
|
|
97
|
-
return v;
|
|
98
|
-
}
|
|
99
|
-
inline AnyValue AnyValue::make_class(const JsFunctionCallable &call, const std::optional<std::string> &name) noexcept
|
|
100
|
-
{
|
|
101
|
-
auto v = from_ptr(new JsFunction(call, name, {}, true));
|
|
102
|
-
auto proto = make_object({});
|
|
103
|
-
proto.define_data_property("constructor", AnyValue::make_data_descriptor(v, true, false, false));
|
|
104
|
-
v.define_data_property("prototype", AnyValue::make_data_descriptor(proto, false, false, false));
|
|
105
|
-
return v;
|
|
106
|
-
}
|
|
107
|
-
inline AnyValue AnyValue::make_generator(const JsFunctionCallable &call, const std::optional<std::string> &name) noexcept
|
|
108
|
-
{
|
|
109
|
-
auto v = from_ptr(new JsFunction(call, true, name));
|
|
110
|
-
auto proto = make_object({});
|
|
111
|
-
proto.define_data_property("constructor", AnyValue::make_data_descriptor(v, true, false, false));
|
|
112
|
-
v.define_data_property("prototype", AnyValue::make_data_descriptor(proto, false, false, false));
|
|
113
|
-
return v;
|
|
114
|
-
}
|
|
115
|
-
inline AnyValue AnyValue::make_async_function(const JsFunctionCallable &call, const std::optional<std::string> &name) noexcept
|
|
116
|
-
{
|
|
117
|
-
auto v = from_ptr(new JsFunction(call, false, true, name));
|
|
118
|
-
auto proto = make_object({});
|
|
119
|
-
proto.define_data_property("constructor", AnyValue::make_data_descriptor(v, true, false, false));
|
|
120
|
-
v.define_data_property("prototype", AnyValue::make_data_descriptor(proto, false, false, false));
|
|
121
|
-
return v;
|
|
122
|
-
}
|
|
123
|
-
inline AnyValue AnyValue::make_async_generator(const JsFunctionCallable &call, const std::optional<std::string> &name) noexcept
|
|
124
|
-
{
|
|
125
|
-
auto v = from_ptr(new JsFunction(call, true, true, name));
|
|
126
|
-
auto proto = make_object({});
|
|
127
|
-
proto.define_data_property("constructor", AnyValue::make_data_descriptor(v, true, false, false));
|
|
128
|
-
v.define_data_property("prototype", AnyValue::make_data_descriptor(proto, false, false, false));
|
|
129
|
-
return v;
|
|
130
|
-
}
|
|
131
|
-
inline AnyValue AnyValue::make_symbol(const std::string &description) noexcept
|
|
132
|
-
{
|
|
133
|
-
return from_ptr(new JsSymbol(description));
|
|
134
|
-
}
|
|
135
|
-
inline AnyValue AnyValue::make_promise(const JsPromise &promise) noexcept
|
|
136
|
-
{
|
|
137
|
-
auto p = new JsPromise();
|
|
138
|
-
*p = promise;
|
|
139
|
-
return from_ptr(p);
|
|
140
|
-
}
|
|
141
|
-
inline AnyValue AnyValue::make_data_descriptor(AnyValue value, bool writable, bool enumerable, bool configurable) noexcept
|
|
142
|
-
{
|
|
143
|
-
return from_ptr(new DataDescriptor(value, writable, enumerable, configurable));
|
|
144
|
-
}
|
|
145
|
-
inline AnyValue AnyValue::make_accessor_descriptor(const std::optional<std::function<AnyValue(AnyValue, std::span<const AnyValue>)>> &get,
|
|
146
|
-
const std::optional<std::function<AnyValue(AnyValue, std::span<const AnyValue>)>> &set,
|
|
147
|
-
bool enumerable,
|
|
148
|
-
bool configurable) noexcept
|
|
149
|
-
{
|
|
150
|
-
return from_ptr(new AccessorDescriptor(get, set, enumerable, configurable));
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
inline AnyValue AnyValue::from_symbol(JsSymbol *sym) noexcept
|
|
154
|
-
{
|
|
155
|
-
return from_ptr(sym);
|
|
156
|
-
}
|
|
157
|
-
inline AnyValue AnyValue::from_string(JsString *str) noexcept
|
|
158
|
-
{
|
|
159
|
-
return from_ptr(str);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
inline AnyValue AnyValue::from_promise(JsPromise &&promise) noexcept
|
|
163
|
-
{
|
|
164
|
-
auto it = new JsPromise(std::move(promise));
|
|
165
|
-
return from_ptr(it);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
inline AnyValue AnyValue::from_iterator(JsIterator<AnyValue> &&iterator) noexcept
|
|
169
|
-
{
|
|
170
|
-
auto it = new JsIterator<AnyValue>(std::move(iterator));
|
|
171
|
-
return from_ptr(it);
|
|
172
|
-
}
|
|
173
|
-
inline AnyValue AnyValue::from_iterator_ref(JsIterator<AnyValue> *iterator) noexcept
|
|
174
|
-
{
|
|
175
|
-
return from_ptr(iterator);
|
|
176
|
-
}
|
|
177
|
-
inline AnyValue AnyValue::from_async_iterator(JsAsyncIterator<AnyValue> &&iterator) noexcept
|
|
178
|
-
{
|
|
179
|
-
auto it = new JsAsyncIterator<AnyValue>(std::move(iterator));
|
|
180
|
-
return from_ptr(it);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
inline AnyValue AnyValue::resolve_property_for_read(const AnyValue &val, AnyValue thisVal, const std::string &propName) noexcept
|
|
184
|
-
{
|
|
185
|
-
if (val.is_data_descriptor())
|
|
186
|
-
{
|
|
187
|
-
return val.as_data_descriptor()->value;
|
|
188
|
-
}
|
|
189
|
-
if (val.is_accessor_descriptor())
|
|
190
|
-
{
|
|
191
|
-
auto accessor = val.as_accessor_descriptor();
|
|
192
|
-
if (accessor->get.has_value())
|
|
193
|
-
return accessor->get.value()(thisVal, std::span<const AnyValue>{});
|
|
194
|
-
else
|
|
195
|
-
{
|
|
196
|
-
return Constants::UNDEFINED;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
return val;
|
|
200
|
-
}
|
|
201
|
-
inline AnyValue AnyValue::resolve_property_for_write(AnyValue &val, AnyValue thisVal, const AnyValue &new_val, const std::string &propName)
|
|
202
|
-
{
|
|
203
|
-
if (val.is_data_descriptor())
|
|
204
|
-
{
|
|
205
|
-
auto data = val.as_data_descriptor();
|
|
206
|
-
if (data->writable)
|
|
207
|
-
{
|
|
208
|
-
data->value = new_val;
|
|
209
|
-
return new_val;
|
|
210
|
-
}
|
|
211
|
-
else
|
|
212
|
-
{
|
|
213
|
-
throw Exception::make_exception("Cannot assign to read only property '" + propName + "' of object '#<Object>'", "TypeError");
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
if (val.is_accessor_descriptor())
|
|
217
|
-
{
|
|
218
|
-
auto accessor = val.as_accessor_descriptor();
|
|
219
|
-
if (accessor->set.has_value())
|
|
220
|
-
{
|
|
221
|
-
const AnyValue args[] = {new_val};
|
|
222
|
-
accessor->set.value()(thisVal, std::span<const AnyValue>(args, 1));
|
|
223
|
-
return new_val;
|
|
224
|
-
}
|
|
225
|
-
else
|
|
226
|
-
{
|
|
227
|
-
throw Exception::make_exception("Cannot set property of #<Object> which has only a getter", "TypeError");
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
val = new_val;
|
|
231
|
-
return new_val;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
inline std::string AnyValue::to_std_string() const
|
|
235
|
-
{
|
|
236
|
-
switch (get_type())
|
|
237
|
-
{
|
|
238
|
-
case JsType::Undefined:
|
|
239
|
-
return "undefined";
|
|
240
|
-
case JsType::Null:
|
|
241
|
-
return "null";
|
|
242
|
-
case JsType::Boolean:
|
|
243
|
-
return as_boolean() ? "true" : "false";
|
|
244
|
-
case JsType::String:
|
|
245
|
-
return as_string()->to_std_string();
|
|
246
|
-
case JsType::Object:
|
|
247
|
-
return as_object()->to_std_string();
|
|
248
|
-
case JsType::Array:
|
|
249
|
-
return as_array()->to_std_string();
|
|
250
|
-
case JsType::Function:
|
|
251
|
-
return as_function()->to_std_string();
|
|
252
|
-
case JsType::Iterator:
|
|
253
|
-
return as_iterator()->to_std_string();
|
|
254
|
-
case JsType::AsyncIterator:
|
|
255
|
-
return as_async_iterator()->to_std_string();
|
|
256
|
-
case JsType::Promise:
|
|
257
|
-
return as_promise()->to_std_string();
|
|
258
|
-
case JsType::Symbol:
|
|
259
|
-
return as_symbol()->to_std_string();
|
|
260
|
-
case JsType::DataDescriptor:
|
|
261
|
-
return as_data_descriptor()->value.to_std_string();
|
|
262
|
-
case JsType::AccessorDescriptor:
|
|
263
|
-
{
|
|
264
|
-
if (as_accessor_descriptor()->get.has_value())
|
|
265
|
-
return as_accessor_descriptor()->get.value()(*this, {}).to_std_string();
|
|
266
|
-
else
|
|
267
|
-
return "undefined";
|
|
268
|
-
}
|
|
269
|
-
case JsType::Number:
|
|
270
|
-
{
|
|
271
|
-
double num = as_double();
|
|
272
|
-
if (std::isnan(num))
|
|
273
|
-
{
|
|
274
|
-
return "NaN";
|
|
275
|
-
}
|
|
276
|
-
if (std::abs(num) >= 1e21 || (std::abs(num) > 0 && std::abs(num) < 1e-6))
|
|
277
|
-
{
|
|
278
|
-
std::ostringstream oss;
|
|
279
|
-
oss << std::scientific << std::setprecision(4) << num;
|
|
280
|
-
return oss.str();
|
|
281
|
-
}
|
|
282
|
-
else
|
|
283
|
-
{
|
|
284
|
-
std::ostringstream oss;
|
|
285
|
-
oss << std::setprecision(6) << std::fixed << num;
|
|
286
|
-
std::string s = oss.str();
|
|
287
|
-
s.erase(s.find_last_not_of('0') + 1, std::string::npos);
|
|
288
|
-
if (!s.empty() && s.back() == '.')
|
|
289
|
-
{
|
|
290
|
-
s.pop_back();
|
|
291
|
-
}
|
|
292
|
-
return s;
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
case JsType::Uninitialized:
|
|
296
|
-
Exception::throw_uninitialized_reference("#<Object>");
|
|
297
|
-
default:
|
|
298
|
-
return "";
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
inline std::string AnyValue::to_property_key() const
|
|
303
|
-
{
|
|
304
|
-
if (is_symbol())
|
|
305
|
-
{
|
|
306
|
-
return as_symbol()->key;
|
|
307
|
-
}
|
|
308
|
-
return to_std_string();
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
inline void AnyValue::set_prototype(AnyValue proto)
|
|
312
|
-
{
|
|
313
|
-
if (is_object())
|
|
314
|
-
{
|
|
315
|
-
as_object()->proto = proto;
|
|
316
|
-
}
|
|
317
|
-
else if (is_array())
|
|
318
|
-
{
|
|
319
|
-
as_array()->proto = proto;
|
|
320
|
-
}
|
|
321
|
-
else if (is_function())
|
|
322
|
-
{
|
|
323
|
-
as_function()->proto = proto;
|
|
324
|
-
}
|
|
325
|
-
else if (is_uninitialized())
|
|
326
|
-
{
|
|
327
|
-
Exception::throw_uninitialized_reference("#<Object>");
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
// AnyValue::call implementation
|
|
332
|
-
inline AnyValue AnyValue::call(AnyValue thisVal, std::span<const AnyValue> args, const std::optional<std::string> &expr) const
|
|
333
|
-
{
|
|
334
|
-
if (!is_function())
|
|
335
|
-
throw Exception::make_exception(expr.value_or(to_std_string()) + " is not a function", "TypeError");
|
|
336
|
-
return as_function()->call(thisVal, args);
|
|
337
|
-
}
|
|
338
|
-
inline AnyValue AnyValue::optional_call(AnyValue thisVal, std::span<const AnyValue> args, const std::optional<std::string> &expr) const
|
|
339
|
-
{
|
|
340
|
-
if (is_null() || is_undefined())
|
|
341
|
-
return Constants::UNDEFINED;
|
|
342
|
-
return as_function()->call(thisVal, args);
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// AnyValue::construct implementation
|
|
346
|
-
inline AnyValue AnyValue::construct(std::span<const AnyValue> args, const std::optional<std::string> &name) const
|
|
347
|
-
{
|
|
348
|
-
if (!is_function() || !as_function()->is_constructor)
|
|
349
|
-
{
|
|
350
|
-
throw Exception::make_exception(name.value_or(to_std_string()) + " is not a constructor", "TypeError");
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
// 1. Get prototype
|
|
354
|
-
AnyValue proto = get_own_property("prototype");
|
|
355
|
-
if (!proto.is_object())
|
|
356
|
-
{
|
|
357
|
-
proto = AnyValue::make_object({});
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
// 2. Create instance
|
|
361
|
-
AnyValue instance = AnyValue::make_object_with_proto({}, proto);
|
|
362
|
-
|
|
363
|
-
// 3. Call function
|
|
364
|
-
AnyValue result = call(instance, args);
|
|
365
|
-
|
|
366
|
-
// 4. Return result if object, else instance
|
|
367
|
-
if (result.is_object() || result.is_function() || result.is_array() || result.is_promise())
|
|
368
|
-
{
|
|
369
|
-
return result;
|
|
370
|
-
}
|
|
371
|
-
return instance;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
}
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "types.hpp"
|
|
4
|
+
#include "any_value.hpp"
|
|
5
|
+
#include "values/string.hpp"
|
|
6
|
+
#include "values/object.hpp"
|
|
7
|
+
#include "values/array.hpp"
|
|
8
|
+
#include "values/function.hpp"
|
|
9
|
+
#include "values/iterator.hpp"
|
|
10
|
+
#include "values/async_iterator.hpp"
|
|
11
|
+
#include "values/promise.hpp"
|
|
12
|
+
#include "values/symbol.hpp"
|
|
13
|
+
#include "values/descriptors.hpp"
|
|
14
|
+
#include "exception.hpp"
|
|
15
|
+
|
|
16
|
+
namespace jspp
|
|
17
|
+
{
|
|
18
|
+
// --- AnyValue GETTERS ---
|
|
19
|
+
inline JsString *AnyValue::as_string() const noexcept { return static_cast<JsString *>(get_ptr()); }
|
|
20
|
+
inline JsObject *AnyValue::as_object() const noexcept { return static_cast<JsObject *>(get_ptr()); }
|
|
21
|
+
inline JsArray *AnyValue::as_array() const noexcept { return static_cast<JsArray *>(get_ptr()); }
|
|
22
|
+
inline JsFunction *AnyValue::as_function() const noexcept { return static_cast<JsFunction *>(get_ptr()); }
|
|
23
|
+
inline JsSymbol *AnyValue::as_symbol() const noexcept { return static_cast<JsSymbol *>(get_ptr()); }
|
|
24
|
+
inline JsPromise *AnyValue::as_promise() const noexcept { return static_cast<JsPromise *>(get_ptr()); }
|
|
25
|
+
inline JsIterator<AnyValue> *AnyValue::as_iterator() const noexcept { return static_cast<JsIterator<AnyValue> *>(get_ptr()); }
|
|
26
|
+
inline JsAsyncIterator<AnyValue> *AnyValue::as_async_iterator() const noexcept { return static_cast<JsAsyncIterator<AnyValue> *>(get_ptr()); }
|
|
27
|
+
inline DataDescriptor *AnyValue::as_data_descriptor() const noexcept { return static_cast<DataDescriptor *>(get_ptr()); }
|
|
28
|
+
inline AccessorDescriptor *AnyValue::as_accessor_descriptor() const noexcept { return static_cast<AccessorDescriptor *>(get_ptr()); }
|
|
29
|
+
|
|
30
|
+
inline bool AnyValue::is_generator() const noexcept { return is_function() && as_function()->is_generator; }
|
|
31
|
+
|
|
32
|
+
// --- AnyValue FACTORIES ---
|
|
33
|
+
inline AnyValue AnyValue::make_string(const std::string &raw_s) noexcept
|
|
34
|
+
{
|
|
35
|
+
return from_ptr(new JsString(raw_s));
|
|
36
|
+
}
|
|
37
|
+
inline AnyValue AnyValue::make_object(std::initializer_list<std::pair<std::string, AnyValue>> props) noexcept
|
|
38
|
+
{
|
|
39
|
+
return from_ptr(new JsObject(props, make_null()));
|
|
40
|
+
}
|
|
41
|
+
inline AnyValue AnyValue::make_object(const std::map<std::string, AnyValue> &props) noexcept
|
|
42
|
+
{
|
|
43
|
+
return from_ptr(new JsObject(props, make_null()));
|
|
44
|
+
}
|
|
45
|
+
inline AnyValue AnyValue::make_object_with_proto(std::initializer_list<std::pair<std::string, AnyValue>> props, AnyValue proto) noexcept
|
|
46
|
+
{
|
|
47
|
+
return from_ptr(new JsObject(props, proto));
|
|
48
|
+
}
|
|
49
|
+
inline AnyValue AnyValue::make_object_with_proto(const std::map<std::string, AnyValue> &props, AnyValue proto) noexcept
|
|
50
|
+
{
|
|
51
|
+
return from_ptr(new JsObject(props, proto));
|
|
52
|
+
}
|
|
53
|
+
inline AnyValue AnyValue::make_array(std::span<const AnyValue> dense) noexcept
|
|
54
|
+
{
|
|
55
|
+
std::vector<AnyValue> vec;
|
|
56
|
+
vec.reserve(dense.size());
|
|
57
|
+
for (const auto &item : dense)
|
|
58
|
+
vec.push_back(item);
|
|
59
|
+
return from_ptr(new JsArray(std::move(vec)));
|
|
60
|
+
}
|
|
61
|
+
inline AnyValue AnyValue::make_array(const std::vector<AnyValue> &dense) noexcept
|
|
62
|
+
{
|
|
63
|
+
return from_ptr(new JsArray(dense));
|
|
64
|
+
}
|
|
65
|
+
inline AnyValue AnyValue::make_array(std::vector<AnyValue> &&dense) noexcept
|
|
66
|
+
{
|
|
67
|
+
return from_ptr(new JsArray(std::move(dense)));
|
|
68
|
+
}
|
|
69
|
+
inline AnyValue AnyValue::make_array_with_proto(std::span<const AnyValue> dense, AnyValue proto) noexcept
|
|
70
|
+
{
|
|
71
|
+
auto arr = new JsArray();
|
|
72
|
+
arr->dense.reserve(dense.size());
|
|
73
|
+
for (const auto &item : dense)
|
|
74
|
+
arr->dense.push_back(item);
|
|
75
|
+
arr->length = dense.size();
|
|
76
|
+
arr->proto = proto;
|
|
77
|
+
return from_ptr(arr);
|
|
78
|
+
}
|
|
79
|
+
inline AnyValue AnyValue::make_array_with_proto(const std::vector<AnyValue> &dense, AnyValue proto) noexcept
|
|
80
|
+
{
|
|
81
|
+
auto arr = new JsArray(dense);
|
|
82
|
+
arr->proto = proto;
|
|
83
|
+
return from_ptr(arr);
|
|
84
|
+
}
|
|
85
|
+
inline AnyValue AnyValue::make_array_with_proto(std::vector<AnyValue> &&dense, AnyValue proto) noexcept
|
|
86
|
+
{
|
|
87
|
+
auto arr = new JsArray(std::move(dense));
|
|
88
|
+
arr->proto = proto;
|
|
89
|
+
return from_ptr(arr);
|
|
90
|
+
}
|
|
91
|
+
inline AnyValue AnyValue::make_function(const JsFunctionCallable &call, const std::optional<std::string> &name, bool is_constructor) noexcept
|
|
92
|
+
{
|
|
93
|
+
auto v = from_ptr(new JsFunction(call, name, {}, false, is_constructor));
|
|
94
|
+
auto proto = make_object({});
|
|
95
|
+
proto.define_data_property("constructor", AnyValue::make_data_descriptor(v, true, false, false));
|
|
96
|
+
v.define_data_property("prototype", AnyValue::make_data_descriptor(proto, false, false, false));
|
|
97
|
+
return v;
|
|
98
|
+
}
|
|
99
|
+
inline AnyValue AnyValue::make_class(const JsFunctionCallable &call, const std::optional<std::string> &name) noexcept
|
|
100
|
+
{
|
|
101
|
+
auto v = from_ptr(new JsFunction(call, name, {}, true));
|
|
102
|
+
auto proto = make_object({});
|
|
103
|
+
proto.define_data_property("constructor", AnyValue::make_data_descriptor(v, true, false, false));
|
|
104
|
+
v.define_data_property("prototype", AnyValue::make_data_descriptor(proto, false, false, false));
|
|
105
|
+
return v;
|
|
106
|
+
}
|
|
107
|
+
inline AnyValue AnyValue::make_generator(const JsFunctionCallable &call, const std::optional<std::string> &name) noexcept
|
|
108
|
+
{
|
|
109
|
+
auto v = from_ptr(new JsFunction(call, true, name));
|
|
110
|
+
auto proto = make_object({});
|
|
111
|
+
proto.define_data_property("constructor", AnyValue::make_data_descriptor(v, true, false, false));
|
|
112
|
+
v.define_data_property("prototype", AnyValue::make_data_descriptor(proto, false, false, false));
|
|
113
|
+
return v;
|
|
114
|
+
}
|
|
115
|
+
inline AnyValue AnyValue::make_async_function(const JsFunctionCallable &call, const std::optional<std::string> &name) noexcept
|
|
116
|
+
{
|
|
117
|
+
auto v = from_ptr(new JsFunction(call, false, true, name));
|
|
118
|
+
auto proto = make_object({});
|
|
119
|
+
proto.define_data_property("constructor", AnyValue::make_data_descriptor(v, true, false, false));
|
|
120
|
+
v.define_data_property("prototype", AnyValue::make_data_descriptor(proto, false, false, false));
|
|
121
|
+
return v;
|
|
122
|
+
}
|
|
123
|
+
inline AnyValue AnyValue::make_async_generator(const JsFunctionCallable &call, const std::optional<std::string> &name) noexcept
|
|
124
|
+
{
|
|
125
|
+
auto v = from_ptr(new JsFunction(call, true, true, name));
|
|
126
|
+
auto proto = make_object({});
|
|
127
|
+
proto.define_data_property("constructor", AnyValue::make_data_descriptor(v, true, false, false));
|
|
128
|
+
v.define_data_property("prototype", AnyValue::make_data_descriptor(proto, false, false, false));
|
|
129
|
+
return v;
|
|
130
|
+
}
|
|
131
|
+
inline AnyValue AnyValue::make_symbol(const std::string &description) noexcept
|
|
132
|
+
{
|
|
133
|
+
return from_ptr(new JsSymbol(description));
|
|
134
|
+
}
|
|
135
|
+
inline AnyValue AnyValue::make_promise(const JsPromise &promise) noexcept
|
|
136
|
+
{
|
|
137
|
+
auto p = new JsPromise();
|
|
138
|
+
*p = promise;
|
|
139
|
+
return from_ptr(p);
|
|
140
|
+
}
|
|
141
|
+
inline AnyValue AnyValue::make_data_descriptor(AnyValue value, bool writable, bool enumerable, bool configurable) noexcept
|
|
142
|
+
{
|
|
143
|
+
return from_ptr(new DataDescriptor(value, writable, enumerable, configurable));
|
|
144
|
+
}
|
|
145
|
+
inline AnyValue AnyValue::make_accessor_descriptor(const std::optional<std::function<AnyValue(AnyValue, std::span<const AnyValue>)>> &get,
|
|
146
|
+
const std::optional<std::function<AnyValue(AnyValue, std::span<const AnyValue>)>> &set,
|
|
147
|
+
bool enumerable,
|
|
148
|
+
bool configurable) noexcept
|
|
149
|
+
{
|
|
150
|
+
return from_ptr(new AccessorDescriptor(get, set, enumerable, configurable));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
inline AnyValue AnyValue::from_symbol(JsSymbol *sym) noexcept
|
|
154
|
+
{
|
|
155
|
+
return from_ptr(sym);
|
|
156
|
+
}
|
|
157
|
+
inline AnyValue AnyValue::from_string(JsString *str) noexcept
|
|
158
|
+
{
|
|
159
|
+
return from_ptr(str);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
inline AnyValue AnyValue::from_promise(JsPromise &&promise) noexcept
|
|
163
|
+
{
|
|
164
|
+
auto it = new JsPromise(std::move(promise));
|
|
165
|
+
return from_ptr(it);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
inline AnyValue AnyValue::from_iterator(JsIterator<AnyValue> &&iterator) noexcept
|
|
169
|
+
{
|
|
170
|
+
auto it = new JsIterator<AnyValue>(std::move(iterator));
|
|
171
|
+
return from_ptr(it);
|
|
172
|
+
}
|
|
173
|
+
inline AnyValue AnyValue::from_iterator_ref(JsIterator<AnyValue> *iterator) noexcept
|
|
174
|
+
{
|
|
175
|
+
return from_ptr(iterator);
|
|
176
|
+
}
|
|
177
|
+
inline AnyValue AnyValue::from_async_iterator(JsAsyncIterator<AnyValue> &&iterator) noexcept
|
|
178
|
+
{
|
|
179
|
+
auto it = new JsAsyncIterator<AnyValue>(std::move(iterator));
|
|
180
|
+
return from_ptr(it);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
inline AnyValue AnyValue::resolve_property_for_read(const AnyValue &val, AnyValue thisVal, const std::string &propName) noexcept
|
|
184
|
+
{
|
|
185
|
+
if (val.is_data_descriptor())
|
|
186
|
+
{
|
|
187
|
+
return val.as_data_descriptor()->value;
|
|
188
|
+
}
|
|
189
|
+
if (val.is_accessor_descriptor())
|
|
190
|
+
{
|
|
191
|
+
auto accessor = val.as_accessor_descriptor();
|
|
192
|
+
if (accessor->get.has_value())
|
|
193
|
+
return accessor->get.value()(thisVal, std::span<const AnyValue>{});
|
|
194
|
+
else
|
|
195
|
+
{
|
|
196
|
+
return Constants::UNDEFINED;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return val;
|
|
200
|
+
}
|
|
201
|
+
inline AnyValue AnyValue::resolve_property_for_write(AnyValue &val, AnyValue thisVal, const AnyValue &new_val, const std::string &propName)
|
|
202
|
+
{
|
|
203
|
+
if (val.is_data_descriptor())
|
|
204
|
+
{
|
|
205
|
+
auto data = val.as_data_descriptor();
|
|
206
|
+
if (data->writable)
|
|
207
|
+
{
|
|
208
|
+
data->value = new_val;
|
|
209
|
+
return new_val;
|
|
210
|
+
}
|
|
211
|
+
else
|
|
212
|
+
{
|
|
213
|
+
throw Exception::make_exception("Cannot assign to read only property '" + propName + "' of object '#<Object>'", "TypeError");
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (val.is_accessor_descriptor())
|
|
217
|
+
{
|
|
218
|
+
auto accessor = val.as_accessor_descriptor();
|
|
219
|
+
if (accessor->set.has_value())
|
|
220
|
+
{
|
|
221
|
+
const AnyValue args[] = {new_val};
|
|
222
|
+
accessor->set.value()(thisVal, std::span<const AnyValue>(args, 1));
|
|
223
|
+
return new_val;
|
|
224
|
+
}
|
|
225
|
+
else
|
|
226
|
+
{
|
|
227
|
+
throw Exception::make_exception("Cannot set property of #<Object> which has only a getter", "TypeError");
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
val = new_val;
|
|
231
|
+
return new_val;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
inline std::string AnyValue::to_std_string() const
|
|
235
|
+
{
|
|
236
|
+
switch (get_type())
|
|
237
|
+
{
|
|
238
|
+
case JsType::Undefined:
|
|
239
|
+
return "undefined";
|
|
240
|
+
case JsType::Null:
|
|
241
|
+
return "null";
|
|
242
|
+
case JsType::Boolean:
|
|
243
|
+
return as_boolean() ? "true" : "false";
|
|
244
|
+
case JsType::String:
|
|
245
|
+
return as_string()->to_std_string();
|
|
246
|
+
case JsType::Object:
|
|
247
|
+
return as_object()->to_std_string();
|
|
248
|
+
case JsType::Array:
|
|
249
|
+
return as_array()->to_std_string();
|
|
250
|
+
case JsType::Function:
|
|
251
|
+
return as_function()->to_std_string();
|
|
252
|
+
case JsType::Iterator:
|
|
253
|
+
return as_iterator()->to_std_string();
|
|
254
|
+
case JsType::AsyncIterator:
|
|
255
|
+
return as_async_iterator()->to_std_string();
|
|
256
|
+
case JsType::Promise:
|
|
257
|
+
return as_promise()->to_std_string();
|
|
258
|
+
case JsType::Symbol:
|
|
259
|
+
return as_symbol()->to_std_string();
|
|
260
|
+
case JsType::DataDescriptor:
|
|
261
|
+
return as_data_descriptor()->value.to_std_string();
|
|
262
|
+
case JsType::AccessorDescriptor:
|
|
263
|
+
{
|
|
264
|
+
if (as_accessor_descriptor()->get.has_value())
|
|
265
|
+
return as_accessor_descriptor()->get.value()(*this, {}).to_std_string();
|
|
266
|
+
else
|
|
267
|
+
return "undefined";
|
|
268
|
+
}
|
|
269
|
+
case JsType::Number:
|
|
270
|
+
{
|
|
271
|
+
double num = as_double();
|
|
272
|
+
if (std::isnan(num))
|
|
273
|
+
{
|
|
274
|
+
return "NaN";
|
|
275
|
+
}
|
|
276
|
+
if (std::abs(num) >= 1e21 || (std::abs(num) > 0 && std::abs(num) < 1e-6))
|
|
277
|
+
{
|
|
278
|
+
std::ostringstream oss;
|
|
279
|
+
oss << std::scientific << std::setprecision(4) << num;
|
|
280
|
+
return oss.str();
|
|
281
|
+
}
|
|
282
|
+
else
|
|
283
|
+
{
|
|
284
|
+
std::ostringstream oss;
|
|
285
|
+
oss << std::setprecision(6) << std::fixed << num;
|
|
286
|
+
std::string s = oss.str();
|
|
287
|
+
s.erase(s.find_last_not_of('0') + 1, std::string::npos);
|
|
288
|
+
if (!s.empty() && s.back() == '.')
|
|
289
|
+
{
|
|
290
|
+
s.pop_back();
|
|
291
|
+
}
|
|
292
|
+
return s;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
case JsType::Uninitialized:
|
|
296
|
+
Exception::throw_uninitialized_reference("#<Object>");
|
|
297
|
+
default:
|
|
298
|
+
return "";
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
inline std::string AnyValue::to_property_key() const
|
|
303
|
+
{
|
|
304
|
+
if (is_symbol())
|
|
305
|
+
{
|
|
306
|
+
return as_symbol()->key;
|
|
307
|
+
}
|
|
308
|
+
return to_std_string();
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
inline void AnyValue::set_prototype(AnyValue proto)
|
|
312
|
+
{
|
|
313
|
+
if (is_object())
|
|
314
|
+
{
|
|
315
|
+
as_object()->proto = proto;
|
|
316
|
+
}
|
|
317
|
+
else if (is_array())
|
|
318
|
+
{
|
|
319
|
+
as_array()->proto = proto;
|
|
320
|
+
}
|
|
321
|
+
else if (is_function())
|
|
322
|
+
{
|
|
323
|
+
as_function()->proto = proto;
|
|
324
|
+
}
|
|
325
|
+
else if (is_uninitialized())
|
|
326
|
+
{
|
|
327
|
+
Exception::throw_uninitialized_reference("#<Object>");
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// AnyValue::call implementation
|
|
332
|
+
inline AnyValue AnyValue::call(AnyValue thisVal, std::span<const AnyValue> args, const std::optional<std::string> &expr) const
|
|
333
|
+
{
|
|
334
|
+
if (!is_function())
|
|
335
|
+
throw Exception::make_exception(expr.value_or(to_std_string()) + " is not a function", "TypeError");
|
|
336
|
+
return as_function()->call(thisVal, args);
|
|
337
|
+
}
|
|
338
|
+
inline AnyValue AnyValue::optional_call(AnyValue thisVal, std::span<const AnyValue> args, const std::optional<std::string> &expr) const
|
|
339
|
+
{
|
|
340
|
+
if (is_null() || is_undefined())
|
|
341
|
+
return Constants::UNDEFINED;
|
|
342
|
+
return as_function()->call(thisVal, args);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// AnyValue::construct implementation
|
|
346
|
+
inline AnyValue AnyValue::construct(std::span<const AnyValue> args, const std::optional<std::string> &name) const
|
|
347
|
+
{
|
|
348
|
+
if (!is_function() || !as_function()->is_constructor)
|
|
349
|
+
{
|
|
350
|
+
throw Exception::make_exception(name.value_or(to_std_string()) + " is not a constructor", "TypeError");
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// 1. Get prototype
|
|
354
|
+
AnyValue proto = get_own_property("prototype");
|
|
355
|
+
if (!proto.is_object())
|
|
356
|
+
{
|
|
357
|
+
proto = AnyValue::make_object({});
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// 2. Create instance
|
|
361
|
+
AnyValue instance = AnyValue::make_object_with_proto({}, proto);
|
|
362
|
+
|
|
363
|
+
// 3. Call function
|
|
364
|
+
AnyValue result = call(instance, args);
|
|
365
|
+
|
|
366
|
+
// 4. Return result if object, else instance
|
|
367
|
+
if (result.is_object() || result.is_function() || result.is_array() || result.is_promise())
|
|
368
|
+
{
|
|
369
|
+
return result;
|
|
370
|
+
}
|
|
371
|
+
return instance;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
}
|