@ugo-studio/jspp 0.3.0 → 0.3.2

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 (127) hide show
  1. package/LICENSE +25 -25
  2. package/README.md +20 -12
  3. package/dist/cli/args.js +22 -0
  4. package/dist/cli/compiler.js +53 -0
  5. package/dist/cli/index.js +43 -107
  6. package/dist/cli/pch.js +71 -0
  7. package/dist/cli/runner.js +23 -0
  8. package/dist/cli/spinner.js +27 -11
  9. package/dist/cli/transpiler.js +20 -0
  10. package/dist/cli/utils.js +59 -0
  11. package/dist/cli/wasm.js +70 -0
  12. package/dist/index.js +17 -6
  13. package/dist/{analysis → interpreter/analysis}/scope.js +38 -3
  14. package/dist/{analysis → interpreter/analysis}/typeAnalyzer.js +563 -28
  15. package/dist/{core → interpreter/core}/codegen/class-handlers.js +1 -1
  16. package/dist/{core → interpreter/core}/codegen/control-flow-handlers.js +12 -11
  17. package/dist/{core → interpreter/core}/codegen/declaration-handlers.js +28 -9
  18. package/dist/{core → interpreter/core}/codegen/destructuring-handlers.js +9 -4
  19. package/dist/{core → interpreter/core}/codegen/expression-handlers.js +82 -88
  20. package/dist/{core → interpreter/core}/codegen/function-handlers.js +159 -46
  21. package/dist/{core → interpreter/core}/codegen/helpers.js +170 -25
  22. package/dist/interpreter/core/codegen/index.js +156 -0
  23. package/dist/{core → interpreter/core}/codegen/literal-handlers.js +9 -0
  24. package/dist/{core → interpreter/core}/codegen/statement-handlers.js +47 -7
  25. package/package.json +6 -4
  26. package/scripts/precompile-headers.ts +293 -50
  27. package/scripts/setup-compiler.ts +63 -63
  28. package/scripts/setup-emsdk.ts +114 -0
  29. package/src/prelude/any_value.cpp +888 -0
  30. package/src/prelude/any_value.hpp +29 -24
  31. package/src/prelude/{exception_helpers.hpp → exception.cpp} +53 -53
  32. package/src/prelude/exception.hpp +27 -27
  33. package/src/prelude/iterator_instantiations.hpp +10 -0
  34. package/src/prelude/{index.hpp → jspp.hpp} +13 -17
  35. package/src/prelude/library/array.cpp +191 -0
  36. package/src/prelude/library/array.hpp +5 -178
  37. package/src/prelude/library/boolean.cpp +30 -0
  38. package/src/prelude/library/boolean.hpp +14 -0
  39. package/src/prelude/library/console.cpp +125 -0
  40. package/src/prelude/library/console.hpp +9 -97
  41. package/src/prelude/library/error.cpp +100 -0
  42. package/src/prelude/library/error.hpp +8 -108
  43. package/src/prelude/library/function.cpp +69 -0
  44. package/src/prelude/library/function.hpp +6 -5
  45. package/src/prelude/library/global.cpp +98 -0
  46. package/src/prelude/library/global.hpp +12 -28
  47. package/src/prelude/library/global_usings.hpp +15 -0
  48. package/src/prelude/library/math.cpp +261 -0
  49. package/src/prelude/library/math.hpp +8 -288
  50. package/src/prelude/library/object.cpp +379 -0
  51. package/src/prelude/library/object.hpp +5 -267
  52. package/src/prelude/library/performance.cpp +21 -0
  53. package/src/prelude/library/performance.hpp +5 -20
  54. package/src/prelude/library/process.cpp +38 -0
  55. package/src/prelude/library/process.hpp +3 -31
  56. package/src/prelude/library/promise.cpp +131 -0
  57. package/src/prelude/library/promise.hpp +5 -116
  58. package/src/prelude/library/symbol.cpp +56 -0
  59. package/src/prelude/library/symbol.hpp +5 -46
  60. package/src/prelude/library/timer.cpp +88 -0
  61. package/src/prelude/library/timer.hpp +11 -87
  62. package/src/prelude/runtime.cpp +19 -0
  63. package/src/prelude/types.hpp +26 -20
  64. package/src/prelude/utils/access.hpp +123 -32
  65. package/src/prelude/utils/assignment_operators.hpp +119 -99
  66. package/src/prelude/utils/log_any_value/array.hpp +61 -40
  67. package/src/prelude/utils/log_any_value/function.hpp +39 -39
  68. package/src/prelude/utils/log_any_value/log_any_value.hpp +1 -1
  69. package/src/prelude/utils/log_any_value/object.hpp +60 -3
  70. package/src/prelude/utils/log_any_value/primitives.hpp +1 -1
  71. package/src/prelude/utils/operators.hpp +109 -94
  72. package/src/prelude/utils/operators_native.hpp +349 -0
  73. package/src/prelude/utils/well_known_symbols.hpp +24 -24
  74. package/src/prelude/values/array.cpp +1399 -0
  75. package/src/prelude/values/array.hpp +4 -0
  76. package/src/prelude/values/async_iterator.cpp +251 -0
  77. package/src/prelude/values/async_iterator.hpp +60 -32
  78. package/src/prelude/values/boolean.cpp +64 -0
  79. package/src/prelude/values/function.cpp +262 -0
  80. package/src/prelude/values/function.hpp +10 -30
  81. package/src/prelude/values/iterator.cpp +309 -0
  82. package/src/prelude/values/iterator.hpp +33 -64
  83. package/src/prelude/values/number.cpp +221 -0
  84. package/src/prelude/values/object.cpp +200 -0
  85. package/src/prelude/values/object.hpp +4 -0
  86. package/src/prelude/values/promise.cpp +479 -0
  87. package/src/prelude/values/promise.hpp +9 -2
  88. package/src/prelude/values/prototypes/array.hpp +46 -1348
  89. package/src/prelude/values/prototypes/async_iterator.hpp +19 -61
  90. package/src/prelude/values/prototypes/boolean.hpp +24 -0
  91. package/src/prelude/values/prototypes/function.hpp +7 -46
  92. package/src/prelude/values/prototypes/iterator.hpp +15 -191
  93. package/src/prelude/values/prototypes/number.hpp +30 -210
  94. package/src/prelude/values/prototypes/object.hpp +7 -23
  95. package/src/prelude/values/prototypes/promise.hpp +8 -186
  96. package/src/prelude/values/prototypes/string.hpp +28 -553
  97. package/src/prelude/values/prototypes/symbol.hpp +9 -70
  98. package/src/prelude/values/shape.hpp +52 -52
  99. package/src/prelude/values/string.cpp +485 -0
  100. package/src/prelude/values/symbol.cpp +89 -0
  101. package/src/prelude/values/symbol.hpp +101 -101
  102. package/dist/cli/file-utils.js +0 -20
  103. package/dist/cli-utils/args.js +0 -59
  104. package/dist/cli-utils/colors.js +0 -9
  105. package/dist/cli-utils/file-utils.js +0 -20
  106. package/dist/cli-utils/spinner.js +0 -55
  107. package/dist/cli.js +0 -153
  108. package/dist/core/codegen/index.js +0 -86
  109. package/src/prelude/any_value_access.hpp +0 -170
  110. package/src/prelude/any_value_defines.hpp +0 -190
  111. package/src/prelude/any_value_helpers.hpp +0 -374
  112. package/src/prelude/utils/operators_primitive.hpp +0 -337
  113. package/src/prelude/values/helpers/array.hpp +0 -199
  114. package/src/prelude/values/helpers/async_iterator.hpp +0 -275
  115. package/src/prelude/values/helpers/function.hpp +0 -109
  116. package/src/prelude/values/helpers/iterator.hpp +0 -145
  117. package/src/prelude/values/helpers/object.hpp +0 -104
  118. package/src/prelude/values/helpers/promise.hpp +0 -254
  119. package/src/prelude/values/helpers/string.hpp +0 -37
  120. package/src/prelude/values/helpers/symbol.hpp +0 -21
  121. /package/dist/{ast → interpreter/ast}/symbols.js +0 -0
  122. /package/dist/{ast → interpreter/ast}/types.js +0 -0
  123. /package/dist/{core → interpreter/core}/codegen/visitor.js +0 -0
  124. /package/dist/{core → interpreter/core}/constants.js +0 -0
  125. /package/dist/{core → interpreter/core}/error.js +0 -0
  126. /package/dist/{core → interpreter/core}/parser.js +0 -0
  127. /package/dist/{core → interpreter/core}/traverser.js +0 -0
