@ugo-studio/jspp 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +5 -3
  2. package/dist/analysis/scope.js +38 -15
  3. package/dist/analysis/typeAnalyzer.js +257 -23
  4. package/dist/ast/types.js +6 -0
  5. package/dist/cli.js +3 -4
  6. package/dist/core/codegen/class-handlers.js +127 -0
  7. package/dist/core/codegen/control-flow-handlers.js +464 -0
  8. package/dist/core/codegen/declaration-handlers.js +31 -14
  9. package/dist/core/codegen/expression-handlers.js +432 -116
  10. package/dist/core/codegen/function-handlers.js +110 -13
  11. package/dist/core/codegen/helpers.js +76 -8
  12. package/dist/core/codegen/index.js +18 -5
  13. package/dist/core/codegen/literal-handlers.js +3 -0
  14. package/dist/core/codegen/statement-handlers.js +152 -186
  15. package/dist/core/codegen/visitor.js +35 -3
  16. package/package.json +3 -3
  17. package/src/prelude/any_value.hpp +658 -734
  18. package/src/prelude/any_value_access.hpp +103 -0
  19. package/src/prelude/any_value_defines.hpp +151 -0
  20. package/src/prelude/any_value_helpers.hpp +246 -0
  21. package/src/prelude/exception.hpp +31 -0
  22. package/src/prelude/exception_helpers.hpp +49 -0
  23. package/src/prelude/index.hpp +35 -12
  24. package/src/prelude/library/console.hpp +20 -20
  25. package/src/prelude/library/error.hpp +111 -0
  26. package/src/prelude/library/global.hpp +15 -4
  27. package/src/prelude/library/performance.hpp +25 -0
  28. package/src/prelude/library/promise.hpp +121 -0
  29. package/src/prelude/library/symbol.hpp +60 -4
  30. package/src/prelude/library/timer.hpp +92 -0
  31. package/src/prelude/scheduler.hpp +145 -0
  32. package/src/prelude/types.hpp +33 -6
  33. package/src/prelude/utils/access.hpp +174 -0
  34. package/src/prelude/utils/log_any_value/array.hpp +245 -0
  35. package/src/prelude/utils/log_any_value/config.hpp +32 -0
  36. package/src/prelude/utils/log_any_value/function.hpp +37 -0
  37. package/src/prelude/utils/log_any_value/fwd.hpp +15 -0
  38. package/src/prelude/utils/log_any_value/helpers.hpp +62 -0
  39. package/src/prelude/utils/log_any_value/log_any_value.hpp +94 -0
  40. package/src/prelude/utils/log_any_value/object.hpp +119 -0
  41. package/src/prelude/utils/log_any_value/primitives.hpp +41 -0
  42. package/src/prelude/{operators.hpp → utils/operators.hpp} +31 -12
  43. package/src/prelude/utils/well_known_symbols.hpp +13 -0
  44. package/src/prelude/values/array.hpp +5 -2
  45. package/src/prelude/{descriptors.hpp → values/descriptors.hpp} +2 -2
  46. package/src/prelude/values/function.hpp +76 -19
  47. package/src/prelude/values/{operators → helpers}/array.hpp +30 -14
  48. package/src/prelude/values/helpers/function.hpp +125 -0
  49. package/src/prelude/values/helpers/iterator.hpp +107 -0
  50. package/src/prelude/values/helpers/object.hpp +64 -0
  51. package/src/prelude/values/helpers/promise.hpp +181 -0
  52. package/src/prelude/values/helpers/string.hpp +50 -0
  53. package/src/prelude/values/helpers/symbol.hpp +23 -0
  54. package/src/prelude/values/iterator.hpp +96 -0
  55. package/src/prelude/values/object.hpp +8 -3
  56. package/src/prelude/values/promise.hpp +73 -0
  57. package/src/prelude/values/prototypes/array.hpp +23 -16
  58. package/src/prelude/values/prototypes/function.hpp +26 -0
  59. package/src/prelude/values/prototypes/iterator.hpp +58 -0
  60. package/src/prelude/values/prototypes/object.hpp +26 -0
  61. package/src/prelude/values/prototypes/promise.hpp +124 -0
  62. package/src/prelude/values/prototypes/string.hpp +366 -357
  63. package/src/prelude/values/prototypes/symbol.hpp +41 -0
  64. package/src/prelude/values/string.hpp +25 -0
  65. package/src/prelude/values/symbol.hpp +102 -0
  66. package/src/prelude/access.hpp +0 -86
  67. package/src/prelude/error.hpp +0 -31
  68. package/src/prelude/error_helpers.hpp +0 -59
  69. package/src/prelude/log_string.hpp +0 -403
  70. package/src/prelude/values/operators/function.hpp +0 -34
  71. package/src/prelude/values/operators/object.hpp +0 -34
  72. package/src/prelude/well_known_symbols.hpp +0 -10
