@ugo-studio/jspp 0.1.9 → 0.2.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.
Files changed (48) hide show
  1. package/README.md +1 -1
  2. package/dist/cli-utils/args.js +2 -0
  3. package/dist/cli.js +1 -1
  4. package/package.json +1 -1
  5. package/src/prelude/any_value.hpp +185 -391
  6. package/src/prelude/any_value_access.hpp +170 -190
  7. package/src/prelude/any_value_defines.hpp +12 -12
  8. package/src/prelude/any_value_helpers.hpp +208 -26
  9. package/src/prelude/exception.hpp +27 -31
  10. package/src/prelude/exception_helpers.hpp +53 -49
  11. package/src/prelude/index.hpp +9 -4
  12. package/src/prelude/library/array.hpp +4 -9
  13. package/src/prelude/library/console.hpp +112 -112
  14. package/src/prelude/library/error.hpp +8 -8
  15. package/src/prelude/library/math.hpp +3 -3
  16. package/src/prelude/library/object.hpp +12 -24
  17. package/src/prelude/library/promise.hpp +1 -1
  18. package/src/prelude/library/symbol.hpp +1 -1
  19. package/src/prelude/library/timer.hpp +3 -3
  20. package/src/prelude/types.hpp +178 -130
  21. package/src/prelude/utils/access.hpp +338 -378
  22. package/src/prelude/utils/log_any_value/function.hpp +39 -39
  23. package/src/prelude/utils/log_any_value/log_any_value.hpp +1 -1
  24. package/src/prelude/utils/operators.hpp +20 -82
  25. package/src/prelude/utils/well_known_symbols.hpp +14 -15
  26. package/src/prelude/values/array.hpp +5 -3
  27. package/src/prelude/values/async_iterator.hpp +3 -1
  28. package/src/prelude/values/descriptors.hpp +15 -3
  29. package/src/prelude/values/function.hpp +5 -9
  30. package/src/prelude/values/helpers/array.hpp +208 -219
  31. package/src/prelude/values/helpers/async_iterator.hpp +7 -11
  32. package/src/prelude/values/helpers/function.hpp +12 -17
  33. package/src/prelude/values/helpers/iterator.hpp +108 -107
  34. package/src/prelude/values/helpers/object.hpp +104 -109
  35. package/src/prelude/values/helpers/promise.hpp +185 -119
  36. package/src/prelude/values/helpers/string.hpp +7 -10
  37. package/src/prelude/values/helpers/symbol.hpp +21 -23
  38. package/src/prelude/values/iterator.hpp +4 -1
  39. package/src/prelude/values/object.hpp +6 -4
  40. package/src/prelude/values/promise.hpp +5 -2
  41. package/src/prelude/values/prototypes/array.hpp +22 -22
  42. package/src/prelude/values/prototypes/async_iterator.hpp +3 -10
  43. package/src/prelude/values/prototypes/iterator.hpp +51 -58
  44. package/src/prelude/values/prototypes/promise.hpp +32 -28
  45. package/src/prelude/values/prototypes/string.hpp +5 -5
  46. package/src/prelude/values/prototypes/symbol.hpp +1 -1
  47. package/src/prelude/values/string.hpp +3 -1
  48. package/src/prelude/values/symbol.hpp +101 -102
@@ -17,83 +17,101 @@
17
17
  #include <cmath>
18
18
  #include <optional>
19
19
  #include <coroutine>
20
- #include <variant>
21
20
 
22
21
  #include "types.hpp"
23
22
  #include "values/non_values.hpp"
24
- #include "values/object.hpp"
25
- #include "values/array.hpp"
26
- #include "values/function.hpp"
27
- #include "values/iterator.hpp"
28
- #include "values/promise.hpp"
29
- #include "values/symbol.hpp"
30
- #include "values/string.hpp"
31
- #include "values/descriptors.hpp"
32
- #include "exception.hpp"
33
- #include "utils/well_known_symbols.hpp"
34
23
 
35
24
  namespace jspp