@@ -0,0 +1,888 @@
1
+ #include "jspp.hpp"
2
+ #include "any_value.hpp"
3
+ #include "values/iterator.hpp"
4
+ #include "values/async_iterator.hpp"
5
+ #include "values/string.hpp"
6
+ #include "values/object.hpp"
7
+ #include "values/array.hpp"
8
+ #include "values/function.hpp"
9
+ #include "values/promise.hpp"
10
+ #include "values/symbol.hpp"
11
+ #include "values/descriptors.hpp"
12
+ #include "exception.hpp"
13
+
14
+ namespace jspp
15
+ {
16
+
17
+ // --- AnyValue methods that were in any_value_helpers.hpp ---
18
+
19
+ bool AnyValue::operator==(const AnyValue &other) const noexcept
20
+ {
21
+ return storage == other.storage;
22
+ }
23
+ bool AnyValue::operator==(const std::string &other) const noexcept
24
+ {
25
+ if (!is_string())
26
+ return false;
27
+ return as_string()->value == other;
28
+ }
29
+ bool AnyValue::operator<(const AnyValue &other) const noexcept
30
+ {
31
+ return storage < other.storage;
32
+ }
33
+
34
+ JsString *AnyValue::as_string() const noexcept { return static_cast<JsString *>(get_ptr()); }
35
+ JsObject *AnyValue::as_object() const noexcept { return static_cast<JsObject *>(get_ptr()); }
36
+ JsArray *AnyValue::as_array() const noexcept { return static_cast<JsArray *>(get_ptr()); }
37
+ JsFunction *AnyValue::as_function() const noexcept { return static_cast<JsFunction *>(get_ptr()); }
38
+ JsSymbol *AnyValue::as_symbol() const noexcept { return static_cast<JsSymbol *>(get_ptr()); }
39
+ JsPromise *AnyValue::as_promise() const noexcept { return static_cast<JsPromise *>(get_ptr()); }
40
+ DataDescriptor *AnyValue::as_data_descriptor() const noexcept { return static_cast<DataDescriptor *>(get_ptr()); }
41
+ AccessorDescriptor *AnyValue::as_accessor_descriptor() const noexcept { return static_cast<AccessorDescriptor *>(get_ptr()); }
42
+
43
+ bool AnyValue::is_generator() const noexcept { return is_function() && as_function()->is_generator; }
44
+
45
+ // --- AnyValue FACTORIES ---
46
+ AnyValue AnyValue::make_string(const std::string &raw_s) noexcept
47
+ {
48
+ return from_ptr(new JsString(raw_s));
49
+ }
50
+ AnyValue AnyValue::make_object(std::initializer_list<std::pair<std::string, AnyValue>> props) noexcept
51
+ {
52
+ return from_ptr(new JsObject(props, make_null()));
53
+ }
54
+ AnyValue AnyValue::make_object(const std::map<std::string, AnyValue> &props) noexcept
55
+ {
56
+ return from_ptr(new JsObject(props, make_null()));
57
+ }
58
+ AnyValue AnyValue::make_array(std::span<const AnyValue> dense) noexcept
59
+ {
60
+ std::vector<AnyValue> vec;
61
+ vec.reserve(dense.size());
62
+ for (const auto &item : dense)
63
+ vec.push_back(item);
64
+ return from_ptr(new JsArray(std::move(vec)));
65
+ }
66
+ AnyValue AnyValue::make_array(const std::vector<AnyValue> &dense) noexcept
67
+ {
68
+ return from_ptr(new JsArray(dense));
69
+ }
70
+ AnyValue AnyValue::make_array(std::vector<AnyValue> &&dense) noexcept
71
+ {
72
+ return from_ptr(new JsArray(std::move(dense)));
73
+ }
74
+ AnyValue AnyValue::make_function(const JsFunctionCallable &call, const std::optional<std::string> &name, bool is_constructor) noexcept
75
+ {
76
+ auto v = from_ptr(new JsFunction(call, name, {}, {}, false, is_constructor));
77
+ auto proto = make_object({});
78
+ proto.define_data_property("constructor", AnyValue::make_data_descriptor(v, true, false, false));
79
+ v.define_data_property("prototype", AnyValue::make_data_descriptor(proto, false, false, false));
80
+ return v;
81
+ }
82
+ AnyValue AnyValue::make_class(const JsFunctionCallable &call, const std::optional<std::string> &name) noexcept
83
+ {
84
+ auto v = from_ptr(new JsFunction(call, name, {}, {}, true));
85
+ auto proto = make_object({});
86
+ proto.define_data_property("constructor", AnyValue::make_data_descriptor(v, true, false, false));
87
+ v.define_data_property("prototype", AnyValue::make_data_descriptor(proto, false, false, false));
88
+ return v;
89
+ }
90
+ AnyValue AnyValue::make_generator(const JsFunctionCallable &call, const std::optional<std::string> &name) noexcept
91
+ {
92
+ auto v = from_ptr(new JsFunction(call, true, name, {}, {}, false));
93
+ auto proto = make_object({});
94
+ proto.define_data_property("constructor", AnyValue::make_data_descriptor(v, true, false, false));
95
+ v.define_data_property("prototype", AnyValue::make_data_descriptor(proto, false, false, false));
96
+ return v;
97
+ }
98
+ AnyValue AnyValue::make_async_function(const JsFunctionCallable &call, const std::optional<std::string> &name) noexcept
99
+ {
100
+ auto v = from_ptr(new JsFunction(call, false, true, name, {}, {}, false));
101
+ auto proto = make_object({});
102
+ proto.define_data_property("constructor", AnyValue::make_data_descriptor(v, true, false, false));
103
+ v.define_data_property("prototype", AnyValue::make_data_descriptor(proto, false, false, false));
104
+ return v;
105
+ }
106
+ AnyValue AnyValue::make_async_generator(const JsFunctionCallable &call, const std::optional<std::string> &name) noexcept
107
+ {
108
+ auto v = from_ptr(new JsFunction(call, true, true, name, {}, {}, false));
109
+ auto proto = make_object({});
110
+ proto.define_data_property("constructor", AnyValue::make_data_descriptor(v, true, false, false));
111
+ v.define_data_property("prototype", AnyValue::make_data_descriptor(proto, false, false, false));
112
+ return v;
113
+ }
114
+ AnyValue AnyValue::make_symbol(const std::string &description) noexcept
115
+ {
116
+ return from_ptr(new JsSymbol(description));
117
+ }
118
+ AnyValue AnyValue::make_promise(const JsPromise &promise) noexcept
119
+ {
120
+ auto p = new JsPromise();
121
+ *p = promise;
122
+ return from_ptr(p);
123
+ }
124
+ AnyValue AnyValue::make_data_descriptor(AnyValue value, bool writable, bool enumerable, bool configurable) noexcept
125
+ {
126
+ return from_ptr(new DataDescriptor(value, writable, enumerable, configurable));
127
+ }
128
+ AnyValue AnyValue::make_accessor_descriptor(const std::optional<std::function<AnyValue(AnyValue, std::span<const AnyValue>)>> &get,
129
+ const std::optional<std::function<AnyValue(AnyValue, std::span<const AnyValue>)>> &set,
130
+ bool enumerable,
131
+ bool configurable) noexcept
132
+ {
133
+ return from_ptr(new AccessorDescriptor(get, set, enumerable, configurable));
134
+ }
135
+
136
+ AnyValue AnyValue::from_symbol(JsSymbol *sym) noexcept
137
+ {
138
+ return from_ptr(sym);
139
+ }
140
+ AnyValue AnyValue::from_string(JsString *str) noexcept
141
+ {
142
+ return from_ptr(str);
143
+ }
144
+ AnyValue AnyValue::from_promise(JsPromise &&promise) noexcept
145
+ {
146
+ auto it = new JsPromise(std::move(promise));
147
+ return from_ptr(it);
148
+ }
149
+ AnyValue AnyValue::from_iterator(JsIterator<AnyValue> &&iterator) noexcept
150
+ {
151
+ auto it = new JsIterator<AnyValue>(std::move(iterator));
152
+ return from_ptr(it);
153
+ }
154
+ AnyValue AnyValue::from_iterator_ref(JsIterator<AnyValue> *iterator) noexcept
155
+ {
156
+ return from_ptr(iterator);
157
+ }
158
+ AnyValue AnyValue::from_async_iterator(JsAsyncIterator<AnyValue> &&iterator) noexcept
159
+ {
160
+ auto it = new JsAsyncIterator<AnyValue>(std::move(iterator));
161
+ return from_ptr(it);
162
+ }
163
+
164
+ AnyValue AnyValue::resolve_property_for_read(const AnyValue &val, AnyValue thisVal, const std::string &propName) noexcept
165
+ {
166
+ if (val.is_data_descriptor())
167
+ {
168
+ return val.as_data_descriptor()->value;
169
+ }
170
+ if (val.is_accessor_descriptor())
171
+ {
172
+ auto accessor = val.as_accessor_descriptor();
173
+ if (accessor->get.has_value())
174
+ return accessor->get.value()(thisVal, std::span<const AnyValue>{});
175
+ else
176
+ {
177
+ return Constants::UNDEFINED;
178
+ }
179
+ }
180
+ return val;
181
+ }
182
+
183
+ AnyValue AnyValue::resolve_property_for_write(AnyValue &val, AnyValue thisVal, const AnyValue &new_val, const std::string &propName)
184
+ {
185
+ if (val.is_data_descriptor())
186
+ {
187
+ auto data = val.as_data_descriptor();
188
+ if (data->writable)
189
+ {
190
+ data->value = new_val;
191
+ return new_val;
192
+ }
193
+ else
194
+ {
195
+ throw Exception::make_exception("Cannot assign to read only property '" + propName + "'", "TypeError");
196
+ }
197
+ }
198
+ if (val.is_accessor_descriptor())
199
+ {
200
+ auto accessor = val.as_accessor_descriptor();
201
+ if (accessor->set.has_value())
202
+ {
203
+ const AnyValue args[] = {new_val};
204
+ accessor->set.value()(thisVal, std::span<const AnyValue>(args, 1));
205
+ return new_val;
206
+ }
207
+ else
208
+ {
209
+ throw Exception::make_exception("Cannot set property of #<Object> which has only a getter", "TypeError");
210
+ }
211
+ }
212
+ val = new_val;
213
+ return new_val;
214
+ }
215
+
216
+ std::string AnyValue::to_std_string() const
217
+ {
218
+ switch (get_type())
219
+ {
220
+ case JsType::Undefined:
221
+ return "undefined";
222
+ case JsType::Null:
223
+ return "null";
224
+ case JsType::Boolean:
225
+ return JsBoolean::to_std_string(as_boolean());
226
+ case JsType::String:
227
+ return as_string()->to_std_string();
228
+ case JsType::Object:
229
+ return as_object()->to_std_string();
230
+ case JsType::Array:
231
+ return as_array()->to_std_string();
232
+ case JsType::Function:
233
+ return as_function()->to_std_string();
234
+ case JsType::Iterator:
235
+ return as_iterator()->to_std_string();
236
+ case JsType::AsyncIterator:
237
+ return as_async_iterator()->to_std_string();
238
+ case JsType::Promise:
239
+ return as_promise()->to_std_string();
240
+ case JsType::Symbol:
241
+ return as_symbol()->to_std_string();
242
+ case JsType::DataDescriptor:
243
+ return as_data_descriptor()->value.to_std_string();
244
+ case JsType::AccessorDescriptor:
245
+ {
246
+ if (as_accessor_descriptor()->get.has_value())
247
+ return as_accessor_descriptor()->get.value()(*this, {}).to_std_string();
248
+ else
249
+ return "undefined";
250
+ }
251
+ case JsType::Number:
252
+ return JsNumber::to_std_string(as_double());
253
+ case JsType::Uninitialized:
254
+ Exception::throw_uninitialized_reference("#<Object>");
255
+ default:
256
+ return "";
257
+ }
258
+ }
259
+
260
+ AnyValue &AnyValue::set_prototype(AnyValue proto)
261
+ {
262
+ if (is_object())
263
+ as_object()->proto = proto;
264
+ else if (is_array())
265
+ as_array()->proto = proto;
266
+ else if (is_function())
267
+ as_function()->proto = proto;
268
+ else if (is_uninitialized())
269
+ Exception::throw_uninitialized_reference("#<Object>");
270
+ return *this;
271
+ }
272
+
273
+ AnyValue AnyValue::call(AnyValue thisVal, std::span<const AnyValue> args, const std::optional<std::string> &expr) const
274
+ {
275
+ if (!is_function())
276
+ throw Exception::make_exception(expr.value_or(to_std_string()) + " is not a function", "TypeError");
277
+ return as_function()->call(thisVal, args);
278
+ }
279
+ AnyValue AnyValue::optional_call(AnyValue thisVal, std::span<const AnyValue> args, const std::optional<std::string> &expr) const
280
+ {
281
+ if (is_null() || is_undefined())
282
+ return Constants::UNDEFINED;
283
+ return as_function()->call(thisVal, args);
284
+ }
285
+
286
+ AnyValue AnyValue::construct(std::span<const AnyValue> args, const std::optional<std::string> &name) const
287
+ {
288
+ if (!is_function() || !as_function()->is_constructor)
289
+ {
290
+ throw Exception::make_exception(name.value_or(to_std_string()) + " is not a constructor", "TypeError");
291
+ }
292
+ AnyValue proto = get_own_property("prototype");
293
+ if (!proto.is_object())
294
+ proto = AnyValue::make_object({});
295
+ AnyValue instance = AnyValue::make_object({}).set_prototype(proto);
296
+ AnyValue result = call(instance, args);
297
+ if (result.is_object() || result.is_function() || result.is_array() || result.is_promise())
298
+ return result;
299
+ return instance;
300
+ }
301
+
302
+ // --- AnyValue methods that were in any_value_access.hpp ---
303
+
304
+ AnyValue AnyValue::get_own_property(const std::string &key) const
305
+ {
306
+ return get_property_with_receiver(key, *this);
307
+ }
308
+
309
+ AnyValue AnyValue::get_own_property_descriptor(const AnyValue &key) const
310
+ {
311
+ if (key.is_symbol())
312
+ {
313
+ switch (get_type())
314
+ {
315
+ case JsType::Object:
316
+ {
317
+ auto obj = as_object();
318
+ auto it = obj->symbol_props.find(key);
319
+ if (it != obj->symbol_props.end())
320
+ return it->second;
321
+ return Constants::UNDEFINED;
322
+ }
323
+ case JsType::Array:
324
+ {
325
+ auto arr = as_array();
326
+ auto it = arr->symbol_props.find(key);
327
+ if (it != arr->symbol_props.end())
328
+ return it->second;
329
+ return Constants::UNDEFINED;
330
+ }
331
+ case JsType::Function:
332
+ {
333
+ auto func = as_function();
334
+ auto it = func->symbol_props.find(key);
335
+ if (it != func->symbol_props.end())
336
+ return it->second;
337
+ return Constants::UNDEFINED;
338
+ }
339
+ default:
340
+ return Constants::UNDEFINED;
341
+ }
342
+ }
343
+
344
+ std::string key_str = key.to_std_string();
345
+ switch (get_type())
346
+ {
347
+ case JsType::Object:
348
+ {
349
+ auto obj = as_object();
350
+ if (obj->deleted_keys.count(key_str))
351
+ return Constants::UNDEFINED;
352
+ auto offset = obj->shape->get_offset(key_str);
353
+ if (offset.has_value())
354
+ return obj->storage[offset.value()];
355
+ return Constants::UNDEFINED;
356
+ }
357
+ case JsType::Array:
358
+ {
359
+ auto arr = as_array();
360
+ if (key_str == "length")
361
+ return AnyValue::make_number(arr->length);
362
+ if (JsArray::is_array_index(key_str))
363
+ {
364
+ uint32_t idx = static_cast<uint32_t>(std::stoull(key_str));
365
+ if (idx < arr->dense.size() && !arr->dense[idx].is_uninitialized())
366
+ return arr->dense[idx];
367
+ if (arr->sparse.count(idx))
368
+ return arr->sparse[idx];
369
+ }
370
+ if (arr->props.count(key_str))
371
+ return arr->props.at(key_str);
372
+ return Constants::UNDEFINED;
373
+ }
374
+ case JsType::Function:
375
+ {
376
+ auto func = as_function();
377
+ if (func->props.count(key_str))
378
+ return func->props.at(key_str);
379
+ return Constants::UNDEFINED;
380
+ }
381
+ case JsType::String:
382
+ {
383
+ auto str = as_string();
384
+ if (key_str == "length")
385
+ return AnyValue::make_number(str->value.length());
386
+ if (JsArray::is_array_index(key_str))
387
+ {
388
+ uint32_t idx = static_cast<uint32_t>(std::stoull(key_str));
389
+ if (idx < str->value.length())
390
+ return AnyValue::make_string(std::string(1, str->value[idx]));
391
+ }
392
+ return Constants::UNDEFINED;
393
+ }
394
+ default:
395
+ return Constants::UNDEFINED;
396
+ }
397
+ }
398
+
399
+ bool AnyValue::has_property(const std::string &key) const
400
+ {
401
+ switch (get_type())
402
+ {
403
+ case JsType::Object:
404
+ return as_object()->has_property(key);
405
+ case JsType::Array:
406
+ return as_array()->has_property(key);
407
+ case JsType::Function:
408
+ return as_function()->has_property(key);
409
+ case JsType::Promise:
410
+ return as_promise()->get_property(key, *this).is_undefined() == false;
411
+ case JsType::Iterator:
412
+ return static_cast<JsIterator<AnyValue> *>(get_ptr())->get_property(key, *this).is_undefined() == false;
413
+ case JsType::AsyncIterator:
414
+ return static_cast<JsAsyncIterator<AnyValue> *>(get_ptr())->get_property(key, *this).is_undefined() == false;
415
+ case JsType::Symbol:
416
+ return SymbolPrototypes::get(key).has_value();
417
+ case JsType::String:
418
+ if (key == "length")
419
+ return true;
420
+ if (JsArray::is_array_index(key))
421
+ {
422
+ uint32_t idx = static_cast<uint32_t>(std::stoull(key));
423
+ return idx < as_string()->value.length();
424
+ }
425
+ return StringPrototypes::get(key).has_value();
426
+ case JsType::Number:
427
+ return NumberPrototypes::get(key).has_value();
428
+ case JsType::Uninitialized:
429
+ Exception::throw_uninitialized_reference("#<Object>");
430
+ return false;
431
+ default:
432
+ return false;
433
+ }
434
+ }
435
+
436
+ bool AnyValue::has_property(const AnyValue &key) const
437
+ {
438
+ if (key.is_symbol())
439
+ {
440
+ switch (get_type())
441
+ {
442
+ case JsType::Object:
443
+ return as_object()->has_symbol_property(key);
444
+ case JsType::Array:
445
+ return as_array()->has_symbol_property(key);
446
+ case JsType::Function:
447
+ return as_function()->has_symbol_property(key);
448
+ case JsType::Promise:
449
+ return as_promise()->has_symbol_property(key);
450
+ case JsType::Iterator:
451
+ return static_cast<JsIterator<AnyValue> *>(get_ptr())->has_symbol_property(key);
452
+ case JsType::AsyncIterator:
453
+ return static_cast<JsAsyncIterator<AnyValue> *>(get_ptr())->has_symbol_property(key);
454
+ default:
455
+ return false;
456
+ }
457
+ }
458
+ return has_property(key.to_std_string());
459
+ }
460
+
461
+ AnyValue AnyValue::get_own_property(uint32_t idx) const
462
+ {
463
+ if (is_array())
464
+ return as_array()->get_property(idx);
465
+ if (is_string())
466
+ return as_string()->get_property(idx);
467
+ return get_own_property(std::to_string(idx));
468
+ }
469
+
470
+ AnyValue AnyValue::get_own_property(const AnyValue &key) const
471
+ {
472
+ if (key.is_number() && is_array())
473
+ return as_array()->get_property(key.as_double());
474
+ if (key.is_number() && is_string())
475
+ return as_string()->get_property(key.as_double());
476
+ if (key.is_symbol())
477
+ return get_own_symbol_property(key);
478
+ return get_own_property(key.to_std_string());
479
+ }
480
+
481
+ AnyValue AnyValue::get_own_symbol_property(const AnyValue &key) const
482
+ {
483
+ return get_symbol_property_with_receiver(key, *this);
484
+ }
485
+
486
+ AnyValue AnyValue::get_property_with_receiver(const std::string &key, AnyValue receiver) const
487
+ {
488
+ switch (get_type())
489
+ {
490
+ case JsType::Object:
491
+ return as_object()->get_property(key, receiver);
492
+ case JsType::Array:
493
+ return as_array()->get_property(key, receiver);
494
+ case JsType::Function:
495
+ return as_function()->get_property(key, receiver);
496
+ case JsType::Promise:
497
+ return as_promise()->get_property(key, receiver);
498
+ case JsType::Iterator:
499
+ return static_cast<JsIterator<AnyValue> *>(get_ptr())->get_property(key, receiver);
500
+ case JsType::AsyncIterator:
501
+ return static_cast<JsAsyncIterator<AnyValue> *>(get_ptr())->get_property(key, receiver);
502
+ case JsType::Symbol:
503
+ return as_symbol()->get_property(key, receiver);
504
+ case JsType::String:
505
+ return as_string()->get_property(key, receiver);
506
+ case JsType::Number:
507
+ {
508
+ auto proto_it = NumberPrototypes::get(key);
509
+ if (proto_it.has_value())
510
+ return AnyValue::resolve_property_for_read(proto_it.value(), receiver, key);
511
+ return Constants::UNDEFINED;
512
+ }
513
+ case JsType::Boolean:
514
+ {
515
+ auto proto_it = BooleanPrototypes::get(key);
516
+ if (proto_it.has_value())
517
+ return AnyValue::resolve_property_for_read(proto_it.value(), receiver, key);
518
+ return Constants::UNDEFINED;
519
+ }
520
+ case JsType::Undefined:
521
+ throw Exception::make_exception("Cannot read properties of undefined (reading '" + key + "')", "TypeError");
522
+ case JsType::Null:
523
+ throw Exception::make_exception("Cannot read properties of null (reading '" + key + "')", "TypeError");
524
+ case JsType::Uninitialized:
525
+ Exception::throw_uninitialized_reference("#<Object>");
526
+ default:
527
+ return Constants::UNDEFINED;
528
+ }
529
+ }
530
+
531
+ AnyValue AnyValue::get_symbol_property_with_receiver(const AnyValue &key, AnyValue receiver) const
532
+ {
533
+ switch (get_type())
534
+ {
535
+ case JsType::Object:
536
+ return as_object()->get_symbol_property(key, receiver);
537
+ case JsType::Array:
538
+ return as_array()->get_symbol_property(key, receiver);
539
+ case JsType::Function:
540
+ return as_function()->get_symbol_property(key, receiver);
541
+ case JsType::Promise:
542
+ return as_promise()->get_symbol_property(key, receiver);
543
+ case JsType::Iterator:
544
+ return static_cast<JsIterator<AnyValue> *>(get_ptr())->get_symbol_property(key, receiver);
545
+ case JsType::AsyncIterator:
546
+ return static_cast<JsAsyncIterator<AnyValue> *>(get_ptr())->get_symbol_property(key, receiver);
547
+ case JsType::Symbol:
548
+ {
549
+ auto proto_it = SymbolPrototypes::get(key);
550
+ if (proto_it.has_value())
551
+ return AnyValue::resolve_property_for_read(proto_it.value(), receiver, key.to_std_string());
552
+ return Constants::UNDEFINED;
553
+ }
554
+ case JsType::String:
555
+ {
556
+ auto proto_it = StringPrototypes::get(key);
557
+ if (proto_it.has_value())
558
+ return AnyValue::resolve_property_for_read(proto_it.value(), receiver, key.to_std_string());
559
+ return Constants::UNDEFINED;
560
+ }
561
+ case JsType::Number:
562
+ {
563
+ auto proto_it = NumberPrototypes::get(key);
564
+ if (proto_it.has_value())
565
+ return AnyValue::resolve_property_for_read(proto_it.value(), receiver, key.to_std_string());
566
+ return Constants::UNDEFINED;
567
+ }
568
+ case JsType::Boolean:
569
+ {
570
+ auto proto_it = BooleanPrototypes::get(key);
571
+ if (proto_it.has_value())
572
+ return AnyValue::resolve_property_for_read(proto_it.value(), receiver, key.to_std_string());
573
+ return Constants::UNDEFINED;
574
+ }
575
+ case JsType::Undefined:
576
+ throw Exception::make_exception("Cannot read properties of undefined (reading Symbol)", "TypeError");
577
+ case JsType::Null:
578
+ throw Exception::make_exception("Cannot read properties of null (reading Symbol)", "TypeError");
579
+ case JsType::Uninitialized:
580
+ Exception::throw_uninitialized_reference("#<Object>");
581
+ default:
582
+ return Constants::UNDEFINED;
583
+ }
584
+ }
585
+
586
+ AnyValue AnyValue::set_own_property(const std::string &key, AnyValue value) const
587
+ {
588
+ switch (get_type())
589
+ {
590
+ case JsType::Object:
591
+ return as_object()->set_property(key, value, *this);
592
+ case JsType::Array:
593
+ return as_array()->set_property(key, value, *this);
594
+ case JsType::Function:
595
+ return as_function()->set_property(key, value, *this);
596
+ case JsType::Promise:
597
+ return as_promise()->set_property(key, value, *this);
598
+ case JsType::Undefined:
599
+ throw Exception::make_exception("Cannot set properties of undefined (setting '" + key + "')", "TypeError");
600
+ case JsType::Null:
601
+ throw Exception::make_exception("Cannot set properties of null (setting '" + key + "')", "TypeError");
602
+ default:
603
+ return value;
604
+ }
605
+ }
606
+
607
+ AnyValue AnyValue::set_own_property(uint32_t idx, AnyValue value) const
608
+ {
609
+ if (is_array())
610
+ return as_array()->set_property(idx, value);
611
+ return set_own_property(std::to_string(idx), value);
612
+ }
613
+
614
+ AnyValue AnyValue::set_own_property(const AnyValue &key, AnyValue value) const
615
+ {
616
+ if (key.is_number() && is_array())
617
+ return as_array()->set_property(key.as_double(), value);
618
+ if (key.is_symbol())
619
+ return set_own_symbol_property(key, value);
620
+ return set_own_property(key.to_std_string(), value);
621
+ }
622
+
623
+ AnyValue AnyValue::set_own_symbol_property(const AnyValue &key, AnyValue value) const
624
+ {
625
+ switch (get_type())
626
+ {
627
+ case JsType::Object:
628
+ return as_object()->set_symbol_property(key, value, *this);
629
+ case JsType::Array:
630
+ return as_array()->set_symbol_property(key, value, *this);
631
+ case JsType::Function:
632
+ return as_function()->set_symbol_property(key, value, *this);
633
+ case JsType::Promise:
634
+ return as_promise()->set_symbol_property(key, value, *this);
635
+ case JsType::Iterator:
636
+ return static_cast<JsIterator<AnyValue> *>(get_ptr())->set_symbol_property(key, value, *this);
637
+ case JsType::AsyncIterator:
638
+ return static_cast<JsAsyncIterator<AnyValue> *>(get_ptr())->set_symbol_property(key, value, *this);
639
+ case JsType::Undefined:
640
+ throw Exception::make_exception("Cannot set properties of undefined (setting Symbol)", "TypeError");
641
+ case JsType::Null:
642
+ throw Exception::make_exception("Cannot set properties of null (setting Symbol)", "TypeError");
643
+ default:
644
+ return value;
645
+ }
646
+ }
647
+
648
+ AnyValue AnyValue::call_own_property(const std::string &key, std::span<const AnyValue> args) const
649
+ {
650
+ return get_own_property(key).call((*this), args, key);
651
+ }
652
+ AnyValue AnyValue::call_own_property(uint32_t idx, std::span<const AnyValue> args) const
653
+ {
654
+ if (is_array())
655
+ return as_array()->get_property(idx).call((*this), args, "[" + std::to_string(idx) + "]");
656
+ if (is_string())
657
+ return as_string()->get_property(idx).call((*this), args, "[" + std::to_string(idx) + "]");
658
+ return call_own_property(std::to_string(idx), args);
659
+ }
660
+ AnyValue AnyValue::call_own_property(const AnyValue &key, std::span<const AnyValue> args) const
661
+ {
662
+ if (key.is_number() && is_array())
663
+ return as_array()->get_property(key.as_double()).call((*this), args, "[" + key.to_std_string() + "]");
664
+ if (key.is_number() && is_string())
665
+ return as_string()->get_property(key.as_double()).call((*this), args, "[" + key.to_std_string() + "]");
666
+ if (key.is_symbol())
667
+ return get_own_symbol_property(key).call((*this), args, key.to_std_string());
668
+ return call_own_property(key.to_std_string(), args);
669
+ }
670
+
671
+ // --- AnyValue methods that were in any_value_defines.hpp ---
672
+
673
+ void AnyValue::define_data_property(const std::string &key, AnyValue value)
674
+ {
675
+ if (is_object())
676
+ {
677
+ auto obj = as_object();
678
+ auto offset = obj->shape->get_offset(key);
679
+ if (offset.has_value())
680
+ obj->storage[offset.value()] = value;
681
+ else
682
+ {
683
+ obj->shape = obj->shape->transition(key);
684
+ obj->storage.push_back(value);
685
+ }
686
+ }
687
+ else if (is_function())
688
+ as_function()->props[key] = value;
689
+ }
690
+
691
+ void AnyValue::define_data_property(const AnyValue &key, AnyValue value)
692
+ {
693
+ if (key.is_symbol())
694
+ {
695
+ if (is_object())
696
+ as_object()->symbol_props[key] = value;
697
+ else if (is_function())
698
+ as_function()->symbol_props[key] = value;
699
+ }
700
+ else
701
+ define_data_property(key.to_std_string(), value);
702
+ }
703
+
704
+ void AnyValue::define_data_property(const std::string &key, AnyValue value, bool writable, bool enumerable, bool configurable)
705
+ {
706
+ define_data_property(key, AnyValue::make_data_descriptor(value, writable, enumerable, configurable));
707
+ }
708
+
709
+ void AnyValue::define_getter(const std::string &key, AnyValue getter)
710
+ {
711
+ if (is_object())
712
+ {
713
+ auto obj = as_object();
714
+ auto offset = obj->shape->get_offset(key);
715
+ if (offset.has_value())
716
+ {
717
+ auto &val = obj->storage[offset.value()];
718
+ if (val.is_accessor_descriptor())
719
+ {
720
+ auto desc = val.as_accessor_descriptor();
721
+ desc->get = [getter](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
722
+ { return getter.call(thisVal, args); };
723
+ }
724
+ else
725
+ {
726
+ auto getFunc = [getter](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
727
+ { return getter.call(thisVal, args); };
728
+ obj->storage[offset.value()] = AnyValue::make_accessor_descriptor(getFunc, std::nullopt, true, true);
729
+ }
730
+ }
731
+ else
732
+ {
733
+ auto getFunc = [getter](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
734
+ { return getter.call(thisVal, args); };
735
+ obj->shape = obj->shape->transition(key);
736
+ obj->storage.push_back(AnyValue::make_accessor_descriptor(getFunc, std::nullopt, true, true));
737
+ }
738
+ }
739
+ else if (is_function())
740
+ {
741
+ auto &props = as_function()->props;
742
+ auto it = props.find(key);
743
+ if (it != props.end() && it->second.is_accessor_descriptor())
744
+ {
745
+ auto desc = it->second.as_accessor_descriptor();
746
+ desc->get = [getter](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
747
+ { return getter.call(thisVal, args); };
748
+ }
749
+ else
750
+ {
751
+ auto getFunc = [getter](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
752
+ { return getter.call(thisVal, args); };
753
+ props[key] = AnyValue::make_accessor_descriptor(getFunc, std::nullopt, true, true);
754
+ }
755
+ }
756
+ }
757
+
758
+ void AnyValue::define_data_property(const AnyValue &key, AnyValue value, bool writable, bool enumerable, bool configurable)
759
+ {
760
+ if (key.is_symbol())
761
+ {
762
+ auto desc = AnyValue::make_data_descriptor(value, writable, enumerable, configurable);
763
+ if (is_object())
764
+ as_object()->symbol_props[key] = desc;
765
+ else if (is_function())
766
+ as_function()->symbol_props[key] = desc;
767
+ }
768
+ else
769
+ define_data_property(key.to_std_string(), value, writable, enumerable, configurable);
770
+ }
771
+
772
+ void AnyValue::define_getter(const AnyValue &key, AnyValue getter)
773
+ {
774
+ if (key.is_symbol())
775
+ {
776
+ auto getFunc = [getter](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
777
+ { return getter.call(thisVal, args); };
778
+ auto desc = AnyValue::make_accessor_descriptor(getFunc, std::nullopt, true, true);
779
+ if (is_object())
780
+ as_object()->symbol_props[key] = desc;
781
+ else if (is_function())
782
+ as_function()->symbol_props[key] = desc;
783
+ }
784
+ else
785
+ define_getter(key.to_std_string(), getter);
786
+ }
787
+
788
+ void AnyValue::define_setter(const std::string &key, AnyValue setter)
789
+ {
790
+ if (is_object())
791
+ {
792
+ auto obj = as_object();
793
+ auto offset = obj->shape->get_offset(key);
794
+ if (offset.has_value())
795
+ {
796
+ auto &val = obj->storage[offset.value()];
797
+ if (val.is_accessor_descriptor())
798
+ {
799
+ auto desc = val.as_accessor_descriptor();
800
+ desc->set = [setter](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
801
+ {
802
+ if (args.empty())
803
+ return Constants::UNDEFINED;
804
+ return setter.call(thisVal, args);
805
+ };
806
+ }
807
+ else
808
+ {
809
+ auto setFunc = [setter](AnyValue thisVal, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
810
+ {
811
+ if (args.empty())
812
+ return jspp::Constants::UNDEFINED;
813
+ return setter.call(thisVal, args);
814
+ };
815
+ obj->storage[offset.value()] = AnyValue::make_accessor_descriptor(std::nullopt, setFunc, true, true);
816
+ }
817
+ }
818
+ else
819
+ {
820
+ auto setFunc = [setter](AnyValue thisVal, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
821
+ {
822
+ if (args.empty())
823
+ return jspp::Constants::UNDEFINED;
824
+ return setter.call(thisVal, args);
825
+ };
826
+ obj->shape = obj->shape->transition(key);
827
+ obj->storage.push_back(AnyValue::make_accessor_descriptor(std::nullopt, setFunc, true, true));
828
+ }
829
+ }
830
+ else if (is_function())
831
+ {
832
+ auto &props = as_function()->props;
833
+ auto it = props.find(key);
834
+ if (it != props.end() && it->second.is_accessor_descriptor())
835
+ {
836
+ auto desc = it->second.as_accessor_descriptor();
837
+ desc->set = [setter](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
838
+ {
839
+ if (args.empty())
840
+ return Constants::UNDEFINED;
841
+ return setter.call(thisVal, args);
842
+ };
843
+ }
844
+ else
845
+ {
846
+ auto setFunc = [setter](AnyValue thisVal, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
847
+ {
848
+ if (args.empty())
849
+ return jspp::Constants::UNDEFINED;
850
+ return setter.call(thisVal, args);
851
+ };
852
+ props[key] = AnyValue::make_accessor_descriptor(std::nullopt, setFunc, true, true);
853
+ }
854
+ }
855
+ }
856
+
857
+ void AnyValue::define_setter(const AnyValue &key, AnyValue setter)
858
+ {
859
+ if (key.is_symbol())
860
+ {
861
+ auto setFunc = [setter](AnyValue thisVal, std::span<const AnyValue> args) -> AnyValue
862
+ {
863
+ if (args.empty())
864
+ return Constants::UNDEFINED;
865
+ return setter.call(thisVal, args);
866
+ };
867
+ auto desc = AnyValue::make_accessor_descriptor(std::nullopt, setFunc, true, true);
868
+ if (is_object())
869
+ as_object()->symbol_props[key] = desc;
870
+ else if (is_function())
871
+ as_function()->symbol_props[key] = desc;
872
+ }
873
+ else
874
+ define_setter(key.to_std_string(), setter);
875
+ }
876
+
877
+ // AnyValue iterator methods from runtime.cpp
878
+ JsIterator<AnyValue> *AnyValue::as_iterator() const noexcept
879
+ {
880
+ return static_cast<JsIterator<AnyValue> *>(get_ptr());
881
+ }
882
+
883
+ JsAsyncIterator<AnyValue> *AnyValue::as_async_iterator() const noexcept
884
+ {
885
+ return static_cast<JsAsyncIterator<AnyValue> *>(get_ptr());
886
+ }
887
+
888
+ } // namespace jspp