@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.
- package/README.md +5 -3
- package/dist/analysis/scope.js +38 -15
- package/dist/analysis/typeAnalyzer.js +257 -23
- package/dist/ast/types.js +6 -0
- package/dist/cli.js +3 -4
- package/dist/core/codegen/class-handlers.js +127 -0
- package/dist/core/codegen/control-flow-handlers.js +464 -0
- package/dist/core/codegen/declaration-handlers.js +31 -14
- package/dist/core/codegen/expression-handlers.js +432 -116
- package/dist/core/codegen/function-handlers.js +110 -13
- package/dist/core/codegen/helpers.js +76 -8
- package/dist/core/codegen/index.js +18 -5
- package/dist/core/codegen/literal-handlers.js +3 -0
- package/dist/core/codegen/statement-handlers.js +152 -186
- package/dist/core/codegen/visitor.js +35 -3
- package/package.json +3 -3
- package/src/prelude/any_value.hpp +658 -734
- package/src/prelude/any_value_access.hpp +103 -0
- package/src/prelude/any_value_defines.hpp +151 -0
- package/src/prelude/any_value_helpers.hpp +246 -0
- package/src/prelude/exception.hpp +31 -0
- package/src/prelude/exception_helpers.hpp +49 -0
- package/src/prelude/index.hpp +35 -12
- package/src/prelude/library/console.hpp +20 -20
- package/src/prelude/library/error.hpp +111 -0
- package/src/prelude/library/global.hpp +15 -4
- package/src/prelude/library/performance.hpp +25 -0
- package/src/prelude/library/promise.hpp +121 -0
- package/src/prelude/library/symbol.hpp +60 -4
- package/src/prelude/library/timer.hpp +92 -0
- package/src/prelude/scheduler.hpp +145 -0
- package/src/prelude/types.hpp +33 -6
- package/src/prelude/utils/access.hpp +174 -0
- package/src/prelude/utils/log_any_value/array.hpp +245 -0
- package/src/prelude/utils/log_any_value/config.hpp +32 -0
- package/src/prelude/utils/log_any_value/function.hpp +37 -0
- package/src/prelude/utils/log_any_value/fwd.hpp +15 -0
- package/src/prelude/utils/log_any_value/helpers.hpp +62 -0
- package/src/prelude/utils/log_any_value/log_any_value.hpp +94 -0
- package/src/prelude/utils/log_any_value/object.hpp +119 -0
- package/src/prelude/utils/log_any_value/primitives.hpp +41 -0
- package/src/prelude/{operators.hpp → utils/operators.hpp} +31 -12
- package/src/prelude/utils/well_known_symbols.hpp +13 -0
- package/src/prelude/values/array.hpp +5 -2
- package/src/prelude/{descriptors.hpp → values/descriptors.hpp} +2 -2
- package/src/prelude/values/function.hpp +76 -19
- package/src/prelude/values/{operators → helpers}/array.hpp +30 -14
- package/src/prelude/values/helpers/function.hpp +125 -0
- package/src/prelude/values/helpers/iterator.hpp +107 -0
- package/src/prelude/values/helpers/object.hpp +64 -0
- package/src/prelude/values/helpers/promise.hpp +181 -0
- package/src/prelude/values/helpers/string.hpp +50 -0
- package/src/prelude/values/helpers/symbol.hpp +23 -0
- package/src/prelude/values/iterator.hpp +96 -0
- package/src/prelude/values/object.hpp +8 -3
- package/src/prelude/values/promise.hpp +73 -0
- package/src/prelude/values/prototypes/array.hpp +23 -16
- package/src/prelude/values/prototypes/function.hpp +26 -0
- package/src/prelude/values/prototypes/iterator.hpp +58 -0
- package/src/prelude/values/prototypes/object.hpp +26 -0
- package/src/prelude/values/prototypes/promise.hpp +124 -0
- package/src/prelude/values/prototypes/string.hpp +366 -357
- package/src/prelude/values/prototypes/symbol.hpp +41 -0
- package/src/prelude/values/string.hpp +25 -0
- package/src/prelude/values/symbol.hpp +102 -0
- package/src/prelude/access.hpp +0 -86
- package/src/prelude/error.hpp +0 -31
- package/src/prelude/error_helpers.hpp +0 -59
- package/src/prelude/log_string.hpp +0 -403
- package/src/prelude/values/operators/function.hpp +0 -34
- package/src/prelude/values/operators/object.hpp +0 -34
- 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::
|
|
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 "
|
|
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([
|
|
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 = [
|
|
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 = [
|
|
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
|
|
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([
|
|
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([
|
|
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([
|
|
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([
|
|
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([
|
|
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([
|
|
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
|
|
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
|
+
}
|