@ugo-studio/jspp 0.1.3 → 0.1.4

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 (69) hide show
  1. package/README.md +2 -2
  2. package/dist/analysis/scope.js +16 -4
  3. package/dist/analysis/typeAnalyzer.js +253 -20
  4. package/dist/ast/types.js +6 -0
  5. package/dist/cli.js +1 -2
  6. package/dist/core/codegen/class-handlers.js +127 -0
  7. package/dist/core/codegen/control-flow-handlers.js +464 -0
  8. package/dist/core/codegen/declaration-handlers.js +31 -14
  9. package/dist/core/codegen/expression-handlers.js +429 -117
  10. package/dist/core/codegen/function-handlers.js +91 -15
  11. package/dist/core/codegen/helpers.js +66 -2
  12. package/dist/core/codegen/index.js +17 -6
  13. package/dist/core/codegen/literal-handlers.js +3 -0
  14. package/dist/core/codegen/statement-handlers.js +133 -204
  15. package/dist/core/codegen/visitor.js +29 -3
  16. package/package.json +3 -3
  17. package/src/prelude/any_value.hpp +658 -634
  18. package/src/prelude/any_value_access.hpp +103 -0
  19. package/src/prelude/any_value_defines.hpp +151 -0
  20. package/src/prelude/any_value_helpers.hpp +246 -225
  21. package/src/prelude/exception.hpp +31 -0
  22. package/src/prelude/exception_helpers.hpp +49 -0
  23. package/src/prelude/index.hpp +18 -9
  24. package/src/prelude/library/console.hpp +13 -13
  25. package/src/prelude/library/error.hpp +111 -0
  26. package/src/prelude/library/global.hpp +15 -4
  27. package/src/prelude/library/performance.hpp +2 -2
  28. package/src/prelude/library/promise.hpp +121 -0
  29. package/src/prelude/library/symbol.hpp +3 -4
  30. package/src/prelude/library/timer.hpp +92 -0
  31. package/src/prelude/scheduler.hpp +145 -0
  32. package/src/prelude/types.hpp +10 -1
  33. package/src/prelude/utils/access.hpp +174 -0
  34. package/src/prelude/utils/log_any_value/array.hpp +245 -0
  35. package/src/prelude/utils/log_any_value/config.hpp +32 -0
  36. package/src/prelude/utils/log_any_value/function.hpp +37 -0
  37. package/src/prelude/utils/log_any_value/fwd.hpp +15 -0
  38. package/src/prelude/utils/log_any_value/helpers.hpp +62 -0
  39. package/src/prelude/utils/log_any_value/log_any_value.hpp +94 -0
  40. package/src/prelude/utils/log_any_value/object.hpp +119 -0
  41. package/src/prelude/utils/log_any_value/primitives.hpp +41 -0
  42. package/src/prelude/{operators.hpp → utils/operators.hpp} +29 -10
  43. package/src/prelude/{well_known_symbols.hpp → utils/well_known_symbols.hpp} +0 -1
  44. package/src/prelude/values/array.hpp +3 -2
  45. package/src/prelude/{descriptors.hpp → values/descriptors.hpp} +2 -2
  46. package/src/prelude/values/function.hpp +76 -51
  47. package/src/prelude/values/helpers/array.hpp +20 -11
  48. package/src/prelude/values/helpers/function.hpp +125 -77
  49. package/src/prelude/values/helpers/iterator.hpp +13 -7
  50. package/src/prelude/values/helpers/object.hpp +36 -6
  51. package/src/prelude/values/helpers/promise.hpp +181 -0
  52. package/src/prelude/values/helpers/string.hpp +3 -3
  53. package/src/prelude/values/helpers/symbol.hpp +2 -2
  54. package/src/prelude/values/iterator.hpp +13 -5
  55. package/src/prelude/values/object.hpp +6 -2
  56. package/src/prelude/values/promise.hpp +73 -0
  57. package/src/prelude/values/prototypes/array.hpp +16 -16
  58. package/src/prelude/values/prototypes/function.hpp +4 -4
  59. package/src/prelude/values/prototypes/iterator.hpp +11 -10
  60. package/src/prelude/values/prototypes/object.hpp +26 -0
  61. package/src/prelude/values/prototypes/promise.hpp +124 -0
  62. package/src/prelude/values/prototypes/string.hpp +26 -26
  63. package/src/prelude/values/prototypes/symbol.hpp +5 -3
  64. package/src/prelude/values/string.hpp +1 -1
  65. package/src/prelude/values/symbol.hpp +1 -1
  66. package/src/prelude/access.hpp +0 -91
  67. package/src/prelude/error.hpp +0 -31
  68. package/src/prelude/error_helpers.hpp +0 -59
  69. package/src/prelude/log_string.hpp +0 -407