@@ -0,0 +1,96 @@
1
+ #pragma once
2
+
3
+ #include "types.hpp"
4
+ #include <coroutine>
5
+ #include <optional>
6
+ #include <iostream>
7
+ #include <utility>
8
+ #include <exception>
9
+
10
+ namespace jspp
11
+ {
12
+ // Forward declaration of AnyValue
13
+ class AnyValue;
14
+
15
+ template <typename T>
16
+ class JsIterator
17
+ {
18
+ public:
19
+ struct NextResult
20
+ {
21
+ std::optional<T> value;
22
+ bool done;
23
+ };
24
+ struct promise_type
25
+ {
26
+ std::optional<T> current_value;
27
+ std::exception_ptr exception_;
28
+ T input_value;
29
+
30
+ JsIterator get_return_object()
31
+ {
32
+ return JsIterator{
33
+ std::coroutine_handle<promise_type>::from_promise(*this)};
34
+ }
35
+
36
+ std::suspend_always initial_suspend() noexcept { return {}; }
37
+
38
+ // valid js generators allow access to the return value after completion,
39
+ // so we must suspend at the end to keep the promise (and value) alive.
40
+ std::suspend_always final_suspend() noexcept { return {}; }
41
+
42
+ // Handle co_yield
43
+ template <typename From>
44
+ auto yield_value(From &&from)
45
+ {
46
+ current_value = std::forward<From>(from);
47
+ struct Awaiter
48
+ {
49
+ promise_type &p;
50
+ bool await_ready() { return false; }
51
+ void await_suspend(std::coroutine_handle<promise_type>) {}
52
+ T await_resume() { return p.input_value; }
53
+ };
54
+ return Awaiter{*this};
55
+ }
56
+
57
+ // Handle co_return
58
+ // This replaces return_void.
59
+ // It captures the final value and moves to final_suspend (implicit).
60
+ template <typename From>
61
+ void return_value(From &&from)
62
+ {
63
+ current_value = std::forward<From>(from);
64
+ }
65
+
66
+ void unhandled_exception()
67
+ {
68
+ exception_ = std::current_exception();
69
+ }
70
+ };
71
+
72
+ using handle_type = std::coroutine_handle<promise_type>;
73
+ handle_type handle;
74
+
75
+ explicit JsIterator(handle_type h) : handle(h) {}
76
+ JsIterator(JsIterator &&other) noexcept : handle(std::exchange(other.handle, nullptr)) {}
77
+
78
+ // Delete copy constructor/assignment to ensure unique ownership of the handle
79
+ JsIterator(const JsIterator &) = delete;
80
+ JsIterator &operator=(const JsIterator &) = delete;
81
+
82
+ ~JsIterator()
83
+ {
84
+ if (handle)
85
+ handle.destroy();
86
+ }
87
+
88
+ std::unordered_map<std::string, AnyValue> props;
89
+
90
+ std::string to_std_string() const;
91
+ NextResult next(const T &val = T());
92
+ std::vector<std::optional<T>> to_vector();
93
+ AnyValue get_property(const std::string &key, const AnyValue &thisVal);
94
+ AnyValue set_property(const std::string &key, const AnyValue &value, const AnyValue &thisVal);
95
+ };
96
+ }
@@ -4,14 +4,19 @@
4
4
 