36
25
  {
37
- enum class JsType : uint8_t
38
- {
39
- Undefined = 0,
40
- Null = 1,
41
- Uninitialized = 2,
42
- Boolean = 3,
43
- Number = 4,
44
- String = 5,
45
- Object = 6,
46
- Array = 7,
47
- Function = 8,
48
- Iterator = 9,
49
- Symbol = 10,
50
- Promise = 11,
51
- DataDescriptor = 12,
52
- AccessorDescriptor = 13,
53
- AsyncIterator = 14,
54
- };
55
-
56
- // The variant order MUST match JsType
57
- using AnyValueVariant = std::variant<
58
- JsUndefined,
59
- JsNull,
60
- JsUninitialized,
61
- bool,
62
- double,
63
- std::shared_ptr<JsString>,
64
- std::shared_ptr<JsObject>,
65
- std::shared_ptr<JsArray>,
66
- std::shared_ptr<JsFunction>,
67
- std::shared_ptr<JsIterator<AnyValue>>,
68
- std::shared_ptr<JsSymbol>,
69
- std::shared_ptr<JsPromise>,
70
- std::shared_ptr<DataDescriptor>,
71
- std::shared_ptr<AccessorDescriptor>,
72
- std::shared_ptr<JsAsyncIterator<AnyValue>>>;
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)
73
37
 
74
38
  class AnyValue
75
39
  {
76
40
  private:
77
- AnyValueVariant storage;
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
+ return (storage & TAG_MASK) == tag;
57
+ }
78
58
 
79
59
  public:
60
+ inline HeapObject* get_ptr() const noexcept {
61
+ return reinterpret_cast<HeapObject*>(storage & PAYLOAD_MASK);
62
+ }
63
+
80
64
  // default ctor (Undefined)
81
- AnyValue() noexcept = default;
65
+ AnyValue() noexcept : storage(TAG_SPECIAL | VAL_UNDEFINED) {}
66
+
67
+ explicit AnyValue(double d) noexcept {
68
+ std::memcpy(&storage, &d, 8);
69
+ if (storage >= TAG_BASE) [[unlikely]] {
70
+ storage = 0x7FF8000000000000ULL;
71
+ }
72
+ }
82
73
 
83
- // Copy/Move handled by std::variant
84
- AnyValue(const AnyValue &) = default;
85
- AnyValue(AnyValue &&) noexcept = default;
86
- AnyValue &operator=(const AnyValue &) = default;
87
- AnyValue &operator=(AnyValue &&) noexcept = default;
74
+ explicit AnyValue(bool b) noexcept : storage(TAG_BOOLEAN | (b ? 1 : 0)) {}
88
75
 
89
- ~AnyValue() = default;
76
+ AnyValue(const AnyValue &other) noexcept : storage(other.storage) {
77
+ if (is_heap_object()) get_ptr()->ref();
78
+ }
79
+
80
+ AnyValue(AnyValue &&other) noexcept : storage(other.storage) {
81
+ other.storage = TAG_SPECIAL | VAL_UNDEFINED;
82
+ }
83
+
84
+ AnyValue &operator=(const AnyValue &other) noexcept {
85
+ if (this != &other) {
86
+ if (is_heap_object()) get_ptr()->deref();
87
+ storage = other.storage;
88
+ if (is_heap_object()) get_ptr()->ref();
89
+ }
90
+ return *this;
91
+ }
92
+
93
+ AnyValue &operator=(AnyValue &&other) noexcept {
94
+ if (this != &other) {
95
+ if (is_heap_object()) get_ptr()->deref();
96
+ storage = other.storage;
97
+ other.storage = TAG_SPECIAL | VAL_UNDEFINED;
98
+ }
99
+ return *this;
100
+ }
101
+
102
+ ~AnyValue() {
103
+ if (is_heap_object()) get_ptr()->deref();
104
+ }
90
105
 
91
106
  // Assignments
92
- AnyValue &operator=(const double &val)
93
- {
94
- storage = val;
107
+ AnyValue &operator=(double val) noexcept {
108
+ if (is_heap_object()) get_ptr()->deref();
109
+ std::memcpy(&storage, &val, 8);
110
+ if (storage >= TAG_BASE) [[unlikely]] {
111
+ storage = 0x7FF8000000000000ULL;
112
+ }
95
113
  return *this;
96
- };
114
+ }
97
115
 
98
116
  friend void swap(AnyValue &a, AnyValue &b) noexcept
