@ugo-studio/jspp 0.1.3 → 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 +2 -2
- package/dist/analysis/scope.js +16 -4
- package/dist/analysis/typeAnalyzer.js +253 -20
- package/dist/ast/types.js +6 -0
- package/dist/cli.js +1 -2
- 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 +429 -117
- package/dist/core/codegen/function-handlers.js +91 -15
- package/dist/core/codegen/helpers.js +66 -2
- package/dist/core/codegen/index.js +17 -6
- package/dist/core/codegen/literal-handlers.js +3 -0
- package/dist/core/codegen/statement-handlers.js +133 -204
- package/dist/core/codegen/visitor.js +29 -3
- package/package.json +3 -3
- package/src/prelude/any_value.hpp +658 -634
- 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 -225
- package/src/prelude/exception.hpp +31 -0
- package/src/prelude/exception_helpers.hpp +49 -0
- package/src/prelude/index.hpp +18 -9
- package/src/prelude/library/console.hpp +13 -13
- package/src/prelude/library/error.hpp +111 -0
- package/src/prelude/library/global.hpp +15 -4
- package/src/prelude/library/performance.hpp +2 -2
- package/src/prelude/library/promise.hpp +121 -0
- package/src/prelude/library/symbol.hpp +3 -4
- package/src/prelude/library/timer.hpp +92 -0
- package/src/prelude/scheduler.hpp +145 -0
- package/src/prelude/types.hpp +10 -1
- 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} +29 -10
- package/src/prelude/{well_known_symbols.hpp → utils/well_known_symbols.hpp} +0 -1
- package/src/prelude/values/array.hpp +3 -2
- package/src/prelude/{descriptors.hpp → values/descriptors.hpp} +2 -2
- package/src/prelude/values/function.hpp +76 -51
- package/src/prelude/values/helpers/array.hpp +20 -11
- package/src/prelude/values/helpers/function.hpp +125 -77
- package/src/prelude/values/helpers/iterator.hpp +13 -7
- package/src/prelude/values/helpers/object.hpp +36 -6
- 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 +13 -5
- package/src/prelude/values/object.hpp +6 -2
- package/src/prelude/values/promise.hpp +73 -0
- package/src/prelude/values/prototypes/array.hpp +16 -16
- package/src/prelude/values/prototypes/function.hpp +4 -4
- package/src/prelude/values/prototypes/iterator.hpp +11 -10
- 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 +26 -26
- package/src/prelude/values/prototypes/symbol.hpp +5 -3
- 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
|
@@ -1,77 +1,125 @@
|
|
|
1
|
-
#pragma once
|
|
2
|
-
|
|
3
|
-
#include <variant>
|
|
4
|
-
|
|
5
|
-
#include "types.hpp"
|
|
6
|
-
#include "values/function.hpp"
|
|
7
|
-
#include "any_value.hpp"
|
|
8
|
-
#include "values/prototypes/function.hpp"
|
|
9
|
-
|
|
10
|
-
std::string jspp::JsFunction::to_std_string() const
|
|
11
|
-
{
|
|
12
|
-
if (
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
{
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <variant>
|
|
4
|
+
|
|
5
|
+
#include "types.hpp"
|
|
6
|
+
#include "values/function.hpp"
|
|
7
|
+
#include "any_value.hpp"
|
|
8
|
+
#include "values/prototypes/function.hpp"
|
|
9
|
+
|
|
10
|
+
std::string jspp::JsFunction::to_std_string() const
|
|
11
|
+
{
|
|
12
|
+
if (is_async) {
|
|
13
|
+
return "async function " + name + "() { [native code] }";
|
|
14
|
+
}
|
|
15
|
+
if (is_generator)
|
|
16
|
+
{
|
|
17
|
+
return "function* " + name + "() { [native code] }";
|
|
18
|
+
}
|
|
19
|
+
return "function " + name + "() { [native code] }";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
jspp::AnyValue jspp::JsFunction::call(const AnyValue &thisVal, const std::vector<AnyValue> &args)
|
|
23
|
+
{
|
|
24
|
+
if (std::function<AnyValue(const AnyValue &, const std::vector<AnyValue> &)> *func = std::get_if<0>(&callable))
|
|
25
|
+
{
|
|
26
|
+
return (*func)(thisVal, args);
|
|
27
|
+
}
|
|
28
|
+
else if (std::function<jspp::JsIterator<jspp::AnyValue>(const AnyValue &, const std::vector<jspp::AnyValue> &)> *func = std::get_if<1>(&callable))
|
|
29
|
+
{
|
|
30
|
+
return AnyValue::from_iterator((*func)(thisVal, args));
|
|
31
|
+
}
|
|
32
|
+
else if (std::function<jspp::JsPromise(const AnyValue &, const std::vector<jspp::AnyValue> &)> *func = std::get_if<2>(&callable))
|
|
33
|
+
{
|
|
34
|
+
return AnyValue::make_promise((*func)(thisVal, args));
|
|
35
|
+
}
|
|
36
|
+
else
|
|
37
|
+
{
|
|
38
|
+
return AnyValue::make_undefined();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
jspp::AnyValue jspp::JsFunction::get_property(const std::string &key, const AnyValue &thisVal)
|
|
43
|
+
{
|
|
44
|
+
auto it = props.find(key);
|
|
45
|
+
if (it == props.end())
|
|
46
|
+
{
|
|
47
|
+
// check explicit proto chain (e.g. for classes extending other classes)
|
|
48
|
+
if (proto && !(*proto).is_null() && !(*proto).is_undefined())
|
|
49
|
+
{
|
|
50
|
+
return (*proto).get_property_with_receiver(key, thisVal);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// check prototype (implicit Function.prototype)
|
|
54
|
+
auto proto_it = FunctionPrototypes::get(key, this);
|
|
55
|
+
if (proto_it.has_value())
|
|
56
|
+
{
|
|
57
|
+
return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key);
|
|
58
|
+
}
|
|
59
|
+
// not found
|
|
60
|
+
return AnyValue::make_undefined();
|
|
61
|
+
}
|
|
62
|
+
return AnyValue::resolve_property_for_read(it->second, thisVal, key);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
jspp::AnyValue jspp::JsFunction::set_property(const std::string &key, const AnyValue &value, const AnyValue &thisVal)
|
|
66
|
+
{
|
|
67
|
+
// set prototype property if accessor descriptor
|
|
68
|
+
auto proto_it = FunctionPrototypes::get(key, this);
|
|
69
|
+
if (proto_it.has_value())
|
|
70
|
+
{
|
|
71
|
+
auto proto_value = proto_it.value();
|
|
72
|
+
if (proto_value.is_accessor_descriptor())
|
|
73
|
+
{
|
|
74
|
+
return AnyValue::resolve_property_for_write(proto_value, thisVal, value, key);
|
|
75
|
+
}
|
|
76
|
+
if (proto_value.is_data_descriptor() && !proto_value.as_data_descriptor()->writable)
|
|
77
|
+
{
|
|
78
|
+
return AnyValue::resolve_property_for_write(proto_value, thisVal, value, key);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// set own property
|
|
83
|
+
auto it = props.find(key);
|
|
84
|
+
if (it != props.end())
|
|
85
|
+
{
|
|
86
|
+
return AnyValue::resolve_property_for_write(it->second, thisVal, value, key);
|
|
87
|
+
}
|
|
88
|
+
else
|
|
89
|
+
{
|
|
90
|
+
props[key] = value;
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// AnyValue::construct implementation
|
|
96
|
+
const jspp::AnyValue jspp::AnyValue::construct(const std::vector<AnyValue> &args) const
|
|
97
|
+
{
|
|
98
|
+
if (!is_function())
|
|
99
|
+
{
|
|
100
|
+
throw Exception::make_exception(to_std_string() + " is not a constructor", "TypeError");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// 1. Get prototype
|
|
104
|
+
AnyValue proto = get_own_property("prototype");
|
|
105
|
+
// If prototype is not an object, default to a plain object (which ideally inherits from Object.prototype)
|
|
106
|
+
// Here we just make a plain object.
|
|
107
|
+
if (!proto.is_object())
|
|
108
|
+
{
|
|
109
|
+
proto = AnyValue::make_object({});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// 2. Create instance
|
|
113
|
+
AnyValue instance = AnyValue::make_object_with_proto({}, proto);
|
|
114
|
+
|
|
115
|
+
// 3. Call function
|
|
116
|
+
// We pass 'instance' as 'this'
|
|
117
|
+
AnyValue result = as_function()->call(instance, args);
|
|
118
|
+
|
|
119
|
+
// 4. Return result if object, else instance
|
|
120
|
+
if (result.is_object() || result.is_function() || result.is_array() || result.is_promise())
|
|
121
|
+
{
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
return instance;
|
|
125
|
+
}
|
|
@@ -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
|
|
|
@@ -49,7 +51,7 @@ std::vector<std::optional<T>> jspp::JsIterator<T>::to_vector()
|
|
|
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
|
{
|
|
@@ -9,22 +9,52 @@ std::string jspp::JsObject::to_std_string() const
|
|
|
9
9
|
return "[Object Object]";
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
jspp::AnyValue jspp::JsObject::get_property(const std::string &key)
|
|
12
|
+
jspp::AnyValue jspp::JsObject::get_property(const std::string &key, const AnyValue &thisVal)
|
|
13
13
|
{
|
|
14
14
|
auto it = props.find(key);
|
|
15
|
-
if (it
|
|
15
|
+
if (it == props.end())
|
|
16
16
|
{
|
|
17
|
-
|
|
17
|
+
// check prototype chain
|
|
18
|
+
if (proto && !(*proto).is_null() && !(*proto).is_undefined())
|
|
19
|
+
{
|
|
20
|
+
return (*proto).get_property_with_receiver(key, thisVal);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// check built-in prototype methods (Object.prototype)
|
|
24
|
+
// ideally these should be on the root prototype object, but for now we keep this fallback
|
|
25
|
+
auto proto_it = ObjectPrototypes::get(key, this);
|
|
26
|
+
if (proto_it.has_value())
|
|
27
|
+
{
|
|
28
|
+
return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key);
|
|
29
|
+
}
|
|
30
|
+
// not found
|
|
31
|
+
return AnyValue::make_undefined();
|
|
18
32
|
}
|
|
19
|
-
return
|
|
33
|
+
return AnyValue::resolve_property_for_read(it->second, thisVal, key);
|
|
20
34
|
}
|
|
21
35
|
|
|
22
|
-
jspp::AnyValue jspp::JsObject::set_property(const std::string &key, const AnyValue &value)
|
|
36
|
+
jspp::AnyValue jspp::JsObject::set_property(const std::string &key, const AnyValue &value, const AnyValue &thisVal)
|
|
23
37
|
{
|
|
38
|
+
// set prototype property if accessor descriptor
|
|
39
|
+
auto proto_it = ObjectPrototypes::get(key, this);
|
|
40
|
+
if (proto_it.has_value())
|
|
41
|
+
{
|
|
42
|
+
auto proto_value = proto_it.value();
|
|
43
|
+
if (proto_value.is_accessor_descriptor())
|
|
44
|
+
{
|
|
45
|
+
return AnyValue::resolve_property_for_write(proto_value, thisVal, value, key);
|
|
46
|
+
}
|
|
47
|
+
if (proto_value.is_data_descriptor() && !proto_value.as_data_descriptor()->writable)
|
|
48
|
+
{
|
|
49
|
+
return AnyValue::resolve_property_for_write(proto_value, thisVal, value, key);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// set own property
|
|
24
54
|
auto it = props.find(key);
|
|
25
55
|
if (it != props.end())
|
|
26
56
|
{
|
|
27
|
-
return
|
|
57
|
+
return AnyValue::resolve_property_for_write(it->second, thisVal, value, key);
|
|
28
58
|
}
|
|
29
59
|
else
|
|
30
60
|
{
|
|
@@ -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](AnyValue v) {
|
|
28
|
+
if (auto s = weak_state.lock()) {
|
|
29
|
+
JsPromise localP; localP.state = s;
|
|
30
|
+
localP.resolve(v);
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
[weak_state](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(AnyValue)> onFulfilled, std::function<void(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();
|
|
91
|
+
NextResult next(const T &val = T());
|
|
84
92
|
std::vector<std::optional<T>> to_vector();
|
|
85
|
-
AnyValue get_property(const std::string &key);
|
|
86
|
-
AnyValue set_property(const std::string &key, const AnyValue &value);
|
|
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
|
}
|
|
@@ -10,9 +10,13 @@ namespace jspp
|
|
|
10
10
|
struct JsObject
|
|
11
11
|
{
|
|
12
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) {}
|
|
13
17
|
|
|
14
18
|
std::string to_std_string() const;
|
|
15
|
-
AnyValue get_property(const std::string &key);
|
|
16
|
-
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);
|
|
17
21
|
};
|
|
18
22
|
}
|