@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.
- package/LICENSE +25 -25
- package/README.md +20 -12
- package/dist/analysis/scope.js +5 -3
- package/dist/analysis/typeAnalyzer.js +21 -25
- package/dist/cli/index.js +14 -4
- package/dist/cli/utils.js +61 -0
- package/dist/core/codegen/class-handlers.js +6 -6
- package/dist/core/codegen/control-flow-handlers.js +10 -9
- package/dist/core/codegen/declaration-handlers.js +10 -3
- package/dist/core/codegen/destructuring-handlers.js +9 -4
- package/dist/core/codegen/expression-handlers.js +40 -29
- package/dist/core/codegen/function-handlers.js +78 -12
- package/dist/core/codegen/helpers.js +91 -14
- package/dist/core/codegen/index.js +4 -2
- package/dist/core/codegen/statement-handlers.js +9 -7
- package/package.json +2 -2
- package/scripts/precompile-headers.ts +249 -50
- package/scripts/setup-compiler.ts +63 -63
- package/src/prelude/any_value.cpp +636 -0
- package/src/prelude/any_value.hpp +369 -362
- package/src/prelude/{exception_helpers.hpp → exception.cpp} +53 -53
- package/src/prelude/exception.hpp +27 -27
- package/src/prelude/iterator_instantiations.hpp +10 -0
- package/src/prelude/{index.hpp → jspp.hpp} +10 -16
- package/src/prelude/library/array.cpp +191 -0
- package/src/prelude/library/array.hpp +13 -186
- package/src/prelude/library/console.cpp +125 -0
- package/src/prelude/library/console.hpp +24 -112
- package/src/prelude/library/error.cpp +100 -0
- package/src/prelude/library/error.hpp +13 -113
- package/src/prelude/library/function.cpp +69 -0
- package/src/prelude/library/function.hpp +11 -10
- package/src/prelude/library/global.cpp +96 -0
- package/src/prelude/library/global.hpp +12 -28
- package/src/prelude/library/global_usings.hpp +15 -0
- package/src/prelude/library/math.cpp +258 -0
- package/src/prelude/library/math.hpp +26 -308
- package/src/prelude/library/object.cpp +379 -0
- package/src/prelude/library/object.hpp +14 -276
- package/src/prelude/library/performance.cpp +21 -0
- package/src/prelude/library/performance.hpp +5 -20
- package/src/prelude/library/process.cpp +38 -0
- package/src/prelude/library/process.hpp +11 -39
- package/src/prelude/library/promise.cpp +131 -0
- package/src/prelude/library/promise.hpp +12 -123
- package/src/prelude/library/symbol.cpp +56 -0
- package/src/prelude/library/symbol.hpp +11 -52
- package/src/prelude/library/timer.cpp +88 -0
- package/src/prelude/library/timer.hpp +16 -92
- package/src/prelude/runtime.cpp +19 -0
- package/src/prelude/types.hpp +184 -179
- package/src/prelude/utils/access.hpp +502 -411
- package/src/prelude/utils/assignment_operators.hpp +99 -99
- package/src/prelude/utils/log_any_value/array.hpp +61 -40
- package/src/prelude/utils/log_any_value/function.hpp +39 -39
- package/src/prelude/utils/log_any_value/object.hpp +60 -3
- package/src/prelude/utils/operators.hpp +351 -336
- package/src/prelude/utils/operators_primitive.hpp +336 -336
- package/src/prelude/utils/well_known_symbols.hpp +24 -24
- package/src/prelude/values/array.cpp +1399 -0
- package/src/prelude/values/array.hpp +4 -1
- package/src/prelude/values/async_iterator.cpp +251 -0
- package/src/prelude/values/async_iterator.hpp +111 -83
- package/src/prelude/values/function.cpp +262 -0
- package/src/prelude/values/function.hpp +62 -82
- package/src/prelude/values/iterator.cpp +309 -0
- package/src/prelude/values/iterator.hpp +33 -64
- package/src/prelude/values/number.cpp +176 -0
- package/src/prelude/values/object.cpp +159 -0
- package/src/prelude/values/object.hpp +4 -0
- package/src/prelude/values/promise.cpp +479 -0
- package/src/prelude/values/promise.hpp +79 -72
- package/src/prelude/values/prototypes/array.hpp +46 -1336
- package/src/prelude/values/prototypes/async_iterator.hpp +19 -61
- package/src/prelude/values/prototypes/function.hpp +7 -46
- package/src/prelude/values/prototypes/iterator.hpp +25 -201
- package/src/prelude/values/prototypes/number.hpp +23 -210
- package/src/prelude/values/prototypes/object.hpp +7 -23
- package/src/prelude/values/prototypes/promise.hpp +18 -196
- package/src/prelude/values/prototypes/string.hpp +39 -542
- package/src/prelude/values/prototypes/symbol.hpp +9 -70
- package/src/prelude/values/shape.hpp +52 -52
- package/src/prelude/values/string.cpp +485 -0
- package/src/prelude/values/string.hpp +25 -26
- package/src/prelude/values/symbol.cpp +89 -0
- package/src/prelude/values/symbol.hpp +101 -101
- package/src/prelude/any_value_access.hpp +0 -170
- package/src/prelude/any_value_defines.hpp +0 -190
- package/src/prelude/any_value_helpers.hpp +0 -374
- package/src/prelude/values/helpers/array.hpp +0 -209
- package/src/prelude/values/helpers/async_iterator.hpp +0 -275
- package/src/prelude/values/helpers/function.hpp +0 -109
- package/src/prelude/values/helpers/iterator.hpp +0 -145
- package/src/prelude/values/helpers/object.hpp +0 -104
- package/src/prelude/values/helpers/promise.hpp +0 -254
- package/src/prelude/values/helpers/string.hpp +0 -61
- 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
|