99
117
  {
@@ -114,415 +132,191 @@ namespace jspp
114
132
  // factories -------------------------------------------------------
115
133
  static AnyValue make_number(double d) noexcept
116
134
  {
117
- AnyValue v;
118
- v.storage = d;
119
- return v;
135
+ return AnyValue(d);
120
136
  }
121
137
  static AnyValue make_nan() noexcept
122
138
  {
123
139
  AnyValue v;
124
- v.storage = std::numeric_limits<double>::quiet_NaN();
140
+ v.storage = 0x7FF8000000000000ULL;
125
141
  return v;
126
142
  }
127
143
  static AnyValue make_uninitialized() noexcept
128
144
  {
129
145
  AnyValue v;
130
- v.storage = JsUninitialized{};
146
+ v.storage = TAG_SPECIAL | VAL_UNINITIALIZED;
131
147
  return v;
132
148
  }
133
149
  static AnyValue make_undefined() noexcept
134
150
  {
135
151
  AnyValue v;
136
- v.storage = JsUndefined{};
152
+ v.storage = TAG_SPECIAL | VAL_UNDEFINED;
137
153
  return v;
138
154
  }
139
155
  static AnyValue make_null() noexcept
140
156
  {
141
157
  AnyValue v;
142
- v.storage = JsNull{};
158
+ v.storage = TAG_SPECIAL | VAL_NULL;
143
159
  return v;
144
160
  }
145
161
  static AnyValue make_boolean(bool b) noexcept
146
162
  {
147
- AnyValue v;
148
- v.storage = b;
149
- return v;
150
- }
151
- static AnyValue make_string(const std::string &raw_s) noexcept
152
- {
153
- AnyValue v;
154
- v.storage = std::make_shared<JsString>(raw_s);
155
- return v;
156
- }
157
- static AnyValue make_object(std::initializer_list<std::pair<std::string, AnyValue>> props) noexcept
158
- {
159
- AnyValue v;
160
- v.storage = std::make_shared<JsObject>(props);
161
- return v;
162
- }
163
- static AnyValue make_object(const std::map<std::string, AnyValue> &props) noexcept
164
- {
165
- AnyValue v;
166
- v.storage = std::make_shared<JsObject>(props);
167
- return v;
168
- }
169
- static AnyValue make_object_with_proto(std::initializer_list<std::pair<std::string, AnyValue>> props, const AnyValue &proto) noexcept
170
- {
171
- AnyValue v;
172
- auto protoPtr = std::make_shared<AnyValue>(proto);
173
- v.storage = std::make_shared<JsObject>(props, protoPtr);
174
- return v;
175
- }
176
- static AnyValue make_object_with_proto(const std::map<std::string, AnyValue> &props, const AnyValue &proto) noexcept
177
- {
178
- AnyValue v;
179
- auto protoPtr = std::make_shared<AnyValue>(proto);
180
- v.storage = std::make_shared<JsObject>(props, protoPtr);
181
- return v;
182
- }
183
- static AnyValue make_array(std::span<const AnyValue> dense) noexcept
184
- {
185
- AnyValue v;
186
- std::vector<AnyValue> vec;
187
- vec.reserve(dense.size());
188
- for (const auto &item : dense)
189
- vec.push_back(item);
190
- v.storage = std::make_shared<JsArray>(std::move(vec));
191
- return v;
192
- }
193
- static AnyValue make_array(const std::vector<AnyValue> &dense) noexcept
194
- {
195
- AnyValue v;
196
- v.storage = std::make_shared<JsArray>(dense);
197
- return v;
198
- }
199
- static AnyValue make_array(std::vector<AnyValue> &&dense) noexcept
200
- {
201
- AnyValue v;
202
- v.storage = std::make_shared<JsArray>(std::move(dense));
203
- return v;
204
- }
205
- static AnyValue make_array_with_proto(std::span<const AnyValue> dense, const AnyValue &proto) noexcept
206
- {
207
- AnyValue v;
208
- std::vector<AnyValue> vec;
209
- vec.reserve(dense.size());
210
- for (const auto &item : dense)
211
- vec.push_back(item);
212
- v.storage = std::make_shared<JsArray>(std::move(vec));
213
- std::get<std::shared_ptr<JsArray>>(v.storage)->proto = std::make_shared<AnyValue>(proto);
214
- return v;
215
- }
216
- static AnyValue make_array_with_proto(const std::vector<AnyValue> &dense, const AnyValue &proto) noexcept
217
- {
218
- AnyValue v;
219
- v.storage = std::make_shared<JsArray>(dense);
220
- std::get<std::shared_ptr<JsArray>>(v.storage)->proto = std::make_shared<AnyValue>(proto);
221
- return v;
222
- }
223
- static AnyValue make_function(const JsFunctionCallable &call, const std::optional<std::string> &name = std::nullopt, bool is_constructor = true) noexcept
224
- {
225
- AnyValue v;
226
- v.storage = std::make_shared<JsFunction>(call, name, std::unordered_map<std::string, AnyValue>{}, false, is_constructor);
227
-
228
- auto proto = make_object({});
229
- proto.define_data_property("constructor", AnyValue::make_data_descriptor(v, true, false, false));
230
- v.define_data_property("prototype", AnyValue::make_data_descriptor(proto, false, false, false));
231
-
232
- return v;
233
- }
234
- static AnyValue make_class(const JsFunctionCallable &call, const std::optional<std::string> &name = std::nullopt) noexcept
235
- {
236
- AnyValue v;
237
- // use Constructor A with is_cls = true
238
- v.storage = std::make_shared<JsFunction>(call, name, std::unordered_map<std::string, AnyValue>{}, true);
239
-
240
- auto proto = make_object({});
241
- proto.define_data_property("constructor", AnyValue::make_data_descriptor(v, true, false, false));
242
- v.define_data_property("prototype", AnyValue::make_data_descriptor(proto, false, false, false));
243
-
244
- return v;
245
- }
246
- static AnyValue make_generator(const JsFunctionCallable &call, const std::optional<std::string> &name = std::nullopt) noexcept
247
- {
248
- AnyValue v;
249
- // use Constructor B with is_gen = true
250
- v.storage = std::make_shared<JsFunction>(call, true, name);
251
-
252
- auto proto = make_object({});
253
- proto.define_data_property("constructor", AnyValue::make_data_descriptor(v, true, false, false));
254
- v.define_data_property("prototype", AnyValue::make_data_descriptor(proto, false, false, false));
255
-
256
- return v;
257
- }
258
- static AnyValue make_async_function(const JsFunctionCallable &call, const std::optional<std::string> &name = std::nullopt) noexcept
259
- {
260
- AnyValue v;
261
- // use Constructor C with is_async_func = true
262
- v.storage = std::make_shared<JsFunction>(call, false, true, name);
263
-
264
- auto proto = make_object({});
265
- proto.define_data_property("constructor", AnyValue::make_data_descriptor(v, true, false, false));
266
- v.define_data_property("prototype", AnyValue::make_data_descriptor(proto, false, false, false));
267
-
268
- return v;
269
- }
270
- static AnyValue make_async_generator(const JsFunctionCallable &call, const std::optional<std::string> &name = std::nullopt) noexcept
271
- {
272
- AnyValue v;
273
- // use Constructor C with is_gen = true and is_async_func = true
274
- v.storage = std::make_shared<JsFunction>(call, true, true, name);
275
-
276
- auto proto = make_object({});
277
- proto.define_data_property("constructor", AnyValue::make_data_descriptor(v, true, false, false));
278
- v.define_data_property("prototype", AnyValue::make_data_descriptor(proto, false, false, false));
279
-
280
- return v;
281
- }
282
- static AnyValue make_symbol(const std::string &description = "") noexcept
283
- {
284
- AnyValue v;
285
- v.storage = std::make_shared<JsSymbol>(description);
286
- return v;
287
- }
288
- static AnyValue make_promise(const JsPromise &promise) noexcept
289
- {
290
- AnyValue v;
291
- v.storage = std::make_shared<JsPromise>(promise);
292
- return v;
293
- }
294
- static AnyValue make_data_descriptor(const AnyValue &value, bool writable, bool enumerable, bool configurable) noexcept
295
- {
296
- AnyValue v;
297
- v.storage = std::make_shared<DataDescriptor>(std::make_shared<AnyValue>(value), writable, enumerable, configurable);
298
- return v;
299
- }
163
+ return AnyValue(b);
164
+ }
165
+
166
+ static AnyValue make_string(const std::string &raw_s) noexcept;
167
+ static AnyValue make_object(std::initializer_list<std::pair<std::string, AnyValue>> props) noexcept;
168
+ static AnyValue make_object(const std::map<std::string, AnyValue> &props) noexcept;
169
+ static AnyValue make_object_with_proto(std::initializer_list<std::pair<std::string, AnyValue>> props, AnyValue proto) noexcept;
170
+ static AnyValue make_object_with_proto(const std::map<std::string, AnyValue> &props, AnyValue proto) noexcept;
171
+ static AnyValue make_array(std::span<const AnyValue> dense) noexcept;
172
+ static AnyValue make_array(const std::vector<AnyValue> &dense) noexcept;
173
+ static AnyValue make_array(std::vector<AnyValue> &&dense) noexcept;
174
+ static AnyValue make_array_with_proto(std::span<const AnyValue> dense, AnyValue proto) noexcept;
175
+ static AnyValue make_array_with_proto(const std::vector<AnyValue> &dense, AnyValue proto) noexcept;
176
+ static AnyValue make_function(const JsFunctionCallable &call, const std::optional<std::string> &name = std::nullopt, bool is_constructor = true) noexcept;
177
+ static AnyValue make_class(const JsFunctionCallable &call, const std::optional<std::string> &name = std::nullopt) noexcept;
178
+ static AnyValue make_generator(const JsFunctionCallable &call, const std::optional<std::string> &name = std::nullopt) noexcept;
179
+ static AnyValue make_async_function(const JsFunctionCallable &call, const std::optional<std::string> &name = std::nullopt) noexcept;
180
+ static AnyValue make_async_generator(const JsFunctionCallable &call, const std::optional<std::string> &name = std::nullopt) noexcept;
181
+ static AnyValue make_symbol(const std::string &description = "") noexcept;
182
+ static AnyValue make_promise(const JsPromise &promise) noexcept;
183
+ static AnyValue make_data_descriptor(AnyValue value, bool writable, bool enumerable, bool configurable) noexcept;
300
184
  static AnyValue make_accessor_descriptor(const std::optional<std::function<AnyValue(const AnyValue &, std::span<const AnyValue>)>> &get,
301
185
  const std::optional<std::function<AnyValue(const AnyValue &, std::span<const AnyValue>)>> &set,
302
186
  bool enumerable,
303
- bool configurable) noexcept
304
- {
305
- AnyValue v;
306
- v.storage = std::make_shared<AccessorDescriptor>(get, set, enumerable, configurable);
307
- return v;
308
- }
187
+ bool configurable) noexcept;
309
188
 
