@ugo-studio/jspp 0.1.4 → 0.1.5

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