5
5
  namespace jspp
6
6
  {
7
+ // Forward declaration of AnyValue
7
8
  class AnyValue;
8
9
 
9
10
  struct JsObject
10
11
  {
11
- std::unordered_map<std::string, AnyValue> props;
12
+ std::map<std::string, AnyValue> props;
13
+ std::shared_ptr<AnyValue> proto;
14
+
15
+ JsObject() : proto(nullptr) {}
16
+ explicit JsObject(const std::map<std::string, AnyValue> &p, std::shared_ptr<AnyValue> pr = nullptr) : props(p), proto(pr) {}
12
17
 
13
18
  std::string to_std_string() const;
14
- AnyValue get_property(const std::string &key);
15
- AnyValue set_property(const std::string &key, const AnyValue &value);
19
+ AnyValue get_property(const std::string &key, const AnyValue &thisVal);
20
+ AnyValue set_property(const std::string &key, const AnyValue &value, const AnyValue &thisVal);
16
21
  };
17
22
  }
@@ -0,0 +1,73 @@
1
+ #pragma once
2
+
3
+ #include "types.hpp"
4
+ #include <vector>
5
+ #include <functional>
6
+ #include <memory>
7
+ #include <variant>
8
+ #include <coroutine>
9
+ #include <unordered_map>
10
+ #include <string>
11
+
12
+ namespace jspp
13
+ {
14
+ // Forward declaration of AnyValue
15
+ class AnyValue;
16
+
17
+ enum class PromiseStatus { Pending, Fulfilled, Rejected };
18
+
19
+ struct PromiseState
20
+ {
21
+ PromiseStatus status = PromiseStatus::Pending;
22
+ std::shared_ptr<AnyValue> result; // Value if fulfilled, reason if rejected
23
+ std::vector<std::function<void(AnyValue)>> onFulfilled;
24
+ std::vector<std::function<void(AnyValue)>> onRejected;
25
+
26
+ PromiseState(); // Defined in helpers
27
+ };
28
+
29
+ struct JsPromisePromiseType; // Forward declaration
30
+
31
+ struct JsPromise
32
+ {
33
+ using promise_type = JsPromisePromiseType;
34
+
35
+ std::shared_ptr<PromiseState> state;
36
+ std::unordered_map<std::string, AnyValue> props;
37
+
38
+ JsPromise();
39
+
40
+ // --- Promise Logic ---
41
+ void resolve(const AnyValue& value);
42
+ void reject(const AnyValue& reason);
43
+ void then(std::function<void(AnyValue)> onFulfilled, std::function<void(AnyValue)> onRejected = nullptr);
44
+
45
+ // --- Methods ---
46
+ std::string to_std_string() const;
47
+ AnyValue get_property(const std::string& key, const AnyValue& thisVal);
48
+ AnyValue set_property(const std::string& key, const AnyValue& value, const AnyValue& thisVal);
49
+ };
50
+
51
+ struct JsPromisePromiseType {
52
+ JsPromise promise;
53
+
54
+ JsPromise get_return_object() { return promise; }
55
+ std::suspend_never initial_suspend() { return {}; }
56
+ std::suspend_never final_suspend() noexcept { return {}; }
57
+
58
+ void return_value(const AnyValue& val);
59
+
60
+ void unhandled_exception();
61
+
62
+ // await_transform for AnyValue
63
+ auto await_transform(const AnyValue& value);
64
+ };
65
+
66
+ // Awaiter for AnyValue
67
+ struct AnyValueAwaiter {
68
+ const AnyValue& value; // Reference to the value being awaited
69
+ bool await_ready();
70
+ void await_suspend(std::coroutine_handle<> h);
71
+ AnyValue await_resume();
72
+ };
73
+ }
@@ -3,8 +3,8 @@
3
3
  #include "types.hpp"