310
- static AnyValue from_symbol(std::shared_ptr<JsSymbol> sym) noexcept
311
- {
312
- AnyValue v;
313
- v.storage = std::move(sym);
314
- return v;
315
- }
316
- static AnyValue from_string(std::shared_ptr<JsString> str) noexcept
317
- {
318
- AnyValue v;
319
- v.storage = std::move(str);
320
- return v;
321
- }
322
- static AnyValue from_iterator(JsIterator<AnyValue> &&iterator) noexcept
323
- {
324
- AnyValue v;
325
- v.storage = std::make_shared<JsIterator<AnyValue>>(std::move(iterator));
326
- return v;
327
- }
328
- static AnyValue from_iterator_ref(JsIterator<AnyValue> *iterator) noexcept
329
- {
330
- AnyValue v;
331
- v.storage = std::shared_ptr<JsIterator<AnyValue>>(iterator, [](JsIterator<AnyValue> *) {});
332
- return v;
333
- }
334
- static AnyValue from_async_iterator(JsAsyncIterator<AnyValue> &&iterator) noexcept
335
- {
189
+ static AnyValue from_symbol(JsSymbol *sym) noexcept;
190
+ static AnyValue from_string(JsString *str) noexcept;
191
+ static AnyValue from_iterator(JsIterator<AnyValue> &&iterator) noexcept;
192
+ static AnyValue from_iterator_ref(JsIterator<AnyValue> *iterator) noexcept;
193
+ static AnyValue from_async_iterator(JsAsyncIterator<AnyValue> &&iterator) noexcept;
194
+
195
+ // internal factory for wrapping raw heap object pointers
196
+ static AnyValue from_ptr(HeapObject* ptr) noexcept {
336
197
  AnyValue v;
337
- v.storage = std::make_shared<JsAsyncIterator<AnyValue>>(std::move(iterator));
198
+ v.storage = TAG_POINTER | reinterpret_cast<uint64_t>(ptr);
199
+ ptr->ref();
338
200
  return v;
339
201
  }
340
202
 
341
- // PROPERTY RESOLUTION HELPERS ---------------------------------------
342
- static AnyValue resolve_property_for_read(const AnyValue &val, const AnyValue &thisVal, const std::string &propName) noexcept
343
- {
344
- switch (val.get_type())
345
- {
346
- case JsType::DataDescriptor:
347
- {
348
- return *(val.as_data_descriptor()->value);
349
- }
350
- case JsType::AccessorDescriptor:
351
- {
352
- const auto &accessor = val.as_accessor_descriptor();
353
- if (accessor->get.has_value())
354
- return accessor->get.value()(thisVal, std::span<const AnyValue>{});
355
- else
356
- {
357
- static AnyValue undefined = AnyValue{};
358
- return undefined;
359
- }
360
- }
361
- default:
362
- {
363
- return val;
364
- }
365
- }
366
- }
367
- static AnyValue resolve_property_for_write(AnyValue &val, const AnyValue &thisVal, const AnyValue &new_val, const std::string &propName)
368
- {
369
- switch (val.get_type())
370
- {
371
- case JsType::DataDescriptor:
372
- {
373
- const auto &data = val.as_data_descriptor();
374
- if (data->writable)
375
- {
376
- *(data->value) = new_val;
377
- return new_val;
378
- }
379
- else
380
- {
381
- throw Exception::make_exception("Cannot assign to read only property '" + propName + "' of object '#<Object>'", "TypeError");
382
- }
383
- }
384
- case JsType::AccessorDescriptor:
385
- {
386
- const auto &accessor = val.as_accessor_descriptor();
387
- if (accessor->set.has_value())
388
- {
389
- const AnyValue args[] = {new_val};
390
- accessor->set.value()(thisVal, args);
391
- return new_val;
392
- }
393
- else
394
- {
395
- throw Exception::make_exception("Cannot set property of #<Object> which has only a getter", "TypeError");
396
- }
397
- }
398
- default:
399
- {
400
- val = new_val;
401
- return new_val;
402
- }
403
- }
404
- }
203
+ static AnyValue resolve_property_for_read(const AnyValue &val, const AnyValue &thisVal, const std::string &propName) noexcept;
204
+ static AnyValue resolve_property_for_write(AnyValue &val, const AnyValue &thisVal, const AnyValue &new_val, const std::string &propName);
405
205
 
406
206
  // TYPE CHECKERS AND ACCESSORS ---------------------------------------
407
- JsType get_type() const noexcept { return static_cast<JsType>(storage.index()); }
408
- bool is_number() const noexcept { return storage.index() == 4; }
409
- bool is_string() const noexcept { return storage.index() == 5; }
410
- bool is_object() const noexcept { return storage.index() == 6; }
411
- bool is_array() const noexcept { return storage.index() == 7; }
412
- bool is_function() const noexcept { return storage.index() == 8; }
413
- bool is_iterator() const noexcept { return storage.index() == 9; }
414
- bool is_boolean() const noexcept { return storage.index() == 3; }
415
- bool is_symbol() const noexcept { return storage.index() == 10; }
416
- bool is_promise() const noexcept { return storage.index() == 11; }
417
- bool is_null() const noexcept { return storage.index() == 1; }
418
- bool is_undefined() const noexcept { return storage.index() == 0; }
419
- bool is_uninitialized() const noexcept { return storage.index() == 2; }
420
- bool is_data_descriptor() const noexcept { return storage.index() == 12; }
421
- bool is_accessor_descriptor() const noexcept { return storage.index() == 13; }
422
- bool is_async_iterator() const noexcept { return storage.index() == 14; }
423
- bool is_generator() const noexcept { return is_function() && as_function()->is_generator; }
424
-
425
- // --- TYPE CASTERS
207
+ JsType get_type() const noexcept {
208
+ if (is_number()) return JsType::Number;
209
+ if (is_heap_object()) return get_ptr()->get_heap_type();
210
+ if (is_boolean()) return JsType::Boolean;
211
+ if (is_undefined()) return JsType::Undefined;
212
+ if (is_null()) return JsType::Null;
213
+ if (is_uninitialized()) return JsType::Uninitialized;
214
+ return JsType::Undefined;
215
+ }
216
+
217
+ inline bool is_number() const noexcept { return storage < TAG_BASE; }
218
+ inline bool is_heap_object() const noexcept { return has_tag(TAG_POINTER); }
219
+ inline bool is_string() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::String; }
220
+ inline bool is_object() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::Object; }
221
+ inline bool is_array() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::Array; }
222
+ inline bool is_function() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::Function; }
223
+ inline bool is_iterator() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::Iterator; }
224
+ inline bool is_boolean() const noexcept { return has_tag(TAG_BOOLEAN); }
225
+ inline bool is_symbol() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::Symbol; }
226
+ inline bool is_promise() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::Promise; }
227
+ inline bool is_null() const noexcept { return storage == (TAG_SPECIAL | VAL_NULL); }
228
+ inline bool is_undefined() const noexcept { return storage == (TAG_SPECIAL | VAL_UNDEFINED); }
229
+ inline bool is_uninitialized() const noexcept { return storage == (TAG_SPECIAL | VAL_UNINITIALIZED); }
230
+ inline bool is_data_descriptor() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::DataDescriptor; }
231
+ inline bool is_accessor_descriptor() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::AccessorDescriptor; }
232
+ inline bool is_async_iterator() const noexcept { return is_heap_object() && get_ptr()->get_heap_type() == JsType::AsyncIterator; }
233
+
234
+ JsString* as_string() const noexcept;
235
+ JsObject* as_object() const noexcept;
236
+ JsArray* as_array() const noexcept;
237
+ JsFunction* as_function() const noexcept;
238
+ JsSymbol* as_symbol() const noexcept;
239
+ JsPromise* as_promise() const noexcept;
240
+ JsIterator<AnyValue>* as_iterator() const noexcept;
241
+ JsAsyncIterator<AnyValue>* as_async_iterator() const noexcept;
242
+ DataDescriptor* as_data_descriptor() const noexcept;
243
+ AccessorDescriptor* as_accessor_descriptor() const noexcept;
244
+
245
+ bool is_generator() const noexcept;
246
+
426
247
  double as_double() const noexcept
