@ugo-studio/jspp 0.2.9 → 0.3.1

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 (97) hide show
  1. package/LICENSE +25 -25
  2. package/README.md +20 -12
  3. package/dist/analysis/scope.js +5 -3
  4. package/dist/analysis/typeAnalyzer.js +21 -25
  5. package/dist/cli/index.js +14 -4
  6. package/dist/cli/utils.js +61 -0
  7. package/dist/core/codegen/class-handlers.js +6 -6
  8. package/dist/core/codegen/control-flow-handlers.js +10 -9
  9. package/dist/core/codegen/declaration-handlers.js +10 -3
  10. package/dist/core/codegen/destructuring-handlers.js +9 -4
  11. package/dist/core/codegen/expression-handlers.js +40 -29
  12. package/dist/core/codegen/function-handlers.js +78 -12
  13. package/dist/core/codegen/helpers.js +91 -14
  14. package/dist/core/codegen/index.js +4 -2
  15. package/dist/core/codegen/statement-handlers.js +9 -7
  16. package/package.json +2 -2
  17. package/scripts/precompile-headers.ts +249 -50
  18. package/scripts/setup-compiler.ts +63 -63
  19. package/src/prelude/any_value.cpp +636 -0
  20. package/src/prelude/any_value.hpp +369 -362
  21. package/src/prelude/{exception_helpers.hpp → exception.cpp} +53 -53
  22. package/src/prelude/exception.hpp +27 -27
  23. package/src/prelude/iterator_instantiations.hpp +10 -0
  24. package/src/prelude/{index.hpp → jspp.hpp} +10 -16
  25. package/src/prelude/library/array.cpp +191 -0
  26. package/src/prelude/library/array.hpp +13 -186
  27. package/src/prelude/library/console.cpp +125 -0
  28. package/src/prelude/library/console.hpp +24 -112
  29. package/src/prelude/library/error.cpp +100 -0
  30. package/src/prelude/library/error.hpp +13 -113
  31. package/src/prelude/library/function.cpp +69 -0
  32. package/src/prelude/library/function.hpp +11 -10
  33. package/src/prelude/library/global.cpp +96 -0
  34. package/src/prelude/library/global.hpp +12 -28
  35. package/src/prelude/library/global_usings.hpp +15 -0
  36. package/src/prelude/library/math.cpp +258 -0
  37. package/src/prelude/library/math.hpp +26 -308
  38. package/src/prelude/library/object.cpp +379 -0
  39. package/src/prelude/library/object.hpp +14 -276
  40. package/src/prelude/library/performance.cpp +21 -0
  41. package/src/prelude/library/performance.hpp +5 -20
  42. package/src/prelude/library/process.cpp +38 -0
  43. package/src/prelude/library/process.hpp +11 -39
  44. package/src/prelude/library/promise.cpp +131 -0
  45. package/src/prelude/library/promise.hpp +12 -123
  46. package/src/prelude/library/symbol.cpp +56 -0
  47. package/src/prelude/library/symbol.hpp +11 -52
  48. package/src/prelude/library/timer.cpp +88 -0
  49. package/src/prelude/library/timer.hpp +16 -92
  50. package/src/prelude/runtime.cpp +19 -0
  51. package/src/prelude/types.hpp +184 -179
  52. package/src/prelude/utils/access.hpp +502 -411
  53. package/src/prelude/utils/assignment_operators.hpp +99 -99
  54. package/src/prelude/utils/log_any_value/array.hpp +61 -40
  55. package/src/prelude/utils/log_any_value/function.hpp +39 -39
  56. package/src/prelude/utils/log_any_value/object.hpp +60 -3
  57. package/src/prelude/utils/operators.hpp +351 -336
  58. package/src/prelude/utils/operators_primitive.hpp +336 -336
  59. package/src/prelude/utils/well_known_symbols.hpp +24 -24
  60. package/src/prelude/values/array.cpp +1399 -0
  61. package/src/prelude/values/array.hpp +4 -1
  62. package/src/prelude/values/async_iterator.cpp +251 -0
  63. package/src/prelude/values/async_iterator.hpp +111 -83
  64. package/src/prelude/values/function.cpp +262 -0
  65. package/src/prelude/values/function.hpp +62 -82
  66. package/src/prelude/values/iterator.cpp +309 -0
  67. package/src/prelude/values/iterator.hpp +33 -64
  68. package/src/prelude/values/number.cpp +176 -0
  69. package/src/prelude/values/object.cpp +159 -0
  70. package/src/prelude/values/object.hpp +4 -0
  71. package/src/prelude/values/promise.cpp +479 -0
  72. package/src/prelude/values/promise.hpp +79 -72
  73. package/src/prelude/values/prototypes/array.hpp +46 -1336
  74. package/src/prelude/values/prototypes/async_iterator.hpp +19 -61
  75. package/src/prelude/values/prototypes/function.hpp +7 -46
  76. package/src/prelude/values/prototypes/iterator.hpp +25 -201
  77. package/src/prelude/values/prototypes/number.hpp +23 -210
  78. package/src/prelude/values/prototypes/object.hpp +7 -23
  79. package/src/prelude/values/prototypes/promise.hpp +18 -196
  80. package/src/prelude/values/prototypes/string.hpp +39 -542
  81. package/src/prelude/values/prototypes/symbol.hpp +9 -70
  82. package/src/prelude/values/shape.hpp +52 -52
  83. package/src/prelude/values/string.cpp +485 -0
  84. package/src/prelude/values/string.hpp +25 -26
  85. package/src/prelude/values/symbol.cpp +89 -0
  86. package/src/prelude/values/symbol.hpp +101 -101
  87. package/src/prelude/any_value_access.hpp +0 -170
  88. package/src/prelude/any_value_defines.hpp +0 -190
  89. package/src/prelude/any_value_helpers.hpp +0 -374
  90. package/src/prelude/values/helpers/array.hpp +0 -209
  91. package/src/prelude/values/helpers/async_iterator.hpp +0 -275
  92. package/src/prelude/values/helpers/function.hpp +0 -109
  93. package/src/prelude/values/helpers/iterator.hpp +0 -145
  94. package/src/prelude/values/helpers/object.hpp +0 -104
  95. package/src/prelude/values/helpers/promise.hpp +0 -254
  96. package/src/prelude/values/helpers/string.hpp +0 -61
  97. package/src/prelude/values/helpers/symbol.hpp +0 -21