@@ -1,634 +1,658 @@
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
-
20
- #include "types.hpp"
21
- #include "values/non_values.hpp"
22
- #include "values/object.hpp"
23
- #include "values/array.hpp"
24
- #include "values/function.hpp"
25
- #include "values/iterator.hpp"
26
- #include "values/symbol.hpp"
27
- #include "values/string.hpp"
28
- #include "error.hpp"
29
- #include "descriptors.hpp"
30
- #include "well_known_symbols.hpp"
31
-
32
- namespace jspp
33
- {
34
- enum class JsType : uint8_t
35
- {
36
- Undefined = 0,
37
- Null = 1,
38
- Uninitialized = 2,
39
- Boolean = 3,
40
- Number = 4,
41
- String = 5,
42
- Object = 6,
43
- Array = 7,
44
- Function = 8,
45
- Iterator = 9,
46
- Symbol = 10,
47
- DataDescriptor = 11,
48
- AccessorDescriptor = 12,
49
- };
50
-
51
- // Tagged storage with a union for payload
52
- struct TaggedValue
53
- {
54
- JsType type;
55
- union
56
- {
57
- JsUndefined undefined;
58
- JsNull null;
59
- JsUninitialized uninitialized;
60
- bool boolean;
61
- double number;
62
- std::shared_ptr<JsString> str;
63
- std::shared_ptr<JsObject> object;
64
- std::shared_ptr<JsArray> array;
65
- std::shared_ptr<JsFunction> function;
66
- std::shared_ptr<JsIterator<AnyValue>> iterator;
67
- std::shared_ptr<JsSymbol> symbol;
68
- std::shared_ptr<DataDescriptor> data_desc;
69
- std::shared_ptr<AccessorDescriptor> accessor_desc;
70
- };
71
-
72
- TaggedValue() noexcept : type(JsType::Undefined), undefined{} {}
73
- ~TaggedValue() {}
74
- };
75
-
76
- class AnyValue
77
- {
78
- private:
79
- TaggedValue storage;
80
-
81
- void destroy_value() noexcept
82
- {
83
- switch (storage.type)
84
- {
85
- case JsType::String:
86
- storage.str.~shared_ptr();
87
- break;
88
- case JsType::Object:
89
- storage.object.~shared_ptr();
90
- break;
91
- case JsType::Array:
92
- storage.array.~shared_ptr();
93
- break;
94
- case JsType::Function:
95
- storage.function.~shared_ptr();
96
- break;
97
- case JsType::Iterator:
98
- storage.iterator.~shared_ptr();
99
- break;
100
- case JsType::Symbol:
101
- storage.symbol.~shared_ptr();
102
- break;
103
- case JsType::DataDescriptor:
104
- storage.data_desc.~shared_ptr();
105
- break;
106
- case JsType::AccessorDescriptor:
107
- storage.accessor_desc.~shared_ptr();
108
- break;
109
- default:
110
- break;
111
- }
112
- }
113
-
114
- void reset_to_undefined() noexcept
115
- {
116
- destroy_value();
117
- storage.type = JsType::Undefined;
118
- storage.undefined = JsUndefined{};
119
- }
120
-
121
- void move_from(AnyValue &other) noexcept
122
- {
123
- storage.type = other.storage.type;
124
- switch (other.storage.type)
125
- {
126
- case JsType::Undefined:
127
- storage.undefined = JsUndefined{};
128
- break;
129
- case JsType::Null:
130
- storage.null = JsNull{};
131
- break;
132
- case JsType::Uninitialized:
133
- storage.uninitialized = JsUninitialized{};
134
- break;
135
- case JsType::Boolean:
136
- storage.boolean = other.storage.boolean;
137
- break;
138
- case JsType::Number:
139
- storage.number = other.storage.number;
140
- break;
141
- case JsType::String:
142
- new (&storage.str) std::shared_ptr<JsString>(std::move(other.storage.str));
143
- break;
144
- case JsType::Object:
145
- new (&storage.object) std::shared_ptr<JsObject>(std::move(other.storage.object));
146
- break;
147
- case JsType::Array:
148
- new (&storage.array) std::shared_ptr<JsArray>(std::move(other.storage.array));
149
- break;
150
- case JsType::Function:
151
- new (&storage.function) std::shared_ptr<JsFunction>(std::move(other.storage.function));
152
- break;
153
- case JsType::Iterator:
154
- new (&storage.iterator) std::shared_ptr<JsIterator<AnyValue>>(std::move(other.storage.iterator));
155
- break;
156
- case JsType::Symbol:
157
- new (&storage.symbol) std::shared_ptr<JsSymbol>(std::move(other.storage.symbol));
158
- break;
159
- case JsType::DataDescriptor:
160
- new (&storage.data_desc) std::shared_ptr<DataDescriptor>(std::move(other.storage.data_desc));
161
- break;
162
- case JsType::AccessorDescriptor:
163
- new (&storage.accessor_desc) std::shared_ptr<AccessorDescriptor>(std::move(other.storage.accessor_desc));
164
- break;
165
- }
166
- }
167
-
168
- void copy_from(const AnyValue &other)
169
- {
170
- storage.type = other.storage.type;
171
- switch (other.storage.type)
172
- {
173
- case JsType::Undefined:
174
- storage.undefined = JsUndefined{};
175
- break;
176
- case JsType::Null:
177
- storage.null = JsNull{};
178
- break;
179
- case JsType::Uninitialized:
180
- storage.uninitialized = JsUninitialized{};
181
- break;
182
- case JsType::Boolean:
183
- storage.boolean = other.storage.boolean;
184
- break;
185
- case JsType::Number:
186
- storage.number = other.storage.number;
187
- break;
188
- case JsType::String:
189
- new (&storage.str) std::shared_ptr<JsString>(std::make_shared<JsString>(*other.storage.str));
190
- break;
191
- case JsType::Object:
192
- new (&storage.object) std::shared_ptr<JsObject>(other.storage.object); // shallow copy
193
- break;
194
- case JsType::Array:
195
- new (&storage.array) std::shared_ptr<JsArray>(other.storage.array); // shallow copy
196
- break;
197
- case JsType::Function:
198
- new (&storage.function) std::shared_ptr<JsFunction>(other.storage.function); // shallow copy
199
- break;
200
- case JsType::Iterator:
201
- new (&storage.iterator) std::shared_ptr<JsIterator<AnyValue>>(other.storage.iterator); // shallow copy
202
- break;
203
- case JsType::Symbol:
204
- new (&storage.symbol) std::shared_ptr<JsSymbol>(other.storage.symbol); // shallow copy (shared)
205
- break;
206
- case JsType::DataDescriptor:
207
- new (&storage.data_desc) std::shared_ptr<DataDescriptor>(other.storage.data_desc); // shallow copy
208
- break;
209
- case JsType::AccessorDescriptor:
210
- new (&storage.accessor_desc) std::shared_ptr<AccessorDescriptor>(other.storage.accessor_desc); // shallow copy
211
- break;
212
- }
213
- }
214
-
215
- public:
216
- // default ctor (Undefined)
217
- AnyValue() noexcept
218
- {
219
- storage.type = JsType::Undefined;
220
- storage.undefined = JsUndefined{};
221
- }
222
-
223
- // 1. Destructor
224
- ~AnyValue() noexcept
225
- {
226
- destroy_value();
227
- }
228
-
229
- // 2. Copy Constructor (deep copy)
230
- AnyValue(const AnyValue &other)
231
- {
232
- copy_from(other);
233
- }
234
-
235
- // 3. Copy Assignment Operator
236
- AnyValue &operator=(const AnyValue &other)
237
- {
238
- if (this != &other)
239
- {
240
- destroy_value();
241
- copy_from(other);
242
- }
243
- return *this;
244
- }
245
-
246
- // 4. Move Constructor
247
- AnyValue(AnyValue &&other) noexcept
248
- {
249
- storage.type = JsType::Undefined;
250
- storage.undefined = JsUndefined{};
251
- move_from(other);
252
- other.reset_to_undefined();
253
- }
254
-
255
- // 5. Move Assignment Operator
256
- AnyValue &operator=(AnyValue &&other) noexcept
257
- {
258
- if (this != &other)
259
- {
260
- destroy_value();
261
- move_from(other);
262
- other.reset_to_undefined();
263
- }
264
- return *this;
265
- }
266
-
267
- friend void swap(AnyValue &a, AnyValue &b) noexcept
268
- {
269
- AnyValue tmp(std::move(a));
270
- a = std::move(b);
271
- b = std::move(tmp);
272
- }
273
-
274
- // factories -------------------------------------------------------
275
- static AnyValue make_number(double d) noexcept
276
- {
277
- AnyValue v;
278
- v.storage.type = JsType::Number;
279
- v.storage.number = d;
280
- return v;
281
- }
282
- static AnyValue make_nan() noexcept
283
- {
284
- AnyValue v;
285
- v.storage.type = JsType::Number;
286
- v.storage.number = std::numeric_limits<double>::quiet_NaN();
287
- return v;
288
- }
289
- static AnyValue make_uninitialized() noexcept
290
- {
291
- AnyValue v;
292
- v.storage.type = JsType::Uninitialized;
293
- v.storage.uninitialized = JsUninitialized{};
294
- return v;
295
- }
296
- static AnyValue make_undefined() noexcept
297
- {
298
- AnyValue v;
299
- v.storage.type = JsType::Undefined;
300
- v.storage.undefined = JsUndefined{};
301
- return v;
302
- }
303
- static AnyValue make_null() noexcept
304
- {
305
- AnyValue v;
306
- v.storage.type = JsType::Null;
307
- v.storage.null = JsNull{};
308
- return v;
309
- }
310
- static AnyValue make_boolean(bool b) noexcept
311
- {
312
- AnyValue v;
313
- v.storage.type = JsType::Boolean;
314
- v.storage.boolean = b;
315
- return v;
316
- }
317
- static AnyValue make_string(const std::string &raw_s) noexcept
318
- {
319
- AnyValue v;
320
- v.storage.type = JsType::String;
321
- new (&v.storage.str) std::shared_ptr<JsString>(std::make_shared<JsString>(raw_s));
322
- return v;
323
- }
324
- static AnyValue make_object(const std::map<std::string, AnyValue> &props) noexcept
325
- {
326
- AnyValue v;
327
- v.storage.type = JsType::Object;
328
- new (&v.storage.object) std::shared_ptr<JsObject>(std::make_shared<JsObject>(props));
329
- return v;
330
- }
331
- static AnyValue make_array(const std::vector<std::optional<AnyValue>> &dense) noexcept
332
- {
333
- AnyValue v;
334
- v.storage.type = JsType::Array;
335
- new (&v.storage.array) std::shared_ptr<JsArray>(std::make_shared<JsArray>(dense));
336
- return v;
337
- }
338
- static AnyValue make_function(const JsFunctionCallable &call, const std::string &name) noexcept
339
- {
340
- AnyValue v;
341
- v.storage.type = JsType::Function;
342
- new (&v.storage.function) std::shared_ptr<JsFunction>(std::make_shared<JsFunction>(call, name));
343
- return v;
344
- }
345
- static AnyValue make_generator(const JsFunctionCallable &call, const std::string &name) noexcept
346
- {
347
- AnyValue v;
348
- v.storage.type = JsType::Function;
349
- new (&v.storage.function) std::shared_ptr<JsFunction>(std::make_shared<JsFunction>(call, true, name));
350
- return v;
351
- }
352
- static AnyValue make_symbol(const std::string &description = "") noexcept
353
- {
354
- AnyValue v;
355
- v.storage.type = JsType::Symbol;
356
- new (&v.storage.symbol) std::shared_ptr<JsSymbol>(std::make_shared<JsSymbol>(description));
357
- return v;
358
- }
359
- static AnyValue make_data_descriptor(const AnyValue &value, bool writable, bool enumerable, bool configurable) noexcept
360
- {
361
- AnyValue v;
362
- v.storage.type = JsType::DataDescriptor;
363
- new (&v.storage.data_desc) std::shared_ptr<DataDescriptor>(std::make_shared<DataDescriptor>(std::make_shared<AnyValue>(value), writable, enumerable, configurable));
364
- return v;
365
- }
366
- static AnyValue make_accessor_descriptor(const std::optional<std::function<AnyValue(const std::vector<AnyValue> &)>> &get,
367
- const std::optional<std::function<AnyValue(const std::vector<AnyValue> &)>> &set,
368
- bool enumerable,
369
- bool configurable) noexcept
370
- {
371
- AnyValue v;
372
- v.storage.type = JsType::AccessorDescriptor;
373
- new (&v.storage.accessor_desc) std::shared_ptr<AccessorDescriptor>(std::make_shared<AccessorDescriptor>(get, set, enumerable, configurable));
374
- return v;
375
- }
376
-
377
- static AnyValue from_symbol(std::shared_ptr<JsSymbol> sym) noexcept
378
- {
379
- AnyValue v;
380
- v.storage.type = JsType::Symbol;
381
- new (&v.storage.symbol) std::shared_ptr<JsSymbol>(std::move(sym));
382
- return v;
383
- }
384
- static AnyValue from_string(std::shared_ptr<JsString> str) noexcept
385
- {
386
- AnyValue v;
387
- v.storage.type = JsType::String;
388
- new (&v.storage.str) std::shared_ptr<JsString>(std::move(str));
389
- return v;
390
- }
391
- static AnyValue from_iterator(JsIterator<AnyValue> &&iterator) noexcept
392
- {
393
- AnyValue v;
394
- v.storage.type = JsType::Iterator;
395
- new (&v.storage.iterator) std::shared_ptr<JsIterator<AnyValue>>(std::make_shared<JsIterator<AnyValue>>(std::move(iterator)));
396
- return v;
397
- }
398
- static AnyValue from_iterator_ref(JsIterator<AnyValue> *iterator) noexcept
399
- {
400
- AnyValue v;
401
- v.storage.type = JsType::Iterator;
402
- new (&v.storage.iterator) std::shared_ptr<JsIterator<AnyValue>>(iterator, [](JsIterator<AnyValue> *) {});
403
- return v;
404
- }
405
-
406
- // property resolution helpers ---------------------------------------
407
- static AnyValue resolve_property_for_read(const AnyValue &val) noexcept
408
- {
409
- switch (val.storage.type)
410
- {
411
- case JsType::DataDescriptor:
412
- {
413
- return *(val.storage.data_desc->value);
414
- }
415
- case JsType::AccessorDescriptor:
416
- {
417
- if (val.storage.accessor_desc->get.has_value())
418
- return val.storage.accessor_desc->get.value()({});
419
- else
420
- {
421
- static AnyValue undefined = AnyValue{};
422
- return undefined;
423
- }
424
- }
425
- default:
426
- {
427
- return val;
428
- }
429
- }
430
- }
431
- static AnyValue resolve_property_for_write(AnyValue &val, const AnyValue &new_val)
432
- {
433
- switch (val.storage.type)
434
- {
435
- case JsType::DataDescriptor:
436
- {
437
- *(val.storage.data_desc->value) = new_val;
438
- return new_val;
439
- }
440
- case JsType::AccessorDescriptor:
441
- {
442
- if (val.storage.accessor_desc->set.has_value())
443
- {
444
- val.storage.accessor_desc->set.value()({new_val});
445
- return new_val;
446
- }
447
- else
448
- {
449
- throw RuntimeError::make_error("Cannot set property of #<Object> which has only a getter", "TypeError");
450
- }
451
- }
452
- default:
453
- {
454
- val = new_val;
455
- return new_val;
456
- }
457
- }
458
- }
459
-
460
- // type checkers and accessors ---------------------------------------
461
- bool is_number() const noexcept { return storage.type == JsType::Number; }
462
- bool is_string() const noexcept { return storage.type == JsType::String; }
463
- bool is_object() const noexcept { return storage.type == JsType::Object; }
464
- bool is_array() const noexcept { return storage.type == JsType::Array; }
465
- bool is_function() const noexcept { return storage.type == JsType::Function; }
466
- bool is_iterator() const noexcept { return storage.type == JsType::Iterator; }
467
- bool is_boolean() const noexcept { return storage.type == JsType::Boolean; }
468
- bool is_symbol() const noexcept { return storage.type == JsType::Symbol; }
469
- bool is_null() const noexcept { return storage.type == JsType::Null; }
470
- bool is_undefined() const noexcept { return storage.type == JsType::Undefined; }
471
- bool is_uninitialized() const noexcept { return storage.type == JsType::Uninitialized; }
472
- bool is_data_descriptor() const noexcept { return storage.type == JsType::DataDescriptor; }
473
- bool is_accessor_descriptor() const noexcept { return storage.type == JsType::AccessorDescriptor; }
474
- bool is_generator() const noexcept { return storage.type == JsType::Function && storage.function->is_generator; }
475
-
476
- // --- TYPE CASTERS
477
- double as_double() const noexcept
478
- {
479
- assert(is_number());
480
- return storage.number;
481
- }
482
- bool as_boolean() const noexcept
483
- {
484
- assert(is_boolean());
485
- return storage.boolean;
486
- }
487
- JsString *as_string() const noexcept
488
- {
489
- assert(is_string());
490
- return storage.str.get();
491
- }
492
- JsObject *as_object() const noexcept
493
- {
494
- assert(is_object());
495
- return storage.object.get();
496
- }
497
- JsArray *as_array() const noexcept
498
- {
499
- assert(is_array());
500
- return storage.array.get();
501
- }
502
- JsFunction *as_function(const std::optional<std::string> &expression = std::nullopt) const
503
- {
504
- if (is_function())
505
- return storage.function.get();
506
- throw RuntimeError::make_error(expression.value_or(to_std_string()) + " is not a function", "TypeError");
507
- }
508
- JsSymbol *as_symbol() const noexcept
509
- {
510
- assert(is_symbol());
511
- return storage.symbol.get();
512
- }
513
- std::shared_ptr<JsIterator<AnyValue>> as_iterator() const
514
- {
515
- assert(is_iterator());
516
- return storage.iterator; // Returns the shared_ptr, incrementing ref count
517
- }
518
- DataDescriptor *as_data_descriptor() const noexcept
519
- {
520
- assert(is_data_descriptor());
521
- return storage.data_desc.get();
522
- }
523
- AccessorDescriptor *as_accessor_descriptor() const noexcept
524
- {
525
- assert(is_accessor_descriptor());
526
- return storage.accessor_desc.get();
527
- }
528
-
529
- // --- PROPERTY ACCESS OPERATORS
530
- AnyValue get_own_property(const std::string &key) const
531
- {
532
- switch (storage.type)
533
- {
534
- case JsType::Object:
535
- return storage.object->get_property(key);
536
- case JsType::Array:
537
- return storage.array->get_property(key);
538
- case JsType::Function:
539
- return storage.function->get_property(key);
540
- case JsType::Iterator:
541
- return storage.iterator->get_property(key);
542
- case JsType::Symbol:
543
- return storage.symbol->get_property(key);
544
- case JsType::String:
545
- return storage.str->get_property(key);
546
- case JsType::Undefined:
547
- throw RuntimeError::make_error("Cannot read properties of undefined (reading '" + key + "')", "TypeError");
548
- case JsType::Null:
549
- throw RuntimeError::make_error("Cannot read properties of null (reading '" + key + "')", "TypeError");
550
- default:
551
- return AnyValue::make_undefined();
552
- }
553
- }
554
- AnyValue get_own_property(uint32_t idx) const noexcept
555
- {
556
- switch (storage.type)
557
- {
558
- case JsType::Array:
559
- return storage.array->get_property(idx);
560
- case JsType::String:
561
- return storage.str->get_property(idx);
562
- default:
563
- return get_own_property(std::to_string(idx));
564
- }
565
- }
566
- AnyValue get_own_property(const AnyValue &key) const noexcept
567
- {
568
- if (key.storage.type == JsType::Number && storage.type == JsType::Array)
569
- return storage.array->get_property(key.storage.number);
570
- if (key.storage.type == JsType::Number && storage.type == JsType::String)
571
- return storage.str->get_property(key.storage.number);
572
-
573
- // If the key is a Symbol, use its internal key string
574
- if (key.storage.type == JsType::Symbol)
575
- return get_own_property(key.storage.symbol->key);
576
-
577
- return get_own_property(key.to_std_string());
578
- }
579
- // for setting values
580
- AnyValue set_own_property(const std::string &key, const AnyValue &value) const
581
- {
582
- switch (storage.type)
583
- {
584
- case JsType::Object:
585
- return storage.object->set_property(key, value);
586
- case JsType::Array:
587
- return storage.array->set_property(key, value);
588
- case JsType::Function:
589
- return storage.function->set_property(key, value);
590
- case JsType::Undefined:
591
- throw RuntimeError::make_error("Cannot set properties of undefined (setting '" + key + "')", "TypeError");
592
- case JsType::Null:
593
- throw RuntimeError::make_error("Cannot set properties of null (setting '" + key + "')", "TypeError");
594
- default:
595
- return value;
596
- }
597
- }
598
- AnyValue set_own_property(uint32_t idx, const AnyValue &value) const
599
- {
600
- if (storage.type == JsType::Array)
601
- {
602
- return storage.array->set_property(idx, value);
603
- }
604
- return set_own_property(std::to_string(idx), value);
605
- }
606
- AnyValue set_own_property(const AnyValue &key, const AnyValue &value) const
607
- {
608
- if (key.storage.type == JsType::Number && storage.type == JsType::Array)
609
- {
610
- return storage.array->set_property(key.storage.number, value);
611
- }
612
-
613
- // If the key is a Symbol, use its internal key string
614
- if (key.storage.type == JsType::Symbol)
615
- return set_own_property(key.storage.symbol->key, value);
616
-
617
- return set_own_property(key.to_std_string(), value);
618
- }
619
-
620
- // --- HELPERS
621
- const bool is_truthy() const noexcept;
622
-
623
- const bool is_strictly_equal_to(const AnyValue &other) const noexcept;
624
- const bool is_equal_to(const AnyValue &other) const noexcept;
625
-
626
- const AnyValue is_strictly_equal_to_primitive(const AnyValue &other) const noexcept;
627
- const AnyValue is_equal_to_primitive(const AnyValue &other) const noexcept;
628
-
629
- const AnyValue not_strictly_equal_to_primitive(const AnyValue &other) const noexcept;
630
- const AnyValue not_equal_to_primitive(const AnyValue &other) const noexcept;
631
-
632
- const std::string to_std_string() const noexcept;
633
- };
634
- }
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
+ #include "values/object.hpp"
24
+ #include "values/array.hpp"
25
+ #include "values/function.hpp"
26
+ #include "values/iterator.hpp"
27
+ #include "values/promise.hpp"
28
+ #include "values/symbol.hpp"
29
+ #include "values/string.hpp"
30
+ #include "exception.hpp"
31
+ #include "values/descriptors.hpp"
32
+ #include "utils/well_known_symbols.hpp"
33
+
34
+ namespace jspp
35
+ {
36
+ enum class JsType : uint8_t
37
+ {
38
+ Undefined = 0,
39
+ Null = 1,
40
+ Uninitialized = 2,
41
+ Boolean = 3,
42
+ Number = 4,
43
+ String = 5,
44
+ Object = 6,
45
+ Array = 7,
46
+ Function = 8,
47
+ Iterator = 9,
48
+ Symbol = 10,
49
+ Promise = 11,
50
+ DataDescriptor = 12,
51
+ AccessorDescriptor = 13,
52
+ };
53
+
54
+ // Tagged storage with a union for payload
55
+ struct TaggedValue
56
+ {
57
+ JsType type;
58
+ union
59
+ {
60
+ JsUndefined undefined;
61
+ JsNull null;
62
+ JsUninitialized uninitialized;
63
+ bool boolean;
64
+ double number;
65
+ std::shared_ptr<JsString> str;
66
+ std::shared_ptr<JsObject> object;
67
+ std::shared_ptr<JsArray> array;
68
+ std::shared_ptr<JsFunction> function;
69
+ std::shared_ptr<JsIterator<AnyValue>> iterator;
70
+ std::shared_ptr<JsSymbol> symbol;
71
+ std::shared_ptr<JsPromise> promise;
72
+ std::shared_ptr<DataDescriptor> data_desc;
73
+ std::shared_ptr<AccessorDescriptor> accessor_desc;
74
+ };
75
+
76
+ TaggedValue() noexcept : type(JsType::Undefined), undefined{} {}
77
+ ~TaggedValue() {}
78
+ };
79
+
80
+ class AnyValue
81
+ {
82
+ private:
83
+ TaggedValue storage;
84
+
85
+ void destroy_value() noexcept
86
+ {
87
+ switch (storage.type)
88
+ {
89
+ case JsType::String:
90
+ storage.str.~shared_ptr();
91
+ break;
92
+ case JsType::Object:
93
+ storage.object.~shared_ptr();
94
+ break;
95
+ case JsType::Array:
96
+ storage.array.~shared_ptr();
97
+ break;
98
+ case JsType::Function:
99
+ storage.function.~shared_ptr();
100
+ break;
101
+ case JsType::Iterator:
102
+ storage.iterator.~shared_ptr();
103
+ break;
104
+ case JsType::Symbol:
105
+ storage.symbol.~shared_ptr();
106
+ break;
107
+ case JsType::Promise:
108
+ storage.promise.~shared_ptr();
109
+ break;
110
+ case JsType::DataDescriptor:
111
+ storage.data_desc.~shared_ptr();
112
+ break;
113
+ case JsType::AccessorDescriptor:
114
+ storage.accessor_desc.~shared_ptr();
115
+ break;
116
+ default:
117
+ break;
118
+ }
119
+ }
120
+
121
+ void reset_to_undefined() noexcept
122
+ {
123
+ destroy_value();
124
+ storage.type = JsType::Undefined;
125
+ storage.undefined = JsUndefined{};
126
+ }
127
+
128
+ void move_from(AnyValue &other) noexcept
129
+ {
130
+ storage.type = other.storage.type;
131
+ switch (other.storage.type)
132
+ {
133
+ case JsType::Undefined:
134
+ storage.undefined = JsUndefined{};
135
+ break;
136
+ case JsType::Null:
137
+ storage.null = JsNull{};
138
+ break;
139
+ case JsType::Uninitialized:
140
+ storage.uninitialized = JsUninitialized{};
141
+ break;
142
+ case JsType::Boolean:
143
+ storage.boolean = other.storage.boolean;
144
+ break;
145
+ case JsType::Number:
146
+ storage.number = other.storage.number;
147
+ break;
148
+ case JsType::String:
149
+ new (&storage.str) std::shared_ptr<JsString>(std::move(other.storage.str));
150
+ break;
151
+ case JsType::Object:
152
+ new (&storage.object) std::shared_ptr<JsObject>(std::move(other.storage.object));
153
+ break;
154
+ case JsType::Array:
155
+ new (&storage.array) std::shared_ptr<JsArray>(std::move(other.storage.array));
156
+ break;
157
+ case JsType::Function:
158
+ new (&storage.function) std::shared_ptr<JsFunction>(std::move(other.storage.function));
159
+ break;
160
+ case JsType::Iterator:
161
+ new (&storage.iterator) std::shared_ptr<JsIterator<AnyValue>>(std::move(other.storage.iterator));
162
+ break;
163
+ case JsType::Symbol:
164
+ new (&storage.symbol) std::shared_ptr<JsSymbol>(std::move(other.storage.symbol));
165
+ break;
166
+ case JsType::Promise:
167
+ new (&storage.promise) std::shared_ptr<JsPromise>(std::move(other.storage.promise));
168
+ break;
169
+ case JsType::DataDescriptor:
170
+ new (&storage.data_desc) std::shared_ptr<DataDescriptor>(std::move(other.storage.data_desc));
171
+ break;
172
+ case JsType::AccessorDescriptor:
173
+ new (&storage.accessor_desc) std::shared_ptr<AccessorDescriptor>(std::move(other.storage.accessor_desc));
174
+ break;
175
+ }
176
+ }
177
+
178
+ void copy_from(const AnyValue &other)
179
+ {
180
+ storage.type = other.storage.type;
181
+ switch (other.storage.type)
182
+ {
183
+ case JsType::Undefined:
184
+ storage.undefined = JsUndefined{};
185
+ break;
186
+ case JsType::Null:
187
+ storage.null = JsNull{};
188
+ break;
189
+ case JsType::Uninitialized:
190
+ storage.uninitialized = JsUninitialized{};
191
+ break;
192
+ case JsType::Boolean:
193
+ storage.boolean = other.storage.boolean;
194
+ break;
195
+ case JsType::Number:
196
+ storage.number = other.storage.number;
197
+ break;
198
+ case JsType::String:
199
+ new (&storage.str) std::shared_ptr<JsString>(std::make_shared<JsString>(*other.storage.str));
200
+ break;
201
+ case JsType::Object:
202
+ new (&storage.object) std::shared_ptr<JsObject>(other.storage.object); // shallow copy
203
+ break;
204
+ case JsType::Array:
205
+ new (&storage.array) std::shared_ptr<JsArray>(other.storage.array); // shallow copy
206
+ break;
207
+ case JsType::Function:
208
+ new (&storage.function) std::shared_ptr<JsFunction>(other.storage.function); // shallow copy
209
+ break;
210
+ case JsType::Iterator:
211
+ new (&storage.iterator) std::shared_ptr<JsIterator<AnyValue>>(other.storage.iterator); // shallow copy
212
+ break;
213
+ case JsType::Symbol:
214
+ new (&storage.symbol) std::shared_ptr<JsSymbol>(other.storage.symbol); // shallow copy (shared)
215
+ break;
216
+ case JsType::Promise:
217
+ new (&storage.promise) std::shared_ptr<JsPromise>(other.storage.promise); // shallow copy
218
+ break;
219
+ case JsType::DataDescriptor:
220
+ new (&storage.data_desc) std::shared_ptr<DataDescriptor>(other.storage.data_desc); // shallow copy
221
+ break;
222
+ case JsType::AccessorDescriptor:
223
+ new (&storage.accessor_desc) std::shared_ptr<AccessorDescriptor>(other.storage.accessor_desc); // shallow copy
224
+ break;
225
+ }
226
+ }
227
+
228
+ public:
229
+ // default ctor (Undefined)
230
+ AnyValue() noexcept
231
+ {
232
+ storage.type = JsType::Undefined;
233
+ storage.undefined = JsUndefined{};
234
+ }
235
+
236
+ // 1. Destructor
237
+ ~AnyValue() noexcept
238
+ {
239
+ destroy_value();
240
+ }
241
+
242
+ // 2. Copy Constructor (deep copy)
243
+ AnyValue(const AnyValue &other)
244
+ {
245
+ copy_from(other);
246
+ }
247
+
248
+ // 3. Copy Assignment Operator
249
+ AnyValue &operator=(const AnyValue &other)
250
+ {
251
+ if (this != &other)
252
+ {
253
+ destroy_value();
254
+ copy_from(other);
255
+ }
256
+ return *this;
257
+ }
258
+
259
+ // 4. Move Constructor
260
+ AnyValue(AnyValue &&other) noexcept
261
+ {
262
+ storage.type = JsType::Undefined;
263
+ storage.undefined = JsUndefined{};
264
+ move_from(other);
265
+ other.reset_to_undefined();
266
+ }
267
+
268
+ // 5. Move Assignment Operator
269
+ AnyValue &operator=(AnyValue &&other) noexcept
270
+ {
271
+ if (this != &other)
272
+ {
273
+ destroy_value();
274
+ move_from(other);
275
+ other.reset_to_undefined();
276
+ }
277
+ return *this;
278
+ }
279
+
280
+ friend void swap(AnyValue &a, AnyValue &b) noexcept
281
+ {
282
+ AnyValue tmp(std::move(a));
283
+ a = std::move(b);
284
+ b = std::move(tmp);
285
+ }
286
+
287
+ // factories -------------------------------------------------------
288
+ static AnyValue make_number(double d) noexcept
289
+ {
290
+ AnyValue v;
291
+ v.storage.type = JsType::Number;
292
+ v.storage.number = d;
293
+ return v;
294
+ }
295
+ static AnyValue make_nan() noexcept
296
+ {
297
+ AnyValue v;
298
+ v.storage.type = JsType::Number;
299
+ v.storage.number = std::numeric_limits<double>::quiet_NaN();
300
+ return v;
301
+ }
302
+ static AnyValue make_uninitialized() noexcept
303
+ {
304
+ AnyValue v;
305
+ v.storage.type = JsType::Uninitialized;
306
+ v.storage.uninitialized = JsUninitialized{};
307
+ return v;
308
+ }
309
+ static AnyValue make_undefined() noexcept
310
+ {
311
+ AnyValue v;
312
+ v.storage.type = JsType::Undefined;
313
+ v.storage.undefined = JsUndefined{};
314
+ return v;
315
+ }
316
+ static AnyValue make_null() noexcept
317
+ {
318
+ AnyValue v;
319
+ v.storage.type = JsType::Null;
320
+ v.storage.null = JsNull{};
321
+ return v;
322
+ }
323
+ static AnyValue make_boolean(bool b) noexcept
324
+ {
325
+ AnyValue v;
326
+ v.storage.type = JsType::Boolean;
327
+ v.storage.boolean = b;
328
+ return v;
329
+ }
330
+ static AnyValue make_string(const std::string &raw_s) noexcept
331
+ {
332
+ AnyValue v;
333
+ v.storage.type = JsType::String;
334
+ new (&v.storage.str) std::shared_ptr<JsString>(std::make_shared<JsString>(raw_s));
335
+ return v;
336
+ }
337
+ static AnyValue make_object(const std::map<std::string, AnyValue> &props) noexcept
338
+ {
339
+ AnyValue v;
340
+ v.storage.type = JsType::Object;
341
+ new (&v.storage.object) std::shared_ptr<JsObject>(std::make_shared<JsObject>(props));
342
+ return v;
343
+ }
344
+ static AnyValue make_object_with_proto(const std::map<std::string, AnyValue> &props, const AnyValue &proto) noexcept
345
+ {
346
+ AnyValue v;
347
+ v.storage.type = JsType::Object;
348
+ auto protoPtr = std::make_shared<AnyValue>(proto);
349
+ new (&v.storage.object) std::shared_ptr<JsObject>(std::make_shared<JsObject>(props, protoPtr));
350
+ return v;
351
+ }
352
+ static AnyValue make_array(const std::vector<std::optional<AnyValue>> &dense) noexcept
353
+ {
354
+ AnyValue v;
355
+ v.storage.type = JsType::Array;
356
+ new (&v.storage.array) std::shared_ptr<JsArray>(std::make_shared<JsArray>(dense));
357
+ return v;
358
+ }
359
+ static AnyValue make_array(std::vector<std::optional<AnyValue>> &&dense) noexcept
360
+ {
361
+ AnyValue v;
362
+ v.storage.type = JsType::Array;
363
+ new (&v.storage.array) std::shared_ptr<JsArray>(std::make_shared<JsArray>(std::move(dense)));
364
+ return v;
365
+ }
366
+ static AnyValue make_function(const JsFunctionCallable &call, const std::string &name) noexcept
367
+ {
368
+ AnyValue v;
369
+ v.storage.type = JsType::Function;
370
+ new (&v.storage.function) std::shared_ptr<JsFunction>(std::make_shared<JsFunction>(call, name));
371
+
372
+ auto proto = make_object({});
373
+ proto.set_own_property("constructor", AnyValue::make_data_descriptor(v, true, false, false));
374
+ v.set_own_property("prototype", AnyValue::make_data_descriptor(proto, false, false, false));
375
+
376
+ return v;
377
+ }
378
+ static AnyValue make_class(const JsFunctionCallable &call, const std::string &name) noexcept
379
+ {
380
+ AnyValue v;
381
+ v.storage.type = JsType::Function;
382
+ // use Constructor A with is_cls = true
383
+ new (&v.storage.function) std::shared_ptr<JsFunction>(std::make_shared<JsFunction>(call, name, std::unordered_map<std::string, AnyValue>{}, true));
384
+
385
+ auto proto = make_object({});
386
+ proto.set_own_property("constructor", AnyValue::make_data_descriptor(v, true, false, false));
387
+ v.set_own_property("prototype", AnyValue::make_data_descriptor(proto, false, false, false));
388
+
389
+ return v;
390
+ }
391
+ static AnyValue make_generator(const JsFunctionCallable &call, const std::string &name) noexcept
392
+ {
393
+ AnyValue v;
394
+ v.storage.type = JsType::Function;
395
+ // use Constructor B with is_gen = true
396
+ new (&v.storage.function) std::shared_ptr<JsFunction>(std::make_shared<JsFunction>(call, true, name));
397
+
398
+ auto proto = make_object({});
399
+ proto.set_own_property("constructor", AnyValue::make_data_descriptor(v, true, false, false));
400
+ v.set_own_property("prototype", AnyValue::make_data_descriptor(proto, false, false, false));
401
+
402
+ return v;
403
+ }
404
+ static AnyValue make_async_function(const JsFunctionCallable &call, const std::string &name) noexcept
405
+ {
406
+ AnyValue v;
407
+ v.storage.type = JsType::Function;
408
+ // use Constructor C with is_async_func = true
409
+ new (&v.storage.function) std::shared_ptr<JsFunction>(std::make_shared<JsFunction>(call, false, true, name));
410
+
411
+ auto proto = make_object({});
412
+ proto.set_own_property("constructor", AnyValue::make_data_descriptor(v, true, false, false));
413
+ v.set_own_property("prototype", AnyValue::make_data_descriptor(proto, false, false, false));
414
+
415
+ return v;
416
+ }
417
+ static AnyValue make_symbol(const std::string &description = "") noexcept
418
+ {
419
+ AnyValue v;
420
+ v.storage.type = JsType::Symbol;
421
+ new (&v.storage.symbol) std::shared_ptr<JsSymbol>(std::make_shared<JsSymbol>(description));
422
+ return v;
423
+ }
424
+ static AnyValue make_promise(const JsPromise &promise) noexcept
425
+ {
426
+ AnyValue v;
427
+ v.storage.type = JsType::Promise;
428
+ new (&v.storage.promise) std::shared_ptr<JsPromise>(std::make_shared<JsPromise>(promise));
429
+ return v;
430
+ }
431
+ static AnyValue make_data_descriptor(const AnyValue &value, bool writable, bool enumerable, bool configurable) noexcept
432
+ {
433
+ AnyValue v;
434
+ v.storage.type = JsType::DataDescriptor;
435
+ new (&v.storage.data_desc) std::shared_ptr<DataDescriptor>(std::make_shared<DataDescriptor>(std::make_shared<AnyValue>(value), writable, enumerable, configurable));
436
+ return v;
437
+ }
438
+ static AnyValue make_accessor_descriptor(const std::optional<std::function<AnyValue(const AnyValue &, const std::vector<AnyValue> &)>> &get,
439
+ const std::optional<std::function<AnyValue(const AnyValue &, const std::vector<AnyValue> &)>> &set,
440
+ bool enumerable,
441
+ bool configurable) noexcept
442
+ {
443
+ AnyValue v;
444
+ v.storage.type = JsType::AccessorDescriptor;
445
+ new (&v.storage.accessor_desc) std::shared_ptr<AccessorDescriptor>(std::make_shared<AccessorDescriptor>(get, set, enumerable, configurable));
446
+ return v;
447
+ }
448
+
449
+ static AnyValue from_symbol(std::shared_ptr<JsSymbol> sym) noexcept
450
+ {
451
+ AnyValue v;
452
+ v.storage.type = JsType::Symbol;
453
+ new (&v.storage.symbol) std::shared_ptr<JsSymbol>(std::move(sym));
454
+ return v;
455
+ }
456
+ static AnyValue from_string(std::shared_ptr<JsString> str) noexcept
457
+ {
458
+ AnyValue v;
459
+ v.storage.type = JsType::String;
460
+ new (&v.storage.str) std::shared_ptr<JsString>(std::move(str));
461
+ return v;
462
+ }
463
+ static AnyValue from_iterator(JsIterator<AnyValue> &&iterator) noexcept
464
+ {
465
+ AnyValue v;
466
+ v.storage.type = JsType::Iterator;
467
+ new (&v.storage.iterator) std::shared_ptr<JsIterator<AnyValue>>(std::make_shared<JsIterator<AnyValue>>(std::move(iterator)));
468
+ return v;
469
+ }
470
+ static AnyValue from_iterator_ref(JsIterator<AnyValue> *iterator) noexcept
471
+ {
472
+ AnyValue v;
473
+ v.storage.type = JsType::Iterator;
474
+ new (&v.storage.iterator) std::shared_ptr<JsIterator<AnyValue>>(iterator, [](JsIterator<AnyValue> *) {});
475
+ return v;
476
+ }
477
+
478
+ // PROPERTY RESOLUTION HELPERS ---------------------------------------
479
+ static AnyValue resolve_property_for_read(const AnyValue &val, const AnyValue &thisVal, const std::string &propName) noexcept
480
+ {
481
+ switch (val.storage.type)
482
+ {
483
+ case JsType::DataDescriptor:
484
+ {
485
+ return *(val.storage.data_desc->value);
486
+ }
487
+ case JsType::AccessorDescriptor:
488
+ {
489
+ if (val.storage.accessor_desc->get.has_value())
490
+ return val.storage.accessor_desc->get.value()(thisVal, {});
491
+ else
492
+ {
493
+ static AnyValue undefined = AnyValue{};
494
+ return undefined;
495
+ }
496
+ }
497
+ default:
498
+ {
499
+ return val;
500
+ }
501
+ }
502
+ }
503
+ static AnyValue resolve_property_for_write(AnyValue &val, const AnyValue &thisVal, const AnyValue &new_val, const std::string &propName)
504
+ {
505
+ switch (val.storage.type)
506
+ {
507
+ case JsType::DataDescriptor:
508
+ {
509
+ if (val.storage.data_desc->writable)
510
+ {
511
+ *(val.storage.data_desc->value) = new_val;
512
+ return new_val;
513
+ }
514
+ else
515
+ {
516
+ throw Exception::make_exception("Cannot assign to read only property '" + propName + "' of object '#<Object>'", "TypeError");
517
+ }
518
+ }
519
+ case JsType::AccessorDescriptor:
520
+ {
521
+ if (val.storage.accessor_desc->set.has_value())
522
+ {
523
+ val.storage.accessor_desc->set.value()(thisVal, {new_val});
524
+ return new_val;
525
+ }
526
+ else
527
+ {
528
+ throw Exception::make_exception("Cannot set property of #<Object> which has only a getter", "TypeError");
529
+ }
530
+ }
531
+ default:
532
+ {
533
+ val = new_val;
534
+ return new_val;
535
+ }
536
+ }
537
+ }
538
+
539
+ // TYPE CHECKERS AND ACCESSORS ---------------------------------------
540
+ JsType get_type() const noexcept { return storage.type; }
541
+ bool is_number() const noexcept { return storage.type == JsType::Number; }
542
+ bool is_string() const noexcept { return storage.type == JsType::String; }
543
+ bool is_object() const noexcept { return storage.type == JsType::Object; }
544
+ bool is_array() const noexcept { return storage.type == JsType::Array; }
545
+ bool is_function() const noexcept { return storage.type == JsType::Function; }
546
+ bool is_iterator() const noexcept { return storage.type == JsType::Iterator; }
547
+ bool is_boolean() const noexcept { return storage.type == JsType::Boolean; }
548
+ bool is_symbol() const noexcept { return storage.type == JsType::Symbol; }
549
+ bool is_promise() const noexcept { return storage.type == JsType::Promise; }
550
+ bool is_null() const noexcept { return storage.type == JsType::Null; }
551
+ bool is_undefined() const noexcept { return storage.type == JsType::Undefined; }
552
+ bool is_uninitialized() const noexcept { return storage.type == JsType::Uninitialized; }
553
+ bool is_data_descriptor() const noexcept { return storage.type == JsType::DataDescriptor; }
554
+ bool is_accessor_descriptor() const noexcept { return storage.type == JsType::AccessorDescriptor; }
555
+ bool is_generator() const noexcept { return storage.type == JsType::Function && storage.function->is_generator; }
556
+
557
+ // --- TYPE CASTERS
558
+ double as_double() const noexcept
559
+ {
560
+ assert(is_number());
561
+ return storage.number;
562
+ }
563
+ bool as_boolean() const noexcept
564
+ {
565
+ assert(is_boolean());
566
+ return storage.boolean;
567
+ }
568
+ JsString *as_string() const noexcept
569
+ {
570
+ assert(is_string());
571
+ return storage.str.get();
572
+ }
573
+ JsObject *as_object() const noexcept
574
+ {
575
+ assert(is_object());
576
+ return storage.object.get();
577
+ }
578
+ JsArray *as_array() const noexcept
579
+ {
580
+ assert(is_array());
581
+ return storage.array.get();
582
+ }
583
+ JsFunction *as_function(const std::optional<std::string> &expression = std::nullopt) const
584
+ {
585
+ if (is_function())
586
+ return storage.function.get();
587
+ throw Exception::make_exception(expression.value_or(to_std_string()) + " is not a function", "TypeError");
588
+ }
589
+ JsSymbol *as_symbol() const noexcept
590
+ {
591
+ assert(is_symbol());
592
+ return storage.symbol.get();
593
+ }
594
+ JsPromise *as_promise() const noexcept
595
+ {
596
+ assert(is_promise());
597
+ return storage.promise.get();
598
+ }
599
+ std::shared_ptr<JsIterator<AnyValue>> as_iterator() const
600
+ {
601
+ assert(is_iterator());
602
+ return storage.iterator; // Returns the shared_ptr, incrementing ref count
603
+ }
604
+ DataDescriptor *as_data_descriptor() const noexcept
605
+ {
606
+ assert(is_data_descriptor());
607
+ return storage.data_desc.get();
608
+ }
609
+ AccessorDescriptor *as_accessor_descriptor() const noexcept
610
+ {
611
+ assert(is_accessor_descriptor());
612
+ return storage.accessor_desc.get();
613
+ }
614
+
615
+ // --- CO_AWAIT Operator ---
616
+ auto operator co_await() const;
617
+
618
+ // --- PROPERTY ACCESS OPERATORS
619
+ AnyValue get_own_property(const std::string &key) const;
620
+ AnyValue get_own_property(uint32_t idx) const noexcept;
621
+ AnyValue get_own_property(const AnyValue &key) const noexcept;
622
+ // for getting values with a specific receiver (used in inheritance chains)
623
+ AnyValue get_property_with_receiver(const std::string &key, const AnyValue &receiver) const;
624
+ // for setting values
625
+ AnyValue set_own_property(const std::string &key, const AnyValue &value) const;
626
+ AnyValue set_own_property(uint32_t idx, const AnyValue &value) const;
627
+ AnyValue set_own_property(const AnyValue &key, const AnyValue &value) const;
628
+
629
+ // --- DEFINERS (Object.defineProperty semantics)
630
+ void define_data_property(const std::string &key, const AnyValue &value);
631
+ void define_data_property(const AnyValue &key, const AnyValue &value);
632
+ void define_data_property(const std::string &key, const AnyValue &value, bool writable, bool enumerable, bool configurable);
633
+ void define_getter(const std::string &key, const AnyValue &getter);
634
+ void define_getter(const AnyValue &key, const AnyValue &getter);
635
+ void define_setter(const std::string &key, const AnyValue &setter);
636
+ void define_setter(const AnyValue &key, const AnyValue &setter);
637
+
638
+ // --- HELPERS
639
+ const bool is_truthy() const noexcept;
640
+ const bool is_strictly_equal_to_primitive(const AnyValue &other) const noexcept;
641
+ const bool is_equal_to_primitive(const AnyValue &other) const noexcept;
642
+
643
+ const AnyValue is_strictly_equal_to(const AnyValue &other) const noexcept;
644
+ const AnyValue is_equal_to(const AnyValue &other) const noexcept;
645
+ const AnyValue not_strictly_equal_to(const AnyValue &other) const noexcept;
646
+ const AnyValue not_equal_to(const AnyValue &other) const noexcept;
647
+
648
+ const AnyValue construct(const std::vector<AnyValue> &args) const;
649
+ void set_prototype(const AnyValue &proto);
650
+ const std::string to_std_string() const noexcept;
651
+ };
652
+
653
+ // Inline implementation of operator co_await
654
+ inline auto AnyValue::operator co_await() const
655
+ {
656
+ return AnyValueAwaiter{*this};
657
+ }
658
+ }