427
248
  {
428
- return std::get<double>(storage);
249
+ double d;
250
+ std::memcpy(&d, &storage, 8);
251
+ return d;
429
252
  }
430
253
  bool as_boolean() const noexcept
431
254
  {
432
- return std::get<bool>(storage);
433
- }
434
- JsString *as_string() const noexcept
435
- {
436
- return std::get<std::shared_ptr<JsString>>(storage).get();
437
- }
438
- JsObject *as_object() const noexcept
439
- {
440
- return std::get<std::shared_ptr<JsObject>>(storage).get();
441
- }
442
- JsArray *as_array() const noexcept
443
- {
444
- return std::get<std::shared_ptr<JsArray>>(storage).get();
445
- }
446
- JsFunction *as_function() const noexcept
447
- {
448
- return std::get<std::shared_ptr<JsFunction>>(storage).get();
449
- }
450
- JsSymbol *as_symbol() const noexcept
451
- {
452
- return std::get<std::shared_ptr<JsSymbol>>(storage).get();
453
- }
454
- JsPromise *as_promise() const noexcept
455
- {
456
- return std::get<std::shared_ptr<JsPromise>>(storage).get();
457
- }
458
- std::shared_ptr<JsIterator<AnyValue>> as_iterator() const
459
- {
460
- return std::get<std::shared_ptr<JsIterator<AnyValue>>>(storage);
461
- }
462
- std::shared_ptr<JsAsyncIterator<AnyValue>> as_async_iterator() const
463
- {
464
- return std::get<std::shared_ptr<JsAsyncIterator<AnyValue>>>(storage);
465
- }
466
- DataDescriptor *as_data_descriptor() const noexcept
467
- {
468
- return std::get<std::shared_ptr<DataDescriptor>>(storage).get();
469
- }
470
- AccessorDescriptor *as_accessor_descriptor() const noexcept
471
- {
472
- return std::get<std::shared_ptr<AccessorDescriptor>>(storage).get();
255
+ return static_cast<bool>(storage & 1);
473
256
  }