@@ -0,0 +1,159 @@
1
+ #include "jspp.hpp"
2
+ #include "values/object.hpp"
3
+ #include "values/prototypes/object.hpp"
4
+
5
+ namespace jspp {
6
+
7
+ // --- JsObject Implementation ---
8
+
9
+ JsObject::JsObject() : shape(Shape::empty_shape()), proto(Constants::Null) {}
10
+
11
+ JsObject::JsObject(std::initializer_list<std::pair<std::string, AnyValue>> p, AnyValue pr) : proto(pr) {
12
+ shape = Shape::empty_shape();
13
+ storage.reserve(p.size());
14
+ for (const auto& pair : p) {
15
+ shape = shape->transition(pair.first);
16
+ storage.push_back(pair.second);
17
+ }
18
+ }
19
+
20
+ JsObject::JsObject(const std::map<std::string, AnyValue> &p, AnyValue pr) : proto(pr) {
21
+ shape = Shape::empty_shape();
22
+ storage.reserve(p.size());
23
+ for (const auto& pair : p) {
24
+ shape = shape->transition(pair.first);
25
+ storage.push_back(pair.second);
26
+ }
27
+ }
28
+
29
+ std::string JsObject::to_std_string() const {
30
+ return "[Object Object]";
31
+ }
32
+
33
+ bool JsObject::has_property(const std::string &key) const {
34
+ if (deleted_keys.count(key)) return false;
35
+
36
+ if (shape->get_offset(key).has_value())
37
+ return true;
38
+ if (!proto.is_null() && !proto.is_undefined()) {
39
+ if (proto.has_property(key))
40
+ return true;
41
+ }
42
+ if (ObjectPrototypes::get(key).has_value())
43
+ return true;
44
+ return false;
45
+ }
46
+
47
+ bool JsObject::has_symbol_property(const AnyValue &key) const {
48
+ if (symbol_props.count(key))
49
+ return true;
50
+ if (!proto.is_null() && !proto.is_undefined()) {
51
+ if (proto.has_property(key)) return true;
52
+ }
53
+ if (ObjectPrototypes::get(key).has_value())
54
+ return true;
55
+ return false;
56
+ }
57
+
58
+ AnyValue JsObject::get_property(const std::string &key, const AnyValue &thisVal) {
59
+ if (deleted_keys.count(key)) return Constants::UNDEFINED;
60
+
61
+ auto offset = shape->get_offset(key);
62
+ if (!offset.has_value()) {
63
+ if (!proto.is_null() && !proto.is_undefined()) {
64
+ if (proto.has_property(key)) {
65
+ return proto.get_property_with_receiver(key, thisVal);
66
+ }
67
+ }
68
+
69
+ auto proto_it = ObjectPrototypes::get(key);
70
+ if (proto_it.has_value()) {
71
+ return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key);
72
+ }
73
+ return Constants::UNDEFINED;
74
+ }
75
+ return AnyValue::resolve_property_for_read(storage[offset.value()], thisVal, key);
76
+ }
77
+
78
+ AnyValue JsObject::get_symbol_property(const AnyValue &key, const AnyValue &thisVal) {
79
+ auto it = symbol_props.find(key);
80
+ if (it == symbol_props.end()) {
81
+ if (!proto.is_null() && !proto.is_undefined()) {
82
+ auto res = proto.get_symbol_property_with_receiver(key, thisVal);
83
+ if (!res.is_undefined()) return res;
84
+ }
85
+
86
+ auto proto_it = ObjectPrototypes::get(key);
87
+ if (proto_it.has_value()) {
88
+ return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key.to_std_string());
89
+ }
90
+ return Constants::UNDEFINED;
91
+ }
92
+ return AnyValue::resolve_property_for_read(it->second, thisVal, key.to_std_string());
93
+ }
94
+
95
+ AnyValue JsObject::set_property(const std::string &key, const AnyValue &value, const AnyValue &thisVal) {
96
+ auto proto_it = ObjectPrototypes::get(key);
97
+ if (proto_it.has_value()) {
98
+ auto proto_value = proto_it.value();
99
+ if (proto_value.is_accessor_descriptor()) {
100
+ return AnyValue::resolve_property_for_write(proto_value, thisVal, value, key);
101
+ }
102
+ if (proto_value.is_data_descriptor() && !proto_value.as_data_descriptor()->writable) {
103
+ return AnyValue::resolve_property_for_write(proto_value, thisVal, value, key);
104
+ }
105
+ }
106
+
107
+ if (deleted_keys.count(key)) deleted_keys.erase(key);
108
+
109
+ auto offset = shape->get_offset(key);
110
+ if (offset.has_value()) {
111
+ return AnyValue::resolve_property_for_write(storage[offset.value()], thisVal, value, key);
112
+ } else {
113
+ shape = shape->transition(key);
114
+ storage.push_back(value);
115
+ return value;
116
+ }
117
+ }
118
+
119
+ AnyValue JsObject::set_symbol_property(const AnyValue &key, const AnyValue &value, const AnyValue &thisVal) {
120
+ auto it = symbol_props.find(key);
121
+ if (it != symbol_props.end()) {
122
+ return AnyValue::resolve_property_for_write(it->second, thisVal, value, key.to_std_string());
123
+ } else {
124
+ symbol_props[key] = value;
125
+ return value;
126
+ }
127
+ }
128
+
129
+ // --- ObjectPrototypes Implementation ---
130
+
131
+ namespace ObjectPrototypes {
132
+
133
+ AnyValue& get_toString_fn() {
134
+ static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> _) -> AnyValue
135
+ { return AnyValue::make_string(thisVal.to_std_string()); },
136
+ "toString");
137
+ return fn;
138
+ }
139
+
140
+ std::optional<AnyValue> get(const std::string &key) {
141
+ if (key == "toString") {
142
+ return get_toString_fn();
143
+ }
144
+ return std::nullopt;
145
+ }
146
+
147
+ std::optional<AnyValue> get(const AnyValue &key) {
148
+ if (key.is_string())
149
+ return get(key.as_string()->value);
150
+
151
+ if (key == AnyValue::from_symbol(WellKnownSymbols::toStringTag)) {
152
+ return get_toString_fn();
153
+ }
154
+ return std::nullopt;
155
+ }
156
+
157
+ } // namespace ObjectPrototypes
158
+
159
+ } // namespace jspp
@@ -16,6 +16,7 @@ namespace jspp
16
16
  std::vector<AnyValue> storage;
