@ugo-studio/jspp 0.2.8 → 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/analysis/typeAnalyzer.js +42 -27
- package/dist/core/codegen/class-handlers.js +6 -6
- package/dist/core/codegen/control-flow-handlers.js +4 -4
- package/dist/core/codegen/declaration-handlers.js +21 -3
- package/dist/core/codegen/destructuring-handlers.js +187 -0
- package/dist/core/codegen/expression-handlers.js +7 -0
- package/dist/core/codegen/function-handlers.js +58 -36
- package/dist/core/codegen/helpers.js +288 -52
- package/dist/core/codegen/index.js +7 -4
- package/dist/core/codegen/statement-handlers.js +43 -23
- package/package.json +1 -1
- package/scripts/precompile-headers.ts +13 -5
- package/src/prelude/any_value.hpp +362 -361
- 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 -365
- 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/performance.hpp +1 -1
- 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 -393
- package/src/prelude/utils/operators.hpp +336 -329
- package/src/prelude/values/array.hpp +0 -1
- package/src/prelude/values/async_iterator.hpp +83 -81
- 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 -271
- package/src/prelude/values/helpers/function.hpp +108 -108
- package/src/prelude/values/helpers/iterator.hpp +144 -107
- package/src/prelude/values/helpers/promise.hpp +253 -253
- package/src/prelude/values/helpers/string.hpp +37 -47
- package/src/prelude/values/iterator.hpp +32 -5
- package/src/prelude/values/promise.hpp +72 -72
- package/src/prelude/values/prototypes/array.hpp +54 -42
- package/src/prelude/values/prototypes/iterator.hpp +201 -74
- 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,361 +1,362 @@
|
|
|
1
|
-
#pragma once
|
|
2
|
-
|
|
3
|
-
#include <cassert>
|
|
4
|
-
#include <cstdint>
|
|
5
|
-
#include <cstring>
|
|
6
|
-
#include <limits>
|
|
7
|
-
#include <new>
|
|
8
|
-
#include <sstream>
|
|
9
|
-
#include <iomanip>
|
|
10
|
-
#include <type_traits>
|
|
11
|
-
#include <memory>
|
|
12
|
-
#include <utility>
|
|
13
|
-
#include <string>
|
|
14
|
-
#include <map>
|
|
15
|
-
#include <vector>
|
|
16
|
-
#include <functional>
|
|
17
|
-
#include <cmath>
|
|
18
|
-
#include <optional>
|
|
19
|
-
#include <coroutine>
|
|
20
|
-
|
|
21
|
-
#include "types.hpp"
|
|
22
|
-
#include "values/non_values.hpp"
|
|
23
|
-
|
|
24
|
-
namespace jspp
|
|
25
|
-
{
|
|
26
|
-
// NAN BOXING SCHEME (64-bit)
|
|
27
|
-
// -------------------------
|
|
28
|
-
// Any value that is NOT a NaN double or is a "quiet" NaN is stored as a double.
|
|
29
|
-
// We use the top bits of the NaN space for tagging.
|
|
30
|
-
//
|
|
31
|
-
// Any value >= 0xFFFC000000000000 is a special tag.
|
|
32
|
-
//
|
|
33
|
-
// Tagging (bits 48-63):
|
|
34
|
-
// 0xFFFC: Pointer to HeapObject
|
|
35
|
-
// 0xFFFD: Boolean (bit 0 is value)
|
|
36
|
-
// 0xFFFE: Special (Undefined, Null, Uninitialized)
|
|
37
|
-
|
|
38
|
-
class AnyValue
|
|
39
|
-
{
|
|
40
|
-
private:
|
|
41
|
-
uint64_t storage;
|
|
42
|
-
|
|
43
|
-
static constexpr uint64_t TAG_BASE = 0xFFFC000000000000ULL;
|
|
44
|
-
static constexpr uint64_t TAG_POINTER = 0xFFFC000000000000ULL;
|
|
45
|
-
static constexpr uint64_t TAG_BOOLEAN = 0xFFFD000000000000ULL;
|
|
46
|
-
static constexpr uint64_t TAG_SPECIAL = 0xFFFE000000000000ULL;
|
|
47
|
-
|
|
48
|
-
static constexpr uint64_t VAL_UNDEFINED = 0x1ULL;
|
|
49
|
-
static constexpr uint64_t VAL_NULL = 0x2ULL;
|
|
50
|
-
static constexpr uint64_t VAL_UNINITIALIZED = 0x3ULL;
|
|
51
|
-
|
|
52
|
-
static constexpr uint64_t TAG_MASK = 0xFFFF000000000000ULL;
|
|
53
|
-
static constexpr uint64_t PAYLOAD_MASK = 0x0000FFFFFFFFFFFFULL;
|
|
54
|
-
|
|
55
|
-
inline bool has_tag(uint64_t tag) const noexcept
|
|
56
|
-
{
|
|
57
|
-
return (storage & TAG_MASK) == tag;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
public:
|
|
61
|
-
inline HeapObject *get_ptr() const noexcept
|
|
62
|
-
{
|
|
63
|
-
return reinterpret_cast<HeapObject *>(storage & PAYLOAD_MASK);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// default ctor (Undefined)
|
|
67
|
-
AnyValue() noexcept : storage(TAG_SPECIAL | VAL_UNDEFINED) {}
|
|
68
|
-
|
|
69
|
-
explicit AnyValue(double d) noexcept
|
|
70
|
-
{
|
|
71
|
-
std::memcpy(&storage, &d, 8);
|
|
72
|
-
if (storage >= TAG_BASE) [[unlikely]]
|
|
73
|
-
{
|
|
74
|
-
storage = 0x7FF8000000000000ULL;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
explicit AnyValue(bool b) noexcept : storage(TAG_BOOLEAN | (b ? 1 : 0)) {}
|
|
79
|
-
|
|
80
|
-
AnyValue(const AnyValue &other) noexcept : storage(other.storage)
|
|
81
|
-
{
|
|
82
|
-
if (is_heap_object())
|
|
83
|
-
get_ptr()->ref();
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
AnyValue(AnyValue &&other) noexcept : storage(other.storage)
|
|
87
|
-
{
|
|
88
|
-
other.storage = TAG_SPECIAL | VAL_UNDEFINED;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
AnyValue &operator=(const AnyValue &other) noexcept
|
|
92
|
-
{
|
|
93
|
-
if (this != &other)
|
|
94
|
-
{
|
|
95
|
-
if (is_heap_object())
|
|
96
|
-
get_ptr()->deref();
|
|
97
|
-
storage = other.storage;
|
|
98
|
-
if (is_heap_object())
|
|
99
|
-
get_ptr()->ref();
|
|
100
|
-
}
|
|
101
|
-
return *this;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
AnyValue &operator=(AnyValue &&other) noexcept
|
|
105
|
-
{
|
|
106
|
-
if (this != &other)
|
|
107
|
-
{
|
|
108
|
-
if (is_heap_object())
|
|
109
|
-
get_ptr()->deref();
|
|
110
|
-
storage = other.storage;
|
|
111
|
-
other.storage = TAG_SPECIAL | VAL_UNDEFINED;
|
|
112
|
-
}
|
|
113
|
-
return *this;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
~AnyValue()
|
|
117
|
-
{
|
|
118
|
-
if (is_heap_object())
|
|
119
|
-
get_ptr()->deref();
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Assignments
|
|
123
|
-
AnyValue &operator=(double val) noexcept
|
|
124
|
-
{
|
|
125
|
-
if (is_heap_object())
|
|
126
|
-
get_ptr()->deref();
|
|
127
|
-
std::memcpy(&storage, &val, 8);
|
|
128
|
-
if (storage >= TAG_BASE) [[unlikely]]
|
|
129
|
-
{
|
|
130
|
-
storage = 0x7FF8000000000000ULL;
|
|
131
|
-
}
|
|
132
|
-
return *this;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
friend void swap(AnyValue &a, AnyValue &b) noexcept
|
|
136
|
-
{
|
|
137
|
-
std::swap(a.storage, b.storage);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// --- FRIENDS for Optimized Operators
|
|
141
|
-
friend AnyValue &operator+=(AnyValue &lhs, const AnyValue &rhs);
|
|
142
|
-
friend AnyValue &operator-=(AnyValue &lhs, const AnyValue &rhs);
|
|
143
|
-
friend AnyValue &operator*=(AnyValue &lhs, const AnyValue &rhs);
|
|
144
|
-
friend AnyValue &operator/=(AnyValue &lhs, const AnyValue &rhs);
|
|
145
|
-
friend AnyValue &operator%=(AnyValue &lhs, const AnyValue &rhs);
|
|
146
|
-
friend AnyValue &operator++(AnyValue &val);
|
|
147
|
-
friend AnyValue operator++(AnyValue &val, int);
|
|
148
|
-
friend AnyValue &operator--(AnyValue &val);
|
|
149
|
-
friend AnyValue operator--(AnyValue &val, int);
|
|
150
|
-
|
|
151
|
-
// factories -------------------------------------------------------
|
|
152
|
-
static AnyValue make_number(double d) noexcept
|
|
153
|
-
{
|
|
154
|
-
return AnyValue(d);
|
|
155
|
-
}
|
|
156
|
-
static AnyValue make_nan() noexcept
|
|
157
|
-
{
|
|
158
|
-
AnyValue v;
|
|
159
|
-
v.storage = 0x7FF8000000000000ULL;
|
|
160
|
-
return v;
|
|
161
|
-
}
|
|
162
|
-
static AnyValue make_uninitialized() noexcept
|
|
163
|
-
{
|
|
164
|
-
AnyValue v;
|
|
165
|
-
v.storage = TAG_SPECIAL | VAL_UNINITIALIZED;
|
|
166
|
-
return v;
|
|
167
|
-
}
|
|
168
|
-
static AnyValue make_undefined() noexcept
|
|
169
|
-
{
|
|
170
|
-
AnyValue v;
|
|
171
|
-
v.storage = TAG_SPECIAL | VAL_UNDEFINED;
|
|
172
|
-
return v;
|
|
173
|
-
}
|
|
174
|
-
static AnyValue make_null() noexcept
|
|
175
|
-
{
|
|
176
|
-
AnyValue v;
|
|
177
|
-
v.storage = TAG_SPECIAL | VAL_NULL;
|
|
178
|
-
return v;
|
|
179
|
-
}
|
|
180
|
-
static AnyValue make_boolean(bool b) noexcept
|
|
181
|
-
{
|
|
182
|
-
return AnyValue(b);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
static AnyValue make_string(const std::string &raw_s) noexcept;
|
|
186
|
-
static AnyValue make_object(std::initializer_list<std::pair<std::string, AnyValue>> props) noexcept;
|
|
187
|
-
static AnyValue make_object(const std::map<std::string, AnyValue> &props) noexcept;
|
|
188
|
-
static AnyValue make_object_with_proto(std::initializer_list<std::pair<std::string, AnyValue>> props, AnyValue proto) noexcept;
|
|
189
|
-
static AnyValue make_object_with_proto(const std::map<std::string, AnyValue> &props, AnyValue proto) noexcept;
|
|
190
|
-
static AnyValue make_array(std::span<const AnyValue> dense) noexcept;
|
|
191
|
-
static AnyValue make_array(const std::vector<AnyValue> &dense) noexcept;
|
|
192
|
-
static AnyValue make_array(std::vector<AnyValue> &&dense) noexcept;
|
|
193
|
-
static AnyValue make_array_with_proto(std::span<const AnyValue> dense, AnyValue proto) noexcept;
|
|
194
|
-
static AnyValue make_array_with_proto(const std::vector<AnyValue> &dense, AnyValue proto) noexcept;
|
|
195
|
-
static AnyValue make_array_with_proto(std::vector<AnyValue> &&dense, AnyValue proto) noexcept;
|
|
196
|
-
static AnyValue make_function(const JsFunctionCallable &call, const std::optional<std::string> &name = std::nullopt, bool is_constructor = true) noexcept;
|
|
197
|
-
static AnyValue make_class(const JsFunctionCallable &call, const std::optional<std::string> &name = std::nullopt) noexcept;
|
|
198
|
-
static AnyValue make_generator(const JsFunctionCallable &call, const std::optional<std::string> &name = std::nullopt) noexcept;
|
|
199
|
-
static AnyValue make_async_function(const JsFunctionCallable &call, const std::optional<std::string> &name = std::nullopt) noexcept;
|
|
200
|
-
static AnyValue make_async_generator(const JsFunctionCallable &call, const std::optional<std::string> &name = std::nullopt) noexcept;
|
|
201
|
-
static AnyValue make_symbol(const std::string &description = "") noexcept;
|
|
202
|
-
static AnyValue make_promise(const JsPromise &promise) noexcept;
|
|
203
|
-
static AnyValue make_data_descriptor(AnyValue value, bool writable, bool enumerable, bool configurable) noexcept;
|
|
204
|
-
static AnyValue make_accessor_descriptor(const std::optional<std::function<AnyValue(
|
|
205
|
-
const std::optional<std::function<AnyValue(
|
|
206
|
-
bool enumerable,
|
|
207
|
-
bool configurable) noexcept;
|
|
208
|
-
|
|
209
|
-
static AnyValue from_symbol(JsSymbol *sym) noexcept;
|
|
210
|
-
static AnyValue from_string(JsString *str) noexcept;
|
|
211
|
-
static AnyValue from_promise(JsPromise &&promise) noexcept;
|
|
212
|
-
static AnyValue from_iterator(JsIterator<AnyValue> &&iterator) noexcept;
|
|
213
|
-
static AnyValue from_iterator_ref(JsIterator<AnyValue> *iterator) noexcept;
|
|
214
|
-
static AnyValue from_async_iterator(JsAsyncIterator<AnyValue> &&iterator) noexcept;
|
|
215
|
-
|
|
216
|
-
// internal factory for wrapping raw heap object pointers
|
|
217
|
-
static AnyValue from_ptr(HeapObject *ptr) noexcept
|
|
218
|
-
{
|
|
219
|
-
AnyValue v;
|
|
220
|
-
v.storage = TAG_POINTER | reinterpret_cast<uint64_t>(ptr);
|
|
221
|
-
ptr->ref();
|
|
222
|
-
return v;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
static AnyValue resolve_property_for_read(const AnyValue &val,
|
|
226
|
-
static AnyValue resolve_property_for_write(AnyValue &val,
|
|
227
|
-
|
|
228
|
-
// TYPE CHECKERS AND ACCESSORS ---------------------------------------
|
|
229
|
-
inline JsType get_type() const noexcept
|
|
230
|
-
{
|
|
231
|
-
if (is_number())
|
|
232
|
-
return JsType::Number;
|
|
233
|
-
if (is_heap_object())
|
|
234
|
-
return get_ptr()->get_heap_type();
|
|
235
|
-
if (is_boolean())
|
|
236
|
-
return JsType::Boolean;
|
|
237
|
-
if (is_undefined())
|
|
238
|
-
return JsType::Undefined;
|
|
239
|
-
if (is_null())
|
|
240
|
-
return JsType::Null;
|
|
241
|
-
if (is_uninitialized())
|
|
242
|
-
return JsType::Uninitialized;
|
|
243
|
-
return JsType::Undefined;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
inline bool is_number() const noexcept { return storage < TAG_BASE; }
|
|
247
|
-
inline bool is_heap_object() const noexcept { return has_tag(TAG_POINTER); }
|
|
248
|
-
inline bool is_string() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::String; }
|
|
249
|
-
inline bool is_object() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::Object; }
|
|
250
|
-
inline bool is_array() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::Array; }
|
|
251
|
-
inline bool is_function() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::Function; }
|
|
252
|
-
inline bool is_iterator() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::Iterator; }
|
|
253
|
-
inline bool is_boolean() const noexcept { return has_tag(TAG_BOOLEAN); }
|
|
254
|
-
inline bool is_symbol() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::Symbol; }
|
|
255
|
-
inline bool is_promise() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::Promise; }
|
|
256
|
-
inline bool is_null() const noexcept { return storage == (TAG_SPECIAL | VAL_NULL); }
|
|
257
|
-
inline bool is_undefined() const noexcept { return storage == (TAG_SPECIAL | VAL_UNDEFINED); }
|
|
258
|
-
inline bool is_uninitialized() const noexcept { return storage == (TAG_SPECIAL | VAL_UNINITIALIZED); }
|
|
259
|
-
inline bool is_data_descriptor() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::DataDescriptor; }
|
|
260
|
-
inline bool is_accessor_descriptor() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::AccessorDescriptor; }
|
|
261
|
-
inline bool is_async_iterator() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::AsyncIterator; }
|
|
262
|
-
|
|
263
|
-
JsString *as_string() const noexcept;
|
|
264
|
-
JsObject *as_object() const noexcept;
|
|
265
|
-
JsArray *as_array() const noexcept;
|
|
266
|
-
JsFunction *as_function() const noexcept;
|
|
267
|
-
JsSymbol *as_symbol() const noexcept;
|
|
268
|
-
JsPromise *as_promise() const noexcept;
|
|
269
|
-
JsIterator<AnyValue> *as_iterator() const noexcept;
|
|
270
|
-
JsAsyncIterator<AnyValue> *as_async_iterator() const noexcept;
|
|
271
|
-
DataDescriptor *as_data_descriptor() const noexcept;
|
|
272
|
-
AccessorDescriptor *as_accessor_descriptor() const noexcept;
|
|
273
|
-
|
|
274
|
-
bool is_generator() const noexcept;
|
|
275
|
-
|
|
276
|
-
double as_double() const noexcept
|
|
277
|
-
{
|
|
278
|
-
double d;
|
|
279
|
-
std::memcpy(&d, &storage, 8);
|
|
280
|
-
return d;
|
|
281
|
-
}
|
|
282
|
-
bool as_boolean() const noexcept
|
|
283
|
-
{
|
|
284
|
-
return static_cast<bool>(storage & 1);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
auto operator co_await() const;
|
|
288
|
-
|
|
289
|
-
bool has_property(const std::string &key) const;
|
|
290
|
-
bool has_property(const char *key) const { return has_property(std::string(key)); }
|
|
291
|
-
|
|
292
|
-
AnyValue get_own_property(const std::string &key) const;
|
|
293
|
-
AnyValue get_own_property(const char *key) const { return get_own_property(std::string(key)); }
|
|
294
|
-
AnyValue get_own_property(uint32_t idx) const;
|
|
295
|
-
AnyValue get_own_property(int idx) const { return get_own_property(static_cast<uint32_t>(idx)); }
|
|
296
|
-
AnyValue get_own_property(const AnyValue &key) const;
|
|
297
|
-
|
|
298
|
-
AnyValue get_property_with_receiver(const std::string &key,
|
|
299
|
-
AnyValue get_property_with_receiver(const char *key,
|
|
300
|
-
|
|
301
|
-
AnyValue set_own_property(const std::string &key,
|
|
302
|
-
AnyValue set_own_property(const char *key,
|
|
303
|
-
AnyValue set_own_property(uint32_t idx,
|
|
304
|
-
AnyValue set_own_property(int idx,
|
|
305
|
-
AnyValue set_own_property(const AnyValue &key,
|
|
306
|
-
|
|
307
|
-
AnyValue call_own_property(const std::string &key, std::span<const AnyValue> args) const;
|
|
308
|
-
AnyValue call_own_property(const char *key, std::span<const AnyValue> args) const { return call_own_property(std::string(key), args); }
|
|
309
|
-
AnyValue call_own_property(uint32_t idx, std::span<const AnyValue> args) const;
|
|
310
|
-
AnyValue call_own_property(int idx, std::span<const AnyValue> args) const { return call_own_property(static_cast<uint32_t>(idx), args); }
|
|
311
|
-
AnyValue call_own_property(const AnyValue &key, std::span<const AnyValue> args) const;
|
|
312
|
-
|
|
313
|
-
void define_data_property(const std::string &key,
|
|
314
|
-
void define_data_property(const char *key,
|
|
315
|
-
void define_data_property(const AnyValue &key,
|
|
316
|
-
void define_data_property(const std::string &key,
|
|
317
|
-
void define_data_property(const char *key,
|
|
318
|
-
|
|
319
|
-
void define_getter(const std::string &key,
|
|
320
|
-
void define_getter(const char *key,
|
|
321
|
-
void define_getter(const AnyValue &key,
|
|
322
|
-
|
|
323
|
-
void define_setter(const std::string &key,
|
|
324
|
-
void define_setter(const char *key,
|
|
325
|
-
void define_setter(const AnyValue &key,
|
|
326
|
-
|
|
327
|
-
AnyValue call(
|
|
328
|
-
AnyValue optional_call(
|
|
329
|
-
AnyValue construct(std::span<const AnyValue> args, const std::optional<std::string> &name = std::nullopt) const;
|
|
330
|
-
void set_prototype(
|
|
331
|
-
std::string to_std_string() const;
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
inline
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
inline const AnyValue
|
|
354
|
-
inline const AnyValue
|
|
355
|
-
inline const AnyValue
|
|
356
|
-
inline const AnyValue
|
|
357
|
-
inline const AnyValue
|
|
358
|
-
inline const AnyValue
|
|
359
|
-
inline const AnyValue
|
|
360
|
-
|
|
361
|
-
}
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <cassert>
|
|
4
|
+
#include <cstdint>
|
|
5
|
+
#include <cstring>
|
|
6
|
+
#include <limits>
|
|
7
|
+
#include <new>
|
|
8
|
+
#include <sstream>
|
|
9
|
+
#include <iomanip>
|
|
10
|
+
#include <type_traits>
|
|
11
|
+
#include <memory>
|
|
12
|
+
#include <utility>
|
|
13
|
+
#include <string>
|
|
14
|
+
#include <map>
|
|
15
|
+
#include <vector>
|
|
16
|
+
#include <functional>
|
|
17
|
+
#include <cmath>
|
|
18
|
+
#include <optional>
|
|
19
|
+
#include <coroutine>
|
|
20
|
+
|
|
21
|
+
#include "types.hpp"
|
|
22
|
+
#include "values/non_values.hpp"
|
|
23
|
+
|
|
24
|
+
namespace jspp
|
|
25
|
+
{
|
|
26
|
+
// NAN BOXING SCHEME (64-bit)
|
|
27
|
+
// -------------------------
|
|
28
|
+
// Any value that is NOT a NaN double or is a "quiet" NaN is stored as a double.
|
|
29
|
+
// We use the top bits of the NaN space for tagging.
|
|
30
|
+
//
|
|
31
|
+
// Any value >= 0xFFFC000000000000 is a special tag.
|
|
32
|
+
//
|
|
33
|
+
// Tagging (bits 48-63):
|
|
34
|
+
// 0xFFFC: Pointer to HeapObject
|
|
35
|
+
// 0xFFFD: Boolean (bit 0 is value)
|
|
36
|
+
// 0xFFFE: Special (Undefined, Null, Uninitialized)
|
|
37
|
+
|
|
38
|
+
class AnyValue
|
|
39
|
+
{
|
|
40
|
+
private:
|
|
41
|
+
uint64_t storage;
|
|
42
|
+
|
|
43
|
+
static constexpr uint64_t TAG_BASE = 0xFFFC000000000000ULL;
|
|
44
|
+
static constexpr uint64_t TAG_POINTER = 0xFFFC000000000000ULL;
|
|
45
|
+
static constexpr uint64_t TAG_BOOLEAN = 0xFFFD000000000000ULL;
|
|
46
|
+
static constexpr uint64_t TAG_SPECIAL = 0xFFFE000000000000ULL;
|
|
47
|
+
|
|
48
|
+
static constexpr uint64_t VAL_UNDEFINED = 0x1ULL;
|
|
49
|
+
static constexpr uint64_t VAL_NULL = 0x2ULL;
|
|
50
|
+
static constexpr uint64_t VAL_UNINITIALIZED = 0x3ULL;
|
|
51
|
+
|
|
52
|
+
static constexpr uint64_t TAG_MASK = 0xFFFF000000000000ULL;
|
|
53
|
+
static constexpr uint64_t PAYLOAD_MASK = 0x0000FFFFFFFFFFFFULL;
|
|
54
|
+
|
|
55
|
+
inline bool has_tag(uint64_t tag) const noexcept
|
|
56
|
+
{
|
|
57
|
+
return (storage & TAG_MASK) == tag;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public:
|
|
61
|
+
inline HeapObject *get_ptr() const noexcept
|
|
62
|
+
{
|
|
63
|
+
return reinterpret_cast<HeapObject *>(storage & PAYLOAD_MASK);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// default ctor (Undefined)
|
|
67
|
+
AnyValue() noexcept : storage(TAG_SPECIAL | VAL_UNDEFINED) {}
|
|
68
|
+
|
|
69
|
+
explicit AnyValue(double d) noexcept
|
|
70
|
+
{
|
|
71
|
+
std::memcpy(&storage, &d, 8);
|
|
72
|
+
if (storage >= TAG_BASE) [[unlikely]]
|
|
73
|
+
{
|
|
74
|
+
storage = 0x7FF8000000000000ULL;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
explicit AnyValue(bool b) noexcept : storage(TAG_BOOLEAN | (b ? 1 : 0)) {}
|
|
79
|
+
|
|
80
|
+
AnyValue(const AnyValue &other) noexcept : storage(other.storage)
|
|
81
|
+
{
|
|
82
|
+
if (is_heap_object())
|
|
83
|
+
get_ptr()->ref();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
AnyValue(AnyValue &&other) noexcept : storage(other.storage)
|
|
87
|
+
{
|
|
88
|
+
other.storage = TAG_SPECIAL | VAL_UNDEFINED;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
AnyValue &operator=(const AnyValue &other) noexcept
|
|
92
|
+
{
|
|
93
|
+
if (this != &other)
|
|
94
|
+
{
|
|
95
|
+
if (is_heap_object())
|
|
96
|
+
get_ptr()->deref();
|
|
97
|
+
storage = other.storage;
|
|
98
|
+
if (is_heap_object())
|
|
99
|
+
get_ptr()->ref();
|
|
100
|
+
}
|
|
101
|
+
return *this;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
AnyValue &operator=(AnyValue &&other) noexcept
|
|
105
|
+
{
|
|
106
|
+
if (this != &other)
|
|
107
|
+
{
|
|
108
|
+
if (is_heap_object())
|
|
109
|
+
get_ptr()->deref();
|
|
110
|
+
storage = other.storage;
|
|
111
|
+
other.storage = TAG_SPECIAL | VAL_UNDEFINED;
|
|
112
|
+
}
|
|
113
|
+
return *this;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
~AnyValue()
|
|
117
|
+
{
|
|
118
|
+
if (is_heap_object())
|
|
119
|
+
get_ptr()->deref();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Assignments
|
|
123
|
+
AnyValue &operator=(double val) noexcept
|
|
124
|
+
{
|
|
125
|
+
if (is_heap_object())
|
|
126
|
+
get_ptr()->deref();
|
|
127
|
+
std::memcpy(&storage, &val, 8);
|
|
128
|
+
if (storage >= TAG_BASE) [[unlikely]]
|
|
129
|
+
{
|
|
130
|
+
storage = 0x7FF8000000000000ULL;
|
|
131
|
+
}
|
|
132
|
+
return *this;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
friend void swap(AnyValue &a, AnyValue &b) noexcept
|
|
136
|
+
{
|
|
137
|
+
std::swap(a.storage, b.storage);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// --- FRIENDS for Optimized Operators
|
|
141
|
+
friend AnyValue &operator+=(AnyValue &lhs, const AnyValue &rhs);
|
|
142
|
+
friend AnyValue &operator-=(AnyValue &lhs, const AnyValue &rhs);
|
|
143
|
+
friend AnyValue &operator*=(AnyValue &lhs, const AnyValue &rhs);
|
|
144
|
+
friend AnyValue &operator/=(AnyValue &lhs, const AnyValue &rhs);
|
|
145
|
+
friend AnyValue &operator%=(AnyValue &lhs, const AnyValue &rhs);
|
|
146
|
+
friend AnyValue &operator++(AnyValue &val);
|
|
147
|
+
friend AnyValue operator++(AnyValue &val, int);
|
|
148
|
+
friend AnyValue &operator--(AnyValue &val);
|
|
149
|
+
friend AnyValue operator--(AnyValue &val, int);
|
|
150
|
+
|
|
151
|
+
// factories -------------------------------------------------------
|
|
152
|
+
static AnyValue make_number(double d) noexcept
|
|
153
|
+
{
|
|
154
|
+
return AnyValue(d);
|
|
155
|
+
}
|
|
156
|
+
static AnyValue make_nan() noexcept
|
|
157
|
+
{
|
|
158
|
+
AnyValue v;
|
|
159
|
+
v.storage = 0x7FF8000000000000ULL;
|
|
160
|
+
return v;
|
|
161
|
+
}
|
|
162
|
+
static AnyValue make_uninitialized() noexcept
|
|
163
|
+
{
|
|
164
|
+
AnyValue v;
|
|
165
|
+
v.storage = TAG_SPECIAL | VAL_UNINITIALIZED;
|
|
166
|
+
return v;
|
|
167
|
+
}
|
|
168
|
+
static AnyValue make_undefined() noexcept
|
|
169
|
+
{
|
|
170
|
+
AnyValue v;
|
|
171
|
+
v.storage = TAG_SPECIAL | VAL_UNDEFINED;
|
|
172
|
+
return v;
|
|
173
|
+
}
|
|
174
|
+
static AnyValue make_null() noexcept
|
|
175
|
+
{
|
|
176
|
+
AnyValue v;
|
|
177
|
+
v.storage = TAG_SPECIAL | VAL_NULL;
|
|
178
|
+
return v;
|
|
179
|
+
}
|
|
180
|
+
static AnyValue make_boolean(bool b) noexcept
|
|
181
|
+
{
|
|
182
|
+
return AnyValue(b);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
static AnyValue make_string(const std::string &raw_s) noexcept;
|
|
186
|
+
static AnyValue make_object(std::initializer_list<std::pair<std::string, AnyValue>> props) noexcept;
|
|
187
|
+
static AnyValue make_object(const std::map<std::string, AnyValue> &props) noexcept;
|
|
188
|
+
static AnyValue make_object_with_proto(std::initializer_list<std::pair<std::string, AnyValue>> props, AnyValue proto) noexcept;
|
|
189
|
+
static AnyValue make_object_with_proto(const std::map<std::string, AnyValue> &props, AnyValue proto) noexcept;
|
|
190
|
+
static AnyValue make_array(std::span<const AnyValue> dense) noexcept;
|
|
191
|
+
static AnyValue make_array(const std::vector<AnyValue> &dense) noexcept;
|
|
192
|
+
static AnyValue make_array(std::vector<AnyValue> &&dense) noexcept;
|
|
193
|
+
static AnyValue make_array_with_proto(std::span<const AnyValue> dense, AnyValue proto) noexcept;
|
|
194
|
+
static AnyValue make_array_with_proto(const std::vector<AnyValue> &dense, AnyValue proto) noexcept;
|
|
195
|
+
static AnyValue make_array_with_proto(std::vector<AnyValue> &&dense, AnyValue proto) noexcept;
|
|
196
|
+
static AnyValue make_function(const JsFunctionCallable &call, const std::optional<std::string> &name = std::nullopt, bool is_constructor = true) noexcept;
|
|
197
|
+
static AnyValue make_class(const JsFunctionCallable &call, const std::optional<std::string> &name = std::nullopt) noexcept;
|
|
198
|
+
static AnyValue make_generator(const JsFunctionCallable &call, const std::optional<std::string> &name = std::nullopt) noexcept;
|
|
199
|
+
static AnyValue make_async_function(const JsFunctionCallable &call, const std::optional<std::string> &name = std::nullopt) noexcept;
|
|
200
|
+
static AnyValue make_async_generator(const JsFunctionCallable &call, const std::optional<std::string> &name = std::nullopt) noexcept;
|
|
201
|
+
static AnyValue make_symbol(const std::string &description = "") noexcept;
|
|
202
|
+
static AnyValue make_promise(const JsPromise &promise) noexcept;
|
|
203
|
+
static AnyValue make_data_descriptor(AnyValue value, bool writable, bool enumerable, bool configurable) noexcept;
|
|
204
|
+
static AnyValue make_accessor_descriptor(const std::optional<std::function<AnyValue(AnyValue, std::span<const AnyValue>)>> &get,
|
|
205
|
+
const std::optional<std::function<AnyValue(AnyValue, std::span<const AnyValue>)>> &set,
|
|
206
|
+
bool enumerable,
|
|
207
|
+
bool configurable) noexcept;
|
|
208
|
+
|
|
209
|
+
static AnyValue from_symbol(JsSymbol *sym) noexcept;
|
|
210
|
+
static AnyValue from_string(JsString *str) noexcept;
|
|
211
|
+
static AnyValue from_promise(JsPromise &&promise) noexcept;
|
|
212
|
+
static AnyValue from_iterator(JsIterator<AnyValue> &&iterator) noexcept;
|
|
213
|
+
static AnyValue from_iterator_ref(JsIterator<AnyValue> *iterator) noexcept;
|
|
214
|
+
static AnyValue from_async_iterator(JsAsyncIterator<AnyValue> &&iterator) noexcept;
|
|
215
|
+
|
|
216
|
+
// internal factory for wrapping raw heap object pointers
|
|
217
|
+
static AnyValue from_ptr(HeapObject *ptr) noexcept
|
|
218
|
+
{
|
|
219
|
+
AnyValue v;
|
|
220
|
+
v.storage = TAG_POINTER | reinterpret_cast<uint64_t>(ptr);
|
|
221
|
+
ptr->ref();
|
|
222
|
+
return v;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
static AnyValue resolve_property_for_read(const AnyValue &val, AnyValue thisVal, const std::string &propName) noexcept;
|
|
226
|
+
static AnyValue resolve_property_for_write(AnyValue &val, AnyValue thisVal, const AnyValue &new_val, const std::string &propName);
|
|
227
|
+
|
|
228
|
+
// TYPE CHECKERS AND ACCESSORS ---------------------------------------
|
|
229
|
+
inline JsType get_type() const noexcept
|
|
230
|
+
{
|
|
231
|
+
if (is_number())
|
|
232
|
+
return JsType::Number;
|
|
233
|
+
if (is_heap_object())
|
|
234
|
+
return get_ptr()->get_heap_type();
|
|
235
|
+
if (is_boolean())
|
|
236
|
+
return JsType::Boolean;
|
|
237
|
+
if (is_undefined())
|
|
238
|
+
return JsType::Undefined;
|
|
239
|
+
if (is_null())
|
|
240
|
+
return JsType::Null;
|
|
241
|
+
if (is_uninitialized())
|
|
242
|
+
return JsType::Uninitialized;
|
|
243
|
+
return JsType::Undefined;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
inline bool is_number() const noexcept { return storage < TAG_BASE; }
|
|
247
|
+
inline bool is_heap_object() const noexcept { return has_tag(TAG_POINTER); }
|
|
248
|
+
inline bool is_string() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::String; }
|
|
249
|
+
inline bool is_object() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::Object; }
|
|
250
|
+
inline bool is_array() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::Array; }
|
|
251
|
+
inline bool is_function() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::Function; }
|
|
252
|
+
inline bool is_iterator() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::Iterator; }
|
|
253
|
+
inline bool is_boolean() const noexcept { return has_tag(TAG_BOOLEAN); }
|
|
254
|
+
inline bool is_symbol() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::Symbol; }
|
|
255
|
+
inline bool is_promise() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::Promise; }
|
|
256
|
+
inline bool is_null() const noexcept { return storage == (TAG_SPECIAL | VAL_NULL); }
|
|
257
|
+
inline bool is_undefined() const noexcept { return storage == (TAG_SPECIAL | VAL_UNDEFINED); }
|
|
258
|
+
inline bool is_uninitialized() const noexcept { return storage == (TAG_SPECIAL | VAL_UNINITIALIZED); }
|
|
259
|
+
inline bool is_data_descriptor() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::DataDescriptor; }
|
|
260
|
+
inline bool is_accessor_descriptor() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::AccessorDescriptor; }
|
|
261
|
+
inline bool is_async_iterator() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::AsyncIterator; }
|
|
262
|
+
|
|
263
|
+
JsString *as_string() const noexcept;
|
|
264
|
+
JsObject *as_object() const noexcept;
|
|
265
|
+
JsArray *as_array() const noexcept;
|
|
266
|
+
JsFunction *as_function() const noexcept;
|
|
267
|
+
JsSymbol *as_symbol() const noexcept;
|
|
268
|
+
JsPromise *as_promise() const noexcept;
|
|
269
|
+
JsIterator<AnyValue> *as_iterator() const noexcept;
|
|
270
|
+
JsAsyncIterator<AnyValue> *as_async_iterator() const noexcept;
|
|
271
|
+
DataDescriptor *as_data_descriptor() const noexcept;
|
|
272
|
+
AccessorDescriptor *as_accessor_descriptor() const noexcept;
|
|
273
|
+
|
|
274
|
+
bool is_generator() const noexcept;
|
|
275
|
+
|
|
276
|
+
double as_double() const noexcept
|
|
277
|
+
{
|
|
278
|
+
double d;
|
|
279
|
+
std::memcpy(&d, &storage, 8);
|
|
280
|
+
return d;
|
|
281
|
+
}
|
|
282
|
+
bool as_boolean() const noexcept
|
|
283
|
+
{
|
|
284
|
+
return static_cast<bool>(storage & 1);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
auto operator co_await() const;
|
|
288
|
+
|
|
289
|
+
bool has_property(const std::string &key) const;
|
|
290
|
+
bool has_property(const char *key) const { return has_property(std::string(key)); }
|
|
291
|
+
|
|
292
|
+
AnyValue get_own_property(const std::string &key) const;
|
|
293
|
+
AnyValue get_own_property(const char *key) const { return get_own_property(std::string(key)); }
|
|
294
|
+
AnyValue get_own_property(uint32_t idx) const;
|
|
295
|
+
AnyValue get_own_property(int idx) const { return get_own_property(static_cast<uint32_t>(idx)); }
|
|
296
|
+
AnyValue get_own_property(const AnyValue &key) const;
|
|
297
|
+
|
|
298
|
+
AnyValue get_property_with_receiver(const std::string &key, AnyValue receiver) const;
|
|
299
|
+
AnyValue get_property_with_receiver(const char *key, AnyValue receiver) const { return get_property_with_receiver(std::string(key), receiver); }
|
|
300
|
+
|
|
301
|
+
AnyValue set_own_property(const std::string &key, AnyValue value) const;
|
|
302
|
+
AnyValue set_own_property(const char *key, AnyValue value) const { return set_own_property(std::string(key), value); }
|
|
303
|
+
AnyValue set_own_property(uint32_t idx, AnyValue value) const;
|
|
304
|
+
AnyValue set_own_property(int idx, AnyValue value) const { return set_own_property(static_cast<uint32_t>(idx), value); }
|
|
305
|
+
AnyValue set_own_property(const AnyValue &key, AnyValue value) const;
|
|
306
|
+
|
|
307
|
+
AnyValue call_own_property(const std::string &key, std::span<const AnyValue> args) const;
|
|
308
|
+
AnyValue call_own_property(const char *key, std::span<const AnyValue> args) const { return call_own_property(std::string(key), args); }
|
|
309
|
+
AnyValue call_own_property(uint32_t idx, std::span<const AnyValue> args) const;
|
|
310
|
+
AnyValue call_own_property(int idx, std::span<const AnyValue> args) const { return call_own_property(static_cast<uint32_t>(idx), args); }
|
|
311
|
+
AnyValue call_own_property(const AnyValue &key, std::span<const AnyValue> args) const;
|
|
312
|
+
|
|
313
|
+
void define_data_property(const std::string &key, AnyValue value);
|
|
314
|
+
void define_data_property(const char *key, AnyValue value) { define_data_property(std::string(key), value); }
|
|
315
|
+
void define_data_property(const AnyValue &key, AnyValue value);
|
|
316
|
+
void define_data_property(const std::string &key, AnyValue value, bool writable, bool enumerable, bool configurable);
|
|
317
|
+
void define_data_property(const char *key, AnyValue value, bool writable, bool enumerable, bool configurable) { define_data_property(std::string(key), value, writable, enumerable, configurable); }
|
|
318
|
+
|
|
319
|
+
void define_getter(const std::string &key, AnyValue getter);
|
|
320
|
+
void define_getter(const char *key, AnyValue getter) { define_getter(std::string(key), getter); }
|
|
321
|
+
void define_getter(const AnyValue &key, AnyValue getter);
|
|
322
|
+
|
|
323
|
+
void define_setter(const std::string &key, AnyValue setter);
|
|
324
|
+
void define_setter(const char *key, AnyValue setter) { define_setter(std::string(key), setter); }
|
|
325
|
+
void define_setter(const AnyValue &key, AnyValue setter);
|
|
326
|
+
|
|
327
|
+
AnyValue call(AnyValue thisVal, std::span<const AnyValue> args, const std::optional<std::string> &expr = std::nullopt) const;
|
|
328
|
+
AnyValue optional_call(AnyValue thisVal, std::span<const AnyValue> args, const std::optional<std::string> &expr = std::nullopt) const;
|
|
329
|
+
AnyValue construct(std::span<const AnyValue> args, const std::optional<std::string> &name = std::nullopt) const;
|
|
330
|
+
void set_prototype(AnyValue proto);
|
|
331
|
+
std::string to_std_string() const;
|
|
332
|
+
std::string to_property_key() const;
|
|
333
|
+
|
|
334
|
+
inline uint64_t get_storage() const noexcept { return storage; }
|
|
335
|
+
inline void *get_raw_ptr() const noexcept { return reinterpret_cast<void *>(storage & PAYLOAD_MASK); }
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
struct AnyValueAwaiter
|
|
339
|
+
{
|
|
340
|
+
AnyValue value;
|
|
341
|
+
bool await_ready();
|
|
342
|
+
void await_suspend(std::coroutine_handle<> h);
|
|
343
|
+
AnyValue await_resume();
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
inline auto AnyValue::operator co_await() const
|
|
347
|
+
{
|
|
348
|
+
return AnyValueAwaiter{*this};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
namespace Constants
|
|
352
|
+
{
|
|
353
|
+
inline const AnyValue UNINITIALIZED = AnyValue::make_uninitialized();
|
|
354
|
+
inline const AnyValue UNDEFINED = AnyValue::make_undefined();
|
|
355
|
+
inline const AnyValue Null = AnyValue::make_null();
|
|
356
|
+
inline const AnyValue NaN = AnyValue::make_nan();
|
|
357
|
+
inline const AnyValue TRUE = AnyValue::make_boolean(true);
|
|
358
|
+
inline const AnyValue FALSE = AnyValue::make_boolean(false);
|
|
359
|
+
inline const AnyValue ZERO = AnyValue::make_number(0.0);
|
|
360
|
+
inline const AnyValue ONE = AnyValue::make_number(1.0);
|
|
361
|
+
}
|
|
362
|
+
}
|