474
257
 
475
- // --- CO_AWAIT Operator ---
476
258
  auto operator co_await() const;
477
259
 
478
- // --- PROPERTY ACCESS OPERATORS
479
260
  bool has_property(const std::string &key) const;
261
+ bool has_property(const char* key) const { return has_property(std::string(key)); }
262
+
480
263
  AnyValue get_own_property(const std::string &key) const;
264
+ AnyValue get_own_property(const char* key) const { return get_own_property(std::string(key)); }
481
265
  AnyValue get_own_property(uint32_t idx) const;
266
+ AnyValue get_own_property(int idx) const { return get_own_property(static_cast<uint32_t>(idx)); }
482
267
  AnyValue get_own_property(const AnyValue &key) const;
483
- // for getting values with a specific receiver (used in inheritance chains)
268
+
484
269
  AnyValue get_property_with_receiver(const std::string &key, const AnyValue &receiver) const;
485
- // for setting values
270
+ AnyValue get_property_with_receiver(const char* key, const AnyValue &receiver) const { return get_property_with_receiver(std::string(key), receiver); }
271
+
486
272
  AnyValue set_own_property(const std::string &key, const AnyValue &value) const;
273
+ AnyValue set_own_property(const char* key, const AnyValue &value) const { return set_own_property(std::string(key), value); }
487
274
  AnyValue set_own_property(uint32_t idx, const AnyValue &value) const;