17
17
  AnyValue proto;
18
18
  std::unordered_set<std::string> deleted_keys;
19
+ std::map<AnyValue, AnyValue> symbol_props;
19
20
 
20
21
  JsObject();
21
22
  JsObject(std::initializer_list<std::pair<std::string, AnyValue>> p, AnyValue pr);
@@ -25,7 +26,10 @@ namespace jspp
25
26
 
26
27
  std::string to_std_string() const;
27
28
  bool has_property(const std::string &key) const;
29
+ bool has_symbol_property(const AnyValue &key) const;
28
30
  AnyValue get_property(const std::string &key, const AnyValue &thisVal);
31
+ AnyValue get_symbol_property(const AnyValue &key, const AnyValue &thisVal);
29
32
  AnyValue set_property(const std::string &key, const AnyValue &value, const AnyValue &thisVal);
33
+ AnyValue set_symbol_property(const AnyValue &key, const AnyValue &value, const AnyValue &thisVal);
30
34
  };
31
35
  }
@@ -0,0 +1,479 @@
1
+ #include "jspp.hpp"
2
+ #include "values/promise.hpp"
3
+ #include "values/prototypes/promise.hpp"
4
+
5
+ namespace jspp {
6
+
7
+ // --- PromiseState Implementation ---
8
+
9
+ PromiseState::PromiseState() : result(Constants::UNDEFINED), handled(false) {}
10
+
11
+ PromiseState::~PromiseState()
12
+ {
13
+ if (status == PromiseStatus::Rejected && !handled)
14
+ {
15
+ std::string msg;
16
+ try
17
+ {
18
+ if (result.is_object() || result.is_function())
19
+ {
20
+ msg = result.call_own_property("toString", {}).to_std_string();
21
+ }
22
+ else
23
+ {
24
+ msg = result.to_std_string();
25
+ }
26
+ }
27
+ catch (...)
28
+ {
29
+ msg = result.to_std_string();
30
+ }
31
+ std::cerr << "UnhandledPromiseRejection: " << msg << "\n";
32
+ std::exit(1);
33
+ }
34
+ }
35
+
36
+ // --- JsPromise Implementation ---
37
+
38
+ JsPromise::JsPromise() : state(std::make_shared<PromiseState>()) {}
39
+
40
+ void JsPromise::resolve(AnyValue value)
41
+ {
42
+ if (state->status != PromiseStatus::Pending)
43
+ return;
44
+
45
+ if (value.is_promise())
46
+ {
47
+ auto p = value.as_promise();
48
+ if (p->state == state)
49
+ {
50
+ reject(AnyValue::make_string("TypeError: Chaining cycle detected for promise"));
51
+ return;
52
+ }
53
+
54
+ auto weak_state = std::weak_ptr<PromiseState>(state);
55
+
56
+ p->then(
57
+ [weak_state](AnyValue v)
58
+ {
59
+ if (auto s = weak_state.lock())
60
+ {
61
+ s->status = PromiseStatus::Fulfilled;
62
+ s->result = v;
63
+ auto callbacks = s->onFulfilled;
64
+ s->onFulfilled.clear();
65
+ s->onRejected.clear();
66
+ for (auto &cb : callbacks)
67
+ jspp::Scheduler::instance().enqueue([cb, v]()
68
+ { cb(v); });
69
+ }
70
+ },
71
+ [weak_state](AnyValue r)
72
+ {
73
+ if (auto s = weak_state.lock())
74
+ {
75
+ s->status = PromiseStatus::Rejected;
76
+ s->result = r;
77
+ auto callbacks = s->onRejected;
78
+ s->onFulfilled.clear();
79
+ s->onRejected.clear();
80
+ for (auto &cb : callbacks)
81
+ jspp::Scheduler::instance().enqueue([cb, r]()
82
+ { cb(r); });
83
+ }
84
+ });
85
+ return;
86
+ }
87
+
88
+ state->status = PromiseStatus::Fulfilled;
89
+ state->result = value;
90
+
91
+ auto callbacks = state->onFulfilled;
92
+ state->onFulfilled.clear();
93
+ state->onRejected.clear();
94
+
95
+ for (auto &cb : callbacks)
96
+ {
97
+ jspp::Scheduler::instance().enqueue([cb, value]()
98
+ { cb(value); });
99
+ }
100
+ }
101
+
102
+ void JsPromise::reject(AnyValue reason)
103
+ {
104
+ if (state->status != PromiseStatus::Pending)
105
+ return;
106
+ state->status = PromiseStatus::Rejected;
107
+ state->result = reason;
108
+
109
+ auto callbacks = state->onRejected;
110
+ state->onFulfilled.clear();
111
+ state->onRejected.clear();
112
+
113
+ for (auto &cb : callbacks)
114
+ {
115
+ jspp::Scheduler::instance().enqueue([cb, reason]()
116
+ { cb(reason); });
117
+ }
118
+ }
119
+
120
+ void JsPromise::then(std::function<void(AnyValue)> onFulfilled, std::function<void(AnyValue)> onRejected)
121
+ {
122
+ state->handled = true;
123
+ if (state->status == PromiseStatus::Fulfilled)
124
+ {
125
+ if (onFulfilled)
126
+ {
127
+ AnyValue val = state->result;
128
+ jspp::Scheduler::instance().enqueue([onFulfilled, val]()
129
+ { onFulfilled(val); });
130
+ }
131
+ }
132
+ else if (state->status == PromiseStatus::Rejected)
133
+ {
134
+ if (onRejected)
135
+ {
136
+ AnyValue val = state->result;
137
+ jspp::Scheduler::instance().enqueue([onRejected, val]()
138
+ { onRejected(val); });
139
+ }
140
+ }
141
+ else
142
+ {
143
+ if (onFulfilled)
144
+ state->onFulfilled.push_back(onFulfilled);
145
+ if (onRejected)
146
+ state->onRejected.push_back(onRejected);
147
+ }
148
+ }
149
+
150
+ std::string JsPromise::to_std_string() const
151
+ {
152
+ return "[object Promise]";
153
+ }
154
+
155
+ bool JsPromise::has_symbol_property(const AnyValue &key) const
156
+ {
157
+ if (symbol_props.count(key) > 0)
158
+ return true;
159
+ if (PromisePrototypes::get(key).has_value())
160
+ return true;
161
+ return false;
162
+ }
163
+
164
+ AnyValue JsPromise::get_property(const std::string &key, AnyValue thisVal)
165
+ {
166
+ auto proto_it = PromisePrototypes::get(key);
167
+ if (proto_it.has_value())
168
+ {
169
+ return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key);
170
+ }
171
+
172
+ auto it = props.find(key);
173
+ if (it != props.end())
174
+ {
175
+ return AnyValue::resolve_property_for_read(it->second, thisVal, key);
176
+ }
177
+ return Constants::UNDEFINED;
178
+ }
179
+
180
+ AnyValue JsPromise::get_symbol_property(const AnyValue &key, AnyValue thisVal)
181
+ {
182
+ auto it = symbol_props.find(key);
183
+ if (it == symbol_props.end())
184
+ {
185
+ auto proto_it = PromisePrototypes::get(key);
186
+ if (proto_it.has_value())
187
+ {
188
+ return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key.to_std_string());
189
+ }
190
+ return Constants::UNDEFINED;
191
+ }
192
+ return AnyValue::resolve_property_for_read(it->second, thisVal, key.to_std_string());
193
+ }
194
+
195
+ AnyValue JsPromise::set_property(const std::string &key, AnyValue value, AnyValue thisVal)
196
+ {
197
+ auto it = props.find(key);
198
+ if (it != props.end())
199
+ {
200
+ return AnyValue::resolve_property_for_write(it->second, thisVal, value, key);
201
+ }
202
+ else
203
+ {
204
+ props[key] = value;
205
+ return value;
206
+ }
207
+ }
208
+
209
+ AnyValue JsPromise::set_symbol_property(const AnyValue &key, AnyValue value, AnyValue thisVal)
210
+ {
211
+ auto it = symbol_props.find(key);
212
+ if (it != symbol_props.end())
213
+ {
214
+ return AnyValue::resolve_property_for_write(it->second, thisVal, value, key.to_std_string());
215
+ }
216
+ else
217
+ {
218
+ symbol_props[key] = value;
219
+ return value;
220
+ }
221
+ }
222
+
223
+ // --- JsPromisePromiseType Implementation ---
224
+
225
+ void JsPromisePromiseType::return_value(AnyValue val)
226
+ {
227
+ promise.resolve(val);
228
+ }
229
+
230
+ void JsPromisePromiseType::unhandled_exception()
231
+ {
232
+ try
233
+ {
234
+ throw;
235
+ }
236
+ catch (const Exception &e)
237
+ {
238
+ promise.reject(e.data);
239
+ }
240
+ catch (const std::exception &e)
241
+ {
242
+ promise.reject(AnyValue::make_string(e.what()));
243
+ }
244
+ catch (...)
245
+ {
246
+ promise.reject(AnyValue::make_string("Unknown exception"));
247
+ }
248
+ }
249
+
250
+ AnyValueAwaiter JsPromisePromiseType::await_transform(AnyValue value)
251
+ {
252
+ return AnyValueAwaiter{value};
253
+ }
254
+
255
+ AnyValueAwaiter JsPromisePromiseType::await_transform(const JsPromise &value)
256
+ {
257
+ return AnyValueAwaiter{AnyValue::make_promise(value)};
258
+ }
259
+
260
+ // --- AnyValueAwaiter Implementation ---
261
+
262
+ bool AnyValueAwaiter::await_ready()
263
+ {
264
+ return false;
265
+ }
266
+
267
+ void AnyValueAwaiter::await_suspend(std::coroutine_handle<> h)
268
+ {
269
+ if (!value.is_promise())
270
+ {
271
+ jspp::Scheduler::instance().enqueue([h]() mutable
272
+ { h.resume(); });
273
+ return;
274
+ }
275
+ auto p = value.as_promise();
276
+
277
+ p->then(
278
+ [h](AnyValue v) mutable
279
+ { h.resume(); },
280
+ [h](AnyValue e) mutable
281
+ { h.resume(); });
282
+ }
283
+
284
+ AnyValue AnyValueAwaiter::await_resume()
285
+ {
286
+ if (!value.is_promise())
287
+ return value;
288
+ auto p = value.as_promise();
289
+ if (p->state->status == PromiseStatus::Fulfilled)
290
+ {
291
+ return p->state->result;
292
+ }
293
+ else
294
+ {
295
+ throw Exception(p->state->result);
296
+ }
297
+ }
298
+
299
+ // --- PromisePrototypes Implementation ---
300
+
301
+ namespace PromisePrototypes {
302
+
303
+ AnyValue &get_then_fn()
304
+ {
305
+ static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
306
+ {
307
+ auto self = thisVal.as_promise();
308
+ AnyValue onFulfilled = (args.size() > 0 && args[0].is_function()) ? args[0] : Constants::UNDEFINED;
309
+ AnyValue onRejected = (args.size() > 1 && args[1].is_function()) ? args[1] : Constants::UNDEFINED;
310
+
311
+ JsPromise newPromise;
312
+ AnyValue newPromiseVal = AnyValue::make_promise(newPromise);
313
+
314
+ auto newPromiseState = newPromise.state;
315
+ auto resolveNew = [newPromiseState](const AnyValue &v)
316
+ {
317
+ if (newPromiseState->status != PromiseStatus::Pending)
318
+ return;
319
+ newPromiseState->status = PromiseStatus::Fulfilled;
320
+ newPromiseState->result = v;
321
+ auto callbacks = newPromiseState->onFulfilled;
322
+ newPromiseState->onFulfilled.clear();
323
+ newPromiseState->onRejected.clear();
324
+ for (auto &cb : callbacks)
325
+ jspp::Scheduler::instance().enqueue([cb, v]()
326
+ { cb(v); });
327
+ };
328
+ auto rejectNew = [newPromiseState](const AnyValue &r)
329
+ {
330
+ if (newPromiseState->status != PromiseStatus::Pending)
331
+ return;
332
+ newPromiseState->status = PromiseStatus::Rejected;
333
+ newPromiseState->result = r;
334
+ auto callbacks = newPromiseState->onRejected;
335
+ newPromiseState->onFulfilled.clear();
336
+ newPromiseState->onRejected.clear();
337
+ for (auto &cb : callbacks)
338
+ jspp::Scheduler::instance().enqueue([cb, r]()
339
+ { cb(r); });
340
+ };
341
+
342
+ auto resolveHandler = [resolveNew, rejectNew, onFulfilled](const AnyValue &val) mutable
343
+ {
344
+ if (onFulfilled.is_function())
345
+ {
346
+ try
347
+ {
348
+ const AnyValue cbArgs[] = {val};
349
+ auto res = onFulfilled.call(Constants::UNDEFINED, cbArgs, "onFulfilled");
350
+ if (res.is_promise())
351
+ {
352
+ auto chained = res.as_promise();
353
+ chained->then(
354
+ [resolveNew](const AnyValue &v)
355
+ { resolveNew(v); },
356
+ [rejectNew](const AnyValue &e)
357
+ { rejectNew(e); });
358
+ }
359
+ else
360
+ {
361
+ resolveNew(res);
362
+ }
363
+ }
364
+ catch (const Exception &e)
365
+ {
366
+ rejectNew(e.data);
367
+ }
368
+ catch (...)
369
+ {
370
+ rejectNew(AnyValue::make_string("Unknown error"));
371
+ }
372
+ }
373
+ else
374
+ {
375
+ resolveNew(val);
376
+ }
377
+ };
378
+
379
+ auto rejectHandler = [resolveNew, rejectNew, onRejected](const AnyValue &reason) mutable
380
+ {
381
+ if (onRejected.is_function())
382
+ {
383
+ try
384
+ {
385
+ const AnyValue cbArgs[] = {reason};
386
+ auto res = onRejected.call(Constants::UNDEFINED, cbArgs, "onRejected");
387
+ if (res.is_promise())
388
+ {
389
+ auto chained = res.as_promise();
390
+ chained->then(
391
+ [resolveNew](const AnyValue &v)
392
+ { resolveNew(v); },
393
+ [rejectNew](const AnyValue &e)
394
+ { rejectNew(e); });
395
+ }
396
+ else
397
+ {
398
+ resolveNew(res);
399
+ }
400
+ }
401
+ catch (const Exception &e)
402
+ {
403
+ rejectNew(e.data);
404
+ }
405
+ catch (...)
406
+ {
407
+ rejectNew(AnyValue::make_string("Unknown error"));
408
+ }
409
+ }
410
+ else
411
+ {
412
+ rejectNew(reason);
413
+ }
414
+ };
415
+
416
+ self->then(resolveHandler, rejectHandler);
417
+ return newPromiseVal; },
418
+ "then");
419
+ return fn;
420
+ }
421
+
422
+ AnyValue &get_catch_fn()
423
+ {
424
+ static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
425
+ {
426
+ AnyValue onRejected = (args.size() > 0 && args[0].is_function()) ? args[0] : Constants::UNDEFINED;
427
+ const AnyValue thenArgs[] = {Constants::UNDEFINED, onRejected};
428
+ return thisVal.get_own_property("then").call(thisVal, thenArgs, "then"); },
429
+ "catch");
430
+ return fn;
431
+ }
432
+
433
+ AnyValue &get_finally_fn()
434
+ {
435
+ static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
436
+ {
437
+ AnyValue onFinally = (args.size() > 0 && args[0].is_function()) ? args[0] : Constants::UNDEFINED;
438
+
439
+ const AnyValue thenArgs[] = {
440
+ AnyValue::make_function([onFinally](const AnyValue &, std::span<const AnyValue> args) -> AnyValue
441
+ {
442
+ AnyValue val = args.empty() ? Constants::UNDEFINED : args[0];
443
+ if (onFinally.is_function())
444
+ {
445
+ onFinally.call(Constants::UNDEFINED, {}, "onFinally");
446
+ }
447
+ return val; },
448
+ ""),
449
+ AnyValue::make_function([onFinally](const AnyValue &, std::span<const AnyValue> args) -> AnyValue
450
+ {
451
+ AnyValue reason = args.empty() ? Constants::UNDEFINED : args[0];
452
+ if (onFinally.is_function())
453
+ {
454
+ onFinally.call(Constants::UNDEFINED, {}, "onFinally");
455
+ }
456
+ throw Exception(reason); },
457
+ "")};
458
+ return thisVal.get_own_property("then").call(thisVal, thenArgs, "then"); },
459
+ "finally");
460
+ return fn;
461
+ }
462
+
463
+ std::optional<AnyValue> get(const std::string &key)
464
+ {
465
+ if (key == "then") return get_then_fn();
466
+ if (key == "catch") return get_catch_fn();
467
+ if (key == "finally") return get_finally_fn();
468
+ return std::nullopt;
469
+ }
470
+
471
+ std::optional<AnyValue> get(const AnyValue &key)
472
+ {
473
+ // Well-known symbols could be added here if needed
474
+ return std::nullopt;
475
+ }
476
+
477
+ } // namespace PromisePrototypes
478
+
479
+ } // namespace jspp