@ugo-studio/jspp 0.1.3 → 0.1.5
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 +2 -2
- package/dist/analysis/scope.js +33 -4
- package/dist/analysis/typeAnalyzer.js +260 -21
- package/dist/ast/symbols.js +29 -0
- package/dist/cli-utils/args.js +57 -0
- package/dist/cli-utils/colors.js +9 -0
- package/dist/cli-utils/file-utils.js +20 -0
- package/dist/cli-utils/spinner.js +55 -0
- package/dist/cli.js +105 -31
- package/dist/core/codegen/class-handlers.js +131 -0
- package/dist/core/codegen/control-flow-handlers.js +474 -0
- package/dist/core/codegen/declaration-handlers.js +36 -15
- package/dist/core/codegen/expression-handlers.js +579 -125
- package/dist/core/codegen/function-handlers.js +222 -37
- package/dist/core/codegen/helpers.js +158 -4
- package/dist/core/codegen/index.js +20 -8
- package/dist/core/codegen/literal-handlers.js +18 -6
- package/dist/core/codegen/statement-handlers.js +171 -228
- package/dist/core/codegen/visitor.js +31 -3
- package/package.json +3 -3
- package/src/prelude/any_value.hpp +510 -633
- package/src/prelude/any_value_access.hpp +151 -0
- package/src/prelude/any_value_defines.hpp +190 -0
- package/src/prelude/any_value_helpers.hpp +139 -225
- package/src/prelude/exception.hpp +32 -0
- package/src/prelude/exception_helpers.hpp +49 -0
- package/src/prelude/index.hpp +25 -9
- package/src/prelude/library/array.hpp +190 -0
- package/src/prelude/library/console.hpp +14 -13
- package/src/prelude/library/error.hpp +113 -0
- package/src/prelude/library/function.hpp +10 -0
- package/src/prelude/library/global.hpp +35 -4
- package/src/prelude/library/math.hpp +308 -0
- package/src/prelude/library/object.hpp +288 -0
- package/src/prelude/library/performance.hpp +2 -2
- package/src/prelude/library/process.hpp +39 -0
- package/src/prelude/library/promise.hpp +131 -0
- package/src/prelude/library/symbol.hpp +46 -59
- package/src/prelude/library/timer.hpp +92 -0
- package/src/prelude/scheduler.hpp +145 -0
- package/src/prelude/types.hpp +58 -1
- package/src/prelude/utils/access.hpp +345 -0
- package/src/prelude/utils/assignment_operators.hpp +99 -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 +39 -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 +136 -0
- package/src/prelude/utils/log_any_value/primitives.hpp +43 -0
- package/src/prelude/utils/operators.hpp +751 -0
- package/src/prelude/utils/well_known_symbols.hpp +25 -0
- package/src/prelude/values/array.hpp +10 -7
- package/src/prelude/{descriptors.hpp → values/descriptors.hpp} +2 -2
- package/src/prelude/values/function.hpp +85 -51
- package/src/prelude/values/helpers/array.hpp +80 -35
- package/src/prelude/values/helpers/function.hpp +110 -77
- package/src/prelude/values/helpers/iterator.hpp +16 -10
- package/src/prelude/values/helpers/object.hpp +85 -10
- package/src/prelude/values/helpers/promise.hpp +181 -0
- package/src/prelude/values/helpers/string.hpp +3 -3
- package/src/prelude/values/helpers/symbol.hpp +2 -2
- package/src/prelude/values/iterator.hpp +14 -6
- package/src/prelude/values/object.hpp +14 -3
- package/src/prelude/values/promise.hpp +73 -0
- package/src/prelude/values/prototypes/array.hpp +855 -16
- package/src/prelude/values/prototypes/function.hpp +4 -4
- package/src/prelude/values/prototypes/iterator.hpp +11 -10
- package/src/prelude/values/prototypes/number.hpp +153 -0
- package/src/prelude/values/prototypes/object.hpp +26 -0
- package/src/prelude/values/prototypes/promise.hpp +134 -0
- package/src/prelude/values/prototypes/string.hpp +29 -29
- package/src/prelude/values/prototypes/symbol.hpp +22 -3
- package/src/prelude/values/shape.hpp +52 -0
- package/src/prelude/values/string.hpp +1 -1
- package/src/prelude/values/symbol.hpp +1 -1
- package/src/prelude/access.hpp +0 -91
- package/src/prelude/error.hpp +0 -31
- package/src/prelude/error_helpers.hpp +0 -59
- package/src/prelude/log_string.hpp +0 -407
- package/src/prelude/operators.hpp +0 -256
- package/src/prelude/well_known_symbols.hpp +0 -14
|
@@ -11,12 +11,14 @@ std::string jspp::JsIterator<T>::to_std_string() const
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
template <typename T>
|
|
14
|
-
jspp::JsIterator<T>::NextResult jspp::JsIterator<T>::next()
|
|
14
|
+
jspp::JsIterator<T>::NextResult jspp::JsIterator<T>::next(const T &val)
|
|
15
15
|
{
|
|
16
16
|
// If the generator is already finished or invalid, return {undefined, true}
|
|
17
17
|
if (!handle || handle.done())
|
|
18
18
|
return {std::nullopt, true};
|
|
19
19
|
|
|
20
|
+
handle.promise().input_value = val;
|
|
21
|
+
|
|
20
22
|
// Resume execution until next co_yield or co_return
|
|
21
23
|
handle.resume();
|
|
22
24
|
|
|
@@ -33,9 +35,9 @@ jspp::JsIterator<T>::NextResult jspp::JsIterator<T>::next()
|
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
template <typename T>
|
|
36
|
-
std::vector<
|
|
38
|
+
std::vector<T> jspp::JsIterator<T>::to_vector()
|
|
37
39
|
{
|
|
38
|
-
std::vector<
|
|
40
|
+
std::vector<T> result;
|
|
39
41
|
while (true)
|
|
40
42
|
{
|
|
41
43
|
auto next = this->next();
|
|
@@ -43,13 +45,13 @@ std::vector<std::optional<T>> jspp::JsIterator<T>::to_vector()
|
|
|
43
45
|
{
|
|
44
46
|
break;
|
|
45
47
|
}
|
|
46
|
-
result.push_back(next.value);
|
|
48
|
+
result.push_back(next.value.value_or(AnyValue::make_undefined()));
|
|
47
49
|
}
|
|
48
50
|
return result;
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
template <typename T>
|
|
52
|
-
jspp::AnyValue jspp::JsIterator<T>::get_property(const std::string &key)
|
|
54
|
+
jspp::AnyValue jspp::JsIterator<T>::get_property(const std::string &key, const AnyValue &thisVal)
|
|
53
55
|
{
|
|
54
56
|
auto it = props.find(key);
|
|
55
57
|
if (it == props.end())
|
|
@@ -60,18 +62,18 @@ jspp::AnyValue jspp::JsIterator<T>::get_property(const std::string &key)
|
|
|
60
62
|
auto proto_it = IteratorPrototypes::get(key, this);
|
|
61
63
|
if (proto_it.has_value())
|
|
62
64
|
{
|
|
63
|
-
return AnyValue::resolve_property_for_read(proto_it.value());
|
|
65
|
+
return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key);
|
|
64
66
|
}
|
|
65
67
|
}
|
|
66
68
|
// prototype not found
|
|
67
69
|
return jspp::AnyValue::make_undefined();
|
|
68
70
|
}
|
|
69
71
|
|
|
70
|
-
return jspp::AnyValue::resolve_property_for_read(it->second);
|
|
72
|
+
return jspp::AnyValue::resolve_property_for_read(it->second, thisVal, key);
|
|
71
73
|
}
|
|
72
74
|
|
|
73
75
|
template <typename T>
|
|
74
|
-
jspp::AnyValue jspp::JsIterator<T>::set_property(const std::string &key, const AnyValue &value)
|
|
76
|
+
jspp::AnyValue jspp::JsIterator<T>::set_property(const std::string &key, const AnyValue &value, const AnyValue &thisVal)
|
|
75
77
|
{
|
|
76
78
|
// set prototype property if accessor descriptor
|
|
77
79
|
if constexpr (std::is_same_v<T, AnyValue>)
|
|
@@ -82,7 +84,11 @@ jspp::AnyValue jspp::JsIterator<T>::set_property(const std::string &key, const A
|
|
|
82
84
|
auto proto_value = proto_it.value();
|
|
83
85
|
if (proto_value.is_accessor_descriptor())
|
|
84
86
|
{
|
|
85
|
-
return AnyValue::resolve_property_for_write(
|
|
87
|
+
return AnyValue::resolve_property_for_write(proto_value, thisVal, value, key);
|
|
88
|
+
}
|
|
89
|
+
if (proto_value.is_data_descriptor() && !proto_value.as_data_descriptor()->writable)
|
|
90
|
+
{
|
|
91
|
+
return AnyValue::resolve_property_for_write(proto_value, thisVal, value, key);
|
|
86
92
|
}
|
|
87
93
|
}
|
|
88
94
|
}
|
|
@@ -91,7 +97,7 @@ jspp::AnyValue jspp::JsIterator<T>::set_property(const std::string &key, const A
|
|
|
91
97
|
auto it = props.find(key);
|
|
92
98
|
if (it != props.end())
|
|
93
99
|
{
|
|
94
|
-
return jspp::AnyValue::resolve_property_for_write(it->second, value);
|
|
100
|
+
return jspp::AnyValue::resolve_property_for_write(it->second, thisVal, value, key);
|
|
95
101
|
}
|
|
96
102
|
else
|
|
97
103
|
{
|
|
@@ -4,31 +4,106 @@
|
|
|
4
4
|
#include "values/object.hpp"
|
|
5
5
|
#include "any_value.hpp"
|
|
6
6
|
|
|
7
|
+
namespace jspp {
|
|
8
|
+
JsObject::JsObject() : shape(Shape::empty_shape()), proto(nullptr) {}
|
|
9
|
+
|
|
10
|
+
JsObject::JsObject(std::initializer_list<std::pair<std::string, AnyValue>> p, std::shared_ptr<AnyValue> pr) : proto(pr) {
|
|
11
|
+
shape = Shape::empty_shape();
|
|
12
|
+
storage.reserve(p.size());
|
|
13
|
+
for (const auto& pair : p) {
|
|
14
|
+
shape = shape->transition(pair.first);
|
|
15
|
+
storage.push_back(pair.second);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
JsObject::JsObject(const std::map<std::string, AnyValue> &p, std::shared_ptr<AnyValue> pr) : proto(pr) {
|
|
20
|
+
shape = Shape::empty_shape();
|
|
21
|
+
storage.reserve(p.size());
|
|
22
|
+
for (const auto& pair : p) {
|
|
23
|
+
shape = shape->transition(pair.first);
|
|
24
|
+
storage.push_back(pair.second);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
7
29
|
std::string jspp::JsObject::to_std_string() const
|
|
8
30
|
{
|
|
9
31
|
return "[Object Object]";
|
|
10
32
|
}
|
|
11
33
|
|
|
12
|
-
|
|
34
|
+
bool jspp::JsObject::has_property(const std::string &key) const
|
|
35
|
+
{
|
|
36
|
+
if (deleted_keys.count(key)) return false;
|
|
37
|
+
|
|
38
|
+
if (shape->get_offset(key).has_value())
|
|
39
|
+
return true;
|
|
40
|
+
if (proto && !(*proto).is_null() && !(*proto).is_undefined())
|
|
41
|
+
{
|
|
42
|
+
if ((*proto).has_property(key))
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
if (ObjectPrototypes::get(key, const_cast<JsObject *>(this)).has_value())
|
|
46
|
+
return true;
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
jspp::AnyValue jspp::JsObject::get_property(const std::string &key, const AnyValue &thisVal)
|
|
13
51
|
{
|
|
14
|
-
|
|
15
|
-
|
|
52
|
+
if (deleted_keys.count(key)) return AnyValue::make_undefined();
|
|
53
|
+
|
|
54
|
+
auto offset = shape->get_offset(key);
|
|
55
|
+
if (!offset.has_value())
|
|
16
56
|
{
|
|
17
|
-
|
|
57
|
+
// check prototype chain
|
|
58
|
+
if (proto && !(*proto).is_null() && !(*proto).is_undefined())
|
|
59
|
+
{
|
|
60
|
+
if ((*proto).has_property(key))
|
|
61
|
+
{
|
|
62
|
+
return (*proto).get_property_with_receiver(key, thisVal);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// check built-in prototype methods (Object.prototype)
|
|
67
|
+
auto proto_it = ObjectPrototypes::get(key, this);
|
|
68
|
+
if (proto_it.has_value())
|
|
69
|
+
{
|
|
70
|
+
return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key);
|
|
71
|
+
}
|
|
72
|
+
// not found
|
|
73
|
+
return AnyValue::make_undefined();
|
|
18
74
|
}
|
|
19
|
-
return
|
|
75
|
+
return AnyValue::resolve_property_for_read(storage[offset.value()], thisVal, key);
|
|
20
76
|
}
|
|
21
77
|
|
|
22
|
-
jspp::AnyValue jspp::JsObject::set_property(const std::string &key, const AnyValue &value)
|
|
78
|
+
jspp::AnyValue jspp::JsObject::set_property(const std::string &key, const AnyValue &value, const AnyValue &thisVal)
|
|
23
79
|
{
|
|
24
|
-
|
|
25
|
-
|
|
80
|
+
// set prototype property if accessor descriptor
|
|
81
|
+
auto proto_it = ObjectPrototypes::get(key, this);
|
|
82
|
+
if (proto_it.has_value())
|
|
83
|
+
{
|
|
84
|
+
auto proto_value = proto_it.value();
|
|
85
|
+
if (proto_value.is_accessor_descriptor())
|
|
86
|
+
{
|
|
87
|
+
return AnyValue::resolve_property_for_write(proto_value, thisVal, value, key);
|
|
88
|
+
}
|
|
89
|
+
if (proto_value.is_data_descriptor() && !proto_value.as_data_descriptor()->writable)
|
|
90
|
+
{
|
|
91
|
+
return AnyValue::resolve_property_for_write(proto_value, thisVal, value, key);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// set own property
|
|
96
|
+
if (deleted_keys.count(key)) deleted_keys.erase(key);
|
|
97
|
+
|
|
98
|
+
auto offset = shape->get_offset(key);
|
|
99
|
+
if (offset.has_value())
|
|
26
100
|
{
|
|
27
|
-
return
|
|
101
|
+
return AnyValue::resolve_property_for_write(storage[offset.value()], thisVal, value, key);
|
|
28
102
|
}
|
|
29
103
|
else
|
|
30
104
|
{
|
|
31
|
-
|
|
105
|
+
shape = shape->transition(key);
|
|
106
|
+
storage.push_back(value);
|
|
32
107
|
return value;
|
|
33
108
|
}
|
|
34
109
|
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "types.hpp"
|
|
4
|
+
#include "values/promise.hpp"
|
|
5
|
+
#include "any_value.hpp"
|
|
6
|
+
#include "values/prototypes/promise.hpp"
|
|
7
|
+
|
|
8
|
+
namespace jspp {
|
|
9
|
+
|
|
10
|
+
inline PromiseState::PromiseState() : result(std::make_shared<AnyValue>(AnyValue::make_undefined())) {}
|
|
11
|
+
|
|
12
|
+
inline JsPromise::JsPromise() : state(std::make_shared<PromiseState>()) {}
|
|
13
|
+
|
|
14
|
+
inline void JsPromise::resolve(const AnyValue& value) {
|
|
15
|
+
if (state->status != PromiseStatus::Pending) return;
|
|
16
|
+
|
|
17
|
+
if (value.is_promise()) {
|
|
18
|
+
auto p = value.as_promise();
|
|
19
|
+
if (p->state == state) {
|
|
20
|
+
reject(AnyValue::make_string("TypeError: Chaining cycle detected for promise"));
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
auto weak_state = std::weak_ptr<PromiseState>(state);
|
|
25
|
+
|
|
26
|
+
p->then(
|
|
27
|
+
[weak_state](const AnyValue& v) {
|
|
28
|
+
if (auto s = weak_state.lock()) {
|
|
29
|
+
JsPromise localP; localP.state = s;
|
|
30
|
+
localP.resolve(v);
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
[weak_state](const AnyValue& r) {
|
|
34
|
+
if (auto s = weak_state.lock()) {
|
|
35
|
+
JsPromise localP; localP.state = s;
|
|
36
|
+
localP.reject(r);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
state->status = PromiseStatus::Fulfilled;
|
|
44
|
+
*(state->result) = value;
|
|
45
|
+
|
|
46
|
+
// Schedule callbacks
|
|
47
|
+
auto callbacks = state->onFulfilled;
|
|
48
|
+
state->onFulfilled.clear();
|
|
49
|
+
state->onRejected.clear();
|
|
50
|
+
|
|
51
|
+
for (auto& cb : callbacks) {
|
|
52
|
+
jspp::Scheduler::instance().enqueue([cb, value]() {
|
|
53
|
+
cb(value);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
inline void JsPromise::reject(const AnyValue& reason) {
|
|
59
|
+
if (state->status != PromiseStatus::Pending) return;
|
|
60
|
+
state->status = PromiseStatus::Rejected;
|
|
61
|
+
*(state->result) = reason;
|
|
62
|
+
|
|
63
|
+
auto callbacks = state->onRejected;
|
|
64
|
+
state->onFulfilled.clear();
|
|
65
|
+
state->onRejected.clear();
|
|
66
|
+
|
|
67
|
+
for (auto& cb : callbacks) {
|
|
68
|
+
jspp::Scheduler::instance().enqueue([cb, reason]() {
|
|
69
|
+
cb(reason);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
inline void JsPromise::then(std::function<void(const AnyValue&)> onFulfilled, std::function<void(const AnyValue&)> onRejected) {
|
|
75
|
+
if (state->status == PromiseStatus::Fulfilled) {
|
|
76
|
+
if (onFulfilled) {
|
|
77
|
+
AnyValue val = *(state->result);
|
|
78
|
+
jspp::Scheduler::instance().enqueue([onFulfilled, val]() {
|
|
79
|
+
onFulfilled(val);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
} else if (state->status == PromiseStatus::Rejected) {
|
|
83
|
+
if (onRejected) {
|
|
84
|
+
AnyValue val = *(state->result);
|
|
85
|
+
jspp::Scheduler::instance().enqueue([onRejected, val]() {
|
|
86
|
+
onRejected(val);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
} else {
|
|
90
|
+
if (onFulfilled) state->onFulfilled.push_back(onFulfilled);
|
|
91
|
+
if (onRejected) state->onRejected.push_back(onRejected);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
inline std::string JsPromise::to_std_string() const {
|
|
96
|
+
return "[object Promise]";
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
inline AnyValue JsPromise::get_property(const std::string& key, const AnyValue& thisVal) {
|
|
100
|
+
// Prototype lookup
|
|
101
|
+
auto proto_it = PromisePrototypes::get(key, const_cast<JsPromise*>(this));
|
|
102
|
+
if (proto_it.has_value()) {
|
|
103
|
+
return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
auto it = props.find(key);
|
|
107
|
+
if (it != props.end()) {
|
|
108
|
+
return AnyValue::resolve_property_for_read(it->second, thisVal, key);
|
|
109
|
+
}
|
|
110
|
+
return AnyValue::make_undefined();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
inline AnyValue JsPromise::set_property(const std::string& key, const AnyValue& value, const AnyValue& thisVal) {
|
|
114
|
+
// Prototype check (if we had setters on prototype)
|
|
115
|
+
|
|
116
|
+
auto it = props.find(key);
|
|
117
|
+
if (it != props.end()) {
|
|
118
|
+
return AnyValue::resolve_property_for_write(it->second, thisVal, value, key);
|
|
119
|
+
} else {
|
|
120
|
+
props[key] = value;
|
|
121
|
+
return value;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// --- Coroutine Methods ---
|
|
126
|
+
|
|
127
|
+
inline void JsPromisePromiseType::return_value(const AnyValue& val) {
|
|
128
|
+
promise.resolve(val);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
inline void JsPromisePromiseType::unhandled_exception() {
|
|
132
|
+
try {
|
|
133
|
+
throw;
|
|
134
|
+
} catch (const Exception& e) {
|
|
135
|
+
promise.reject(*(e.data));
|
|
136
|
+
} catch (const std::exception& e) {
|
|
137
|
+
promise.reject(AnyValue::make_string(e.what()));
|
|
138
|
+
} catch (...) {
|
|
139
|
+
promise.reject(AnyValue::make_string("Unknown exception"));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
inline auto JsPromisePromiseType::await_transform(const AnyValue& value) {
|
|
144
|
+
return AnyValueAwaiter{value};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// --- AnyValueAwaiter ---
|
|
148
|
+
|
|
149
|
+
inline bool AnyValueAwaiter::await_ready() {
|
|
150
|
+
if (!value.is_promise()) return true; // Non-promise values are ready immediately (for now)
|
|
151
|
+
// Always suspend for promises to ensure microtask interleaving, even if already resolved.
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
inline void AnyValueAwaiter::await_suspend(std::coroutine_handle<> h) {
|
|
156
|
+
if (!value.is_promise()) {
|
|
157
|
+
h.resume();
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
auto p = value.as_promise();
|
|
161
|
+
|
|
162
|
+
// Attach resume to promise resolution.
|
|
163
|
+
// Since we are using the Scheduler in .then(), this will be queued.
|
|
164
|
+
p->then(
|
|
165
|
+
[h](AnyValue v) mutable { h.resume(); },
|
|
166
|
+
[h](AnyValue e) mutable { h.resume(); }
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
inline AnyValue AnyValueAwaiter::await_resume() {
|
|
171
|
+
if (!value.is_promise()) return value;
|
|
172
|
+
auto p = value.as_promise();
|
|
173
|
+
if (p->state->status == PromiseStatus::Fulfilled) {
|
|
174
|
+
return *(p->state->result);
|
|
175
|
+
} else {
|
|
176
|
+
// Throw exception to be caught by try/catch in coroutine
|
|
177
|
+
throw Exception(*(p->state->result));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
#include "types.hpp"
|
|
4
4
|
#include "values/array.hpp"
|
|
5
5
|
#include "values/string.hpp"
|
|
6
|
-
#include "
|
|
6
|
+
#include "exception.hpp"
|
|
7
7
|
#include "any_value.hpp"
|
|
8
8
|
#include "values/prototypes/string.hpp"
|
|
9
9
|
|
|
@@ -22,13 +22,13 @@ jspp::JsIterator<jspp::AnyValue> jspp::JsString::get_iterator()
|
|
|
22
22
|
co_return AnyValue::make_undefined();
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
jspp::AnyValue jspp::JsString::get_property(const std::string &key)
|
|
25
|
+
jspp::AnyValue jspp::JsString::get_property(const std::string &key, const AnyValue &thisVal)
|
|
26
26
|
{
|
|
27
27
|
// Check for prototype methods
|
|
28
28
|
auto proto_fn = StringPrototypes::get(key, this);
|
|
29
29
|
if (proto_fn.has_value())
|
|
30
30
|
{
|
|
31
|
-
return AnyValue::resolve_property_for_read(proto_fn.value());
|
|
31
|
+
return AnyValue::resolve_property_for_read(proto_fn.value(), thisVal, key);
|
|
32
32
|
}
|
|
33
33
|
// Handle character access by string index (e.g., "abc"["1"])
|
|
34
34
|
if (JsArray::is_array_index(key))
|
|
@@ -10,13 +10,13 @@ std::string jspp::JsSymbol::to_std_string() const
|
|
|
10
10
|
return "Symbol(" + description + ")";
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
jspp::AnyValue jspp::JsSymbol::get_property(const std::string &key)
|
|
13
|
+
jspp::AnyValue jspp::JsSymbol::get_property(const std::string &key, const AnyValue &thisVal)
|
|
14
14
|
{
|
|
15
15
|
// check prototype
|
|
16
16
|
auto proto_it = SymbolPrototypes::get(key, this);
|
|
17
17
|
if (proto_it.has_value())
|
|
18
18
|
{
|
|
19
|
-
return AnyValue::resolve_property_for_read(proto_it.value());
|
|
19
|
+
return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key);
|
|
20
20
|
}
|
|
21
21
|
// not found
|
|
22
22
|
return AnyValue::make_undefined();
|
|
@@ -25,6 +25,7 @@ namespace jspp
|
|
|
25
25
|
{
|
|
26
26
|
std::optional<T> current_value;
|
|
27
27
|
std::exception_ptr exception_;
|
|
28
|
+
T input_value;
|
|
28
29
|
|
|
29
30
|
JsIterator get_return_object()
|
|
30
31
|
{
|
|
@@ -40,10 +41,17 @@ namespace jspp
|
|
|
40
41
|
|
|
41
42
|
// Handle co_yield
|
|
42
43
|
template <typename From>
|
|
43
|
-
|
|
44
|
+
auto yield_value(From &&from)
|
|
44
45
|
{
|
|
45
46
|
current_value = std::forward<From>(from);
|
|
46
|
-
|
|
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};
|
|
47
55
|
}
|
|
48
56
|
|
|
49
57
|
// Handle co_return
|
|
@@ -80,9 +88,9 @@ namespace jspp
|
|
|
80
88
|
std::unordered_map<std::string, AnyValue> props;
|
|
81
89
|
|
|
82
90
|
std::string to_std_string() const;
|
|
83
|
-
NextResult next();
|
|
84
|
-
std::vector<
|
|
85
|
-
AnyValue get_property(const std::string &key);
|
|
86
|
-
AnyValue set_property(const std::string &key, const AnyValue &value);
|
|
91
|
+
NextResult next(const T &val = T());
|
|
92
|
+
std::vector<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);
|
|
87
95
|
};
|
|
88
96
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
3
|
#include "types.hpp"
|
|
4
|
+
#include "shape.hpp"
|
|
5
|
+
#include <vector>
|
|
6
|
+
#include <unordered_set>
|
|
4
7
|
|
|
5
8
|
namespace jspp
|
|
6
9
|
{
|
|
@@ -9,10 +12,18 @@ namespace jspp
|
|
|
9
12
|
|
|
10
13
|
struct JsObject
|
|
11
14
|
{
|
|
12
|
-
std::
|
|
15
|
+
std::shared_ptr<Shape> shape;
|
|
16
|
+
std::vector<AnyValue> storage;
|
|
17
|
+
std::shared_ptr<AnyValue> proto;
|
|
18
|
+
std::unordered_set<std::string> deleted_keys;
|
|
19
|
+
|
|
20
|
+
JsObject();
|
|
21
|
+
JsObject(std::initializer_list<std::pair<std::string, AnyValue>> p, std::shared_ptr<AnyValue> pr = nullptr);
|
|
22
|
+
JsObject(const std::map<std::string, AnyValue> &p, std::shared_ptr<AnyValue> pr = nullptr);
|
|
13
23
|
|
|
14
24
|
std::string to_std_string() const;
|
|
15
|
-
|
|
16
|
-
AnyValue
|
|
25
|
+
bool has_property(const std::string &key) const;
|
|
26
|
+
AnyValue get_property(const std::string &key, const AnyValue &thisVal);
|
|
27
|
+
AnyValue set_property(const std::string &key, const AnyValue &value, const AnyValue &thisVal);
|
|
17
28
|
};
|
|
18
29
|
}
|
|
@@ -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(const AnyValue&)>> onFulfilled;
|
|
24
|
+
std::vector<std::function<void(const 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(const AnyValue&)> onFulfilled, std::function<void(const 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
|
+
}
|