275
+ AnyValue set_own_property(int idx, const AnyValue &value) const { return set_own_property(static_cast<uint32_t>(idx), value); }
488
276
  AnyValue set_own_property(const AnyValue &key, const AnyValue &value) const;
489
- // for calling the gotten the property
277
+
490
278
  AnyValue call_own_property(const std::string &key, std::span<const AnyValue> args) const;
279
+ AnyValue call_own_property(const char* key, std::span<const AnyValue> args) const { return call_own_property(std::string(key), args); }
491
280
  AnyValue call_own_property(uint32_t idx, std::span<const AnyValue> args) const;
281
+ AnyValue call_own_property(int idx, std::span<const AnyValue> args) const { return call_own_property(static_cast<uint32_t>(idx), args); }
492
282
  AnyValue call_own_property(const AnyValue &key, std::span<const AnyValue> args) const;
493
283
 
494
- // --- DEFINERS (Object.defineProperty semantics)
495
284
  void define_data_property(const std::string &key, const AnyValue &value);
285
+ void define_data_property(const char* key, const AnyValue &value) { define_data_property(std::string(key), value); }
496
286
  void define_data_property(const AnyValue &key, const AnyValue &value);
497
287
  void define_data_property(const std::string &key, const AnyValue &value, bool writable, bool enumerable, bool configurable);
288
+ void define_data_property(const char* key, const AnyValue &value, bool writable, bool enumerable, bool configurable) { define_data_property(std::string(key), value, writable, enumerable, configurable); }
289
+
498
290
  void define_getter(const std::string &key, const AnyValue &getter);
291
+ void define_getter(const char* key, const AnyValue &getter) { define_getter(std::string(key), getter); }
499
292
  void define_getter(const AnyValue &key, const AnyValue &getter);
293
+
500
294
  void define_setter(const std::string &key, const AnyValue &setter);
295
+ void define_setter(const char* key, const AnyValue &setter) { define_setter(std::string(key), setter); }
501
296
  void define_setter(const AnyValue &key, const AnyValue &setter);
502
297
 
503
- // --- HELPERS
504
- const AnyValue call(const AnyValue &thisVal, std::span<const AnyValue> args, const std::optional<std::string> &expr) const;
505
- const AnyValue construct(std::span<const AnyValue> args, const std::optional<std::string> &name) const;
298
+ AnyValue call(const AnyValue &thisVal, std::span<const AnyValue> args, const std::optional<std::string> &expr = std::nullopt) const;
299
+ AnyValue construct(std::span<const AnyValue> args, const std::optional<std::string> &name = std::nullopt) const;
506
300
  void set_prototype(const AnyValue &proto);
507
301
  std::string to_std_string() const;
302
+
303
+ inline uint64_t get_storage() const noexcept { return storage; }
304
+ inline void* get_raw_ptr() const noexcept { return reinterpret_cast<void*>(storage & PAYLOAD_MASK); }
508
305
  };
509
306
 
510
- // Awaiter for AnyValue
511
307
  struct AnyValueAwaiter
512
308
  {
513
- AnyValue value; // Held by value
309
+ AnyValue value;
514
310
  bool await_ready();
515
311
  void await_suspend(std::coroutine_handle<> h);
516
312
  AnyValue await_resume();
517
313
  };
518
314
 
519
- // Inline implementation of operator co_await
520
315
  inline auto AnyValue::operator co_await() const
521
316
  {
522
317
  return AnyValueAwaiter{*this};
523
318
  }
524
319
 
525
- // Global Constants for Optimization
526
320
  namespace Constants
527
321
  {
528
322
  inline const AnyValue UNINITIALIZED = AnyValue::make_uninitialized();
@@ -534,4 +328,4 @@ namespace jspp
534
328
  inline const AnyValue ZERO = AnyValue::make_number(0.0);
535
329
  inline const AnyValue ONE = AnyValue::make_number(1.0);
536
330
  }
537
- }
331
+ }