4
4
  #include "values/array.hpp"
5
5
  #include "any_value.hpp"
6
- #include "error.hpp"
7
- #include "operators.hpp"
6
+ #include "exception.hpp"
7
+ #include "utils/operators.hpp"
8
8
  #include <algorithm>
9
9
  #include <vector>
10
10
 
@@ -14,24 +14,31 @@ namespace jspp
14
14
  {
15
15
  inline std::optional<AnyValue> get(const std::string &key, JsArray *self)
16
16
  {
17
-
18
17
  // --- toString() method ---
19
- if (key == "toString")
18
+ if (key == "toString" )
20
19
  {
21
- return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
20
+ return AnyValue::make_function([self](const AnyValue &thisVal, const std::vector<AnyValue> &_) -> AnyValue
22
21
  { return AnyValue::make_string(self->to_std_string()); },
23
22
  key);
24
23
  }
25
24
 
25
+ // --- [Symbol.iterator]() method ---
26
+ if (key == WellKnownSymbols::iterator->key)
27
+ {
28
+ return AnyValue::make_generator([self](const AnyValue &thisVal, const std::vector<AnyValue> &_) -> AnyValue
29
+ { return AnyValue::from_iterator(self->get_iterator()); },
30
+ key);
31
+ }
32
+
26
33
  // --- length property ---
27
34
  if (key == "length")
28
35
  {
29
- auto getter = [&self](const std::vector<AnyValue> &args) -> AnyValue
36
+ auto getter = [self](const AnyValue &thisVal, const std::vector<AnyValue> &args) -> AnyValue
30
37
  {
31
38
  return AnyValue::make_number(self->length);
32
39
  };
33
40
 
34
- auto setter = [&self](const std::vector<AnyValue> &args) -> AnyValue
41
+ auto setter = [self](const AnyValue &thisVal, const std::vector<AnyValue> &args) -> AnyValue
35
42
  {
36
43
  if (args.empty())
37
44
  {
@@ -43,7 +50,7 @@ namespace jspp
43
50
 
44
51
  if (new_len_double < 0 || std::isnan(new_len_double) || std::isinf(new_len_double) || new_len_double != static_cast<uint64_t>(new_len_double))
45
52
  {
46
- throw RuntimeError::make_error("Invalid array length", "RangeError");
53
+ throw Exception::make_exception("Invalid array length", "RangeError");
47
54
  }
48
55
  uint64_t new_len = static_cast<uint64_t>(new_len_double);
49
56
 
@@ -79,7 +86,7 @@ namespace jspp
79
86
  // --- push() method ---
80
87
  if (key == "push")
81
88
  {
82
- return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
89
+ return AnyValue::make_function([self](const AnyValue &thisVal, const std::vector<AnyValue> &args) -> AnyValue
83
90
  {
84
91
  for (const auto &arg : args)
85
92
  {
@@ -92,7 +99,7 @@ namespace jspp
92
99
  // --- pop() method ---
93
100
  if (key == "pop")
94
101
  {
95
- return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
102
+ return AnyValue::make_function([self](const AnyValue &thisVal, const std::vector<AnyValue> &args) -> AnyValue
96
103
  {
97
104
  if (self->length == 0)
98
105
  {
@@ -117,7 +124,7 @@ namespace jspp
117
124
  // --- shift() method ---
118
125
  if (key == "shift")
119
126
  {
120
- return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
127
+ return AnyValue::make_function([self](const AnyValue &thisVal, const std::vector<AnyValue> &args) -> AnyValue
121
128
  {
122
129
  if (self->length == 0)
123
130
  {
@@ -148,7 +155,7 @@ namespace jspp
148
155
  // --- unshift() method ---
149
156
  if (key == "unshift")
150
157
  {
151
- return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
158
+ return AnyValue::make_function([self](const AnyValue &thisVal, const std::vector<AnyValue> &args) -> AnyValue
152
159
  {
153
160
  size_t args_count = args.size();
154
161
  if (args_count == 0)
@@ -175,7 +182,7 @@ namespace jspp
175
182
  // --- join() method ---
176
183
  if (key == "join")
177
184
  {
178
- return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
185
+ return AnyValue::make_function([self](const AnyValue &thisVal, const std::vector<AnyValue> &args) -> AnyValue
179
186
  {
180
187
  std::string sep = ",";
181
188
  if (!args.empty() && !args[0].is_undefined())
@@ -203,11 +210,11 @@ namespace jspp
203
210
  // --- forEach() method ---
204
211
  if (key == "forEach")
205
212
  {
206
- return AnyValue::make_function([&self](const std::vector<AnyValue> &args) -> AnyValue
213
+ return AnyValue::make_function([self](const AnyValue &thisVal, const std::vector<AnyValue> &args) -> AnyValue
207
214
  {
208
215
  if (args.empty() || !args[0].is_function())
209
216
  {
210
- throw RuntimeError::make_error("callback is not a function", "TypeError");
217
+ throw Exception::make_exception("callback is not a function", "TypeError");
211
218
  }
212
219
  auto callback = args[0].as_function();
213
220
  for (uint64_t i = 0; i < self->length; ++i)
@@ -215,7 +222,7 @@ namespace jspp
215
222
  AnyValue val = self->get_property(static_cast<uint32_t>(i));
216
223
  if (!val.is_undefined())
217
224
  { // forEach skips empty slots
218
- callback->call({val, AnyValue::make_number(i)});
225
+ callback->call(thisVal, {val, AnyValue::make_number(i)});
219
226
  }
220
227
  }
221
228
  return AnyValue::make_undefined(); },
@@ -0,0 +1,26 @@
1
+ #pragma once
2
+
3
+ #include "types.hpp"
4
+ #include "values/function.hpp"
5
+ #include "any_value.hpp"
6
+ #include "exception.hpp"
7
+ #include "utils/operators.hpp"
8
+
9
+ namespace jspp
10
+ {
11
+ namespace FunctionPrototypes
12
+ {
13
+ inline std::optional<AnyValue> get(const std::string &key, JsFunction *self)
14
+ {
15
+ // --- toString() method ---
16
+ if (key == "toString" )
17
+ {
18
+ return AnyValue::make_function([self](const AnyValue &thisVal, const std::vector<AnyValue> &_) -> AnyValue
19
+ { return AnyValue::make_string(self->to_std_string()); },
20
+ key);
21
+ }
22
+
23
+ return std::nullopt;
24
+ }
25
+ }
26
+ }
@@ -0,0 +1,58 @@
1
+ #pragma once
2
+
3
+ #include "types.hpp"
4
+ #include "values/iterator.hpp"
5
+ #include "any_value.hpp"
6
+ #include "exception.hpp"
7
+ #include "utils/operators.hpp"
8
+
9
+ namespace jspp
10
+ {
11
+ namespace IteratorPrototypes
12
+ {
13
+ inline std::optional<AnyValue> get(const std::string &key, JsIterator<AnyValue> *self)
14
+ {
15
+ // --- toString() method ---
16
+ if (key == "toString" )
17
+ {
18
+ return AnyValue::make_function([self](const AnyValue &thisVal, const std::vector<AnyValue> &) -> AnyValue
19
+ { return AnyValue::make_string(self->to_std_string()); },
20
+ key);
21
+ }
22
+ // --- [Symbol.iterator]() method ---
23
+ if (key == WellKnownSymbols::iterator->key)
24
+ {
25
+ return AnyValue::make_generator([self](const AnyValue &thisVal, const std::vector<AnyValue> &) -> AnyValue
26
+ {
27
+ // An iterator's iterator is itself.
28
+ // We need to return an AnyValue that holds a shared_ptr to this JsIterator.
29
+ // Since we only have a raw pointer `self`, we can't directly make a new shared_ptr.
30
+ // We'll return an AnyValue wrapping the raw pointer for now.
31
+ // This relies on the calling context to manage lifetime, which is true for `for-of`.
32
+ // A better solution might involve passing a shared_ptr to `self` into the prototype getters.
33
+ // For now, let's assume the object containing the iterator is alive.
34
+ return AnyValue::from_iterator_ref(self); },
35
+ key);
36
+ }
37
+ // --- next() method ---
38
+ if (key == "next")
39
+ {
40
+ return AnyValue::make_function([self](const AnyValue &thisVal, const std::vector<AnyValue> &args) -> AnyValue
41
+ {
42
+ AnyValue val = args.empty() ? AnyValue::make_undefined() : args[0];
43
+ auto res = self->next(val);
44
+ return AnyValue::make_object({{"value",res.value.value_or(AnyValue::make_undefined())},{"done",AnyValue::make_boolean(res.done)},}); },
45
+ key);
46
+ }
47
+ // --- toArray() method ---
48
+ if (key == "toArray")
49
+ {
50
+ return AnyValue::make_function([self](const AnyValue &thisVal, const std::vector<AnyValue> &) -> AnyValue
51
+ { return AnyValue::make_array(self->to_vector()); },
52
+ key);
53
+ }
54
+
55
+ return std::nullopt;
56
+ }
57
+ }
58
+ }
@@ -0,0 +1,26 @@
1
+ #pragma once
2
+
3
+ #include "types.hpp"
4
+ #include "values/object.hpp"
5
+ #include "any_value.hpp"
6
+ #include "exception.hpp"
7
+ #include "utils/operators.hpp"
8
+
9
+ namespace jspp
10
+ {
11
+ namespace ObjectPrototypes
12
+ {
13
+ inline std::optional<AnyValue> get(const std::string &key, JsObject *self)
14
+ {
15
+ // --- toString() method ---
16
+ if (key == "toString" )
17
+ {
18
+ return AnyValue::make_function([self](const AnyValue &thisVal, const std::vector<AnyValue> &_) -> AnyValue
19
+ { return AnyValue::make_string(self->to_std_string()); },
20
+ key);
21
+ }
22
+
23
+ return std::nullopt;
24
+ }
25
+ }
26
+ }
@@ -0,0 +1,124 @@
1
+ #pragma once
2
+
3
+ #include "types.hpp"
4
+ #include "values/promise.hpp"
5
+ #include "any_value.hpp"
6
+
7
+ namespace jspp {
8
+ namespace PromisePrototypes {
9
+ inline std::optional<AnyValue> get(const std::string& key, JsPromise* self) {
10
+
11
+ if (key == "then") {
12
+ return AnyValue::make_function([self](const AnyValue& thisVal, const std::vector<AnyValue>& args) -> AnyValue {
13
+ AnyValue onFulfilled = (args.size() > 0 && args[0].is_function()) ? args[0] : AnyValue::make_undefined();
14
+ AnyValue onRejected = (args.size() > 1 && args[1].is_function()) ? args[1] : AnyValue::make_undefined();
15
+
16
+ // "then" returns a new Promise
17
+ JsPromise newPromise;
18
+ AnyValue newPromiseVal = AnyValue::make_promise(newPromise);
19
+
20
+ // Capture shared pointer to the new promise's state to keep it alive and modify it
21
+ auto newPromiseState = newPromise.state;
22
+ // Helper wrapper to interact with state
23
+ auto resolveNew = [newPromiseState](const AnyValue& v) {
24
+ JsPromise p; p.state = newPromiseState;
25
+ p.resolve(v);
26
+ };
27
+ auto rejectNew = [newPromiseState](const AnyValue& r) {
28
+ JsPromise p; p.state = newPromiseState;
29
+ p.reject(r);
30
+ };
31
+
32
+
33
+ // Resolve handler
34
+ auto resolveHandler = [resolveNew, rejectNew, onFulfilled](AnyValue val) mutable {
35
+ if (onFulfilled.is_function()) {
36
+ try {
37
+ auto res = onFulfilled.as_function()->call(AnyValue::make_undefined(), {val});
38
+ if (res.is_promise()) {
39
+ // Chaining: newPromise follows res
40
+ auto chained = res.as_promise();
41
+ chained->then(
42
+ [resolveNew](AnyValue v) { resolveNew(v); },
43
+ [rejectNew](AnyValue e) { rejectNew(e); }
44
+ );
45
+ } else {
46
+ resolveNew(res);
47
+ }
48
+ } catch (const Exception& e) {
49
+ rejectNew(*e.data);
50
+ } catch (...) {
51
+ rejectNew(AnyValue::make_string("Unknown error"));
52
+ }
53
+ } else {
54
+ resolveNew(val); // Fallthrough
55
+ }
56
+ };
57
+
58
+ // Reject handler
59
+ auto rejectHandler = [resolveNew, rejectNew, onRejected](AnyValue reason) mutable {
60
+ if (onRejected.is_function()) {
61
+ try {
62
+ auto res = onRejected.as_function()->call(AnyValue::make_undefined(), {reason});
63
+ if (res.is_promise()) {
64
+ auto chained = res.as_promise();
65
+ chained->then(
66
+ [resolveNew](AnyValue v) { resolveNew(v); },
67
+ [rejectNew](AnyValue e) { rejectNew(e); }
68
+ );
69
+ } else {
70
+ resolveNew(res); // Recovered
71
+ }
72
+ } catch (const Exception& e) {
73
+ rejectNew(*e.data);
74
+ } catch (...) {
75
+ rejectNew(AnyValue::make_string("Unknown error"));
76
+ }
77
+ } else {
78
+ rejectNew(reason); // Fallthrough
79
+ }
80
+ };
81
+
82
+ self->then(resolveHandler, rejectHandler);
83
+ return newPromiseVal;
84
+ }, "then");
85
+ }
86
+
87
+ if (key == "catch") {
88
+ return AnyValue::make_function([self](const AnyValue& thisVal, const std::vector<AnyValue>& args) -> AnyValue {
89
+ // catch(onRejected) is then(undefined, onRejected)
90
+ AnyValue onRejected = (args.size() > 0 && args[0].is_function()) ? args[0] : AnyValue::make_undefined();
91
+ return thisVal.get_own_property("then").as_function()->call(thisVal, {AnyValue::make_undefined(), onRejected});
92
+ }, "catch");
93
+ }
94
+
95
+ if (key == "finally") {
96
+ return AnyValue::make_function([self](const AnyValue& thisVal, const std::vector<AnyValue>& args) -> AnyValue {
97
+ AnyValue onFinally = (args.size() > 0 && args[0].is_function()) ? args[0] : AnyValue::make_undefined();
98
+
99
+ // finally(onFinally) returns a promise that passes through value/reason,
100
+ // but executes onFinally first.
101
+
102
+ return thisVal.get_own_property("then").as_function()->call(thisVal, {
103
+ AnyValue::make_function([onFinally](const AnyValue&, const std::vector<AnyValue>& args) -> AnyValue {
104
+ AnyValue val = args.empty() ? AnyValue::make_undefined() : args[0];
105
+ if (onFinally.is_function()) {
106
+ onFinally.as_function()->call(AnyValue::make_undefined(), {});
107
+ }
108
+ return val;
109
+ }, ""),
110
+ AnyValue::make_function([onFinally](const AnyValue&, const std::vector<AnyValue>& args) -> AnyValue {
111
+ AnyValue reason = args.empty() ? AnyValue::make_undefined() : args[0];
112
+ if (onFinally.is_function()) {
113
+ onFinally.as_function()->call(AnyValue::make_undefined(), {});
114
+ }
115
+ throw Exception(reason);
116
+ }, "")
117
+ });
118
+ }, "finally");
119
+ }
120
+
121
+ return std::nullopt;
122
+ }
123
+ }
124
+ }