@ugo-studio/jspp 0.1.9 → 0.2.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.
Files changed (48) hide show
  1. package/README.md +1 -1
  2. package/dist/cli-utils/args.js +2 -0
  3. package/dist/cli.js +4 -4
  4. package/package.json +1 -1
  5. package/src/prelude/any_value.hpp +185 -391
  6. package/src/prelude/any_value_access.hpp +170 -190
  7. package/src/prelude/any_value_defines.hpp +12 -12
  8. package/src/prelude/any_value_helpers.hpp +208 -26
  9. package/src/prelude/exception.hpp +27 -31
  10. package/src/prelude/exception_helpers.hpp +53 -49
  11. package/src/prelude/index.hpp +4 -4
  12. package/src/prelude/library/array.hpp +4 -9
  13. package/src/prelude/library/console.hpp +112 -112
  14. package/src/prelude/library/error.hpp +8 -8
  15. package/src/prelude/library/math.hpp +3 -3
  16. package/src/prelude/library/object.hpp +12 -24
  17. package/src/prelude/library/promise.hpp +1 -1
  18. package/src/prelude/library/symbol.hpp +1 -1
  19. package/src/prelude/library/timer.hpp +3 -3
  20. package/src/prelude/types.hpp +178 -130
  21. package/src/prelude/utils/access.hpp +338 -378
  22. package/src/prelude/utils/log_any_value/function.hpp +39 -39
  23. package/src/prelude/utils/log_any_value/log_any_value.hpp +1 -1
  24. package/src/prelude/utils/operators.hpp +20 -82
  25. package/src/prelude/utils/well_known_symbols.hpp +14 -15
  26. package/src/prelude/values/array.hpp +5 -3
  27. package/src/prelude/values/async_iterator.hpp +3 -1
  28. package/src/prelude/values/descriptors.hpp +15 -3
  29. package/src/prelude/values/function.hpp +5 -9
  30. package/src/prelude/values/helpers/array.hpp +208 -219
  31. package/src/prelude/values/helpers/async_iterator.hpp +7 -11
  32. package/src/prelude/values/helpers/function.hpp +12 -17
  33. package/src/prelude/values/helpers/iterator.hpp +108 -107
  34. package/src/prelude/values/helpers/object.hpp +104 -109
  35. package/src/prelude/values/helpers/promise.hpp +185 -119
  36. package/src/prelude/values/helpers/string.hpp +7 -10
  37. package/src/prelude/values/helpers/symbol.hpp +21 -23
  38. package/src/prelude/values/iterator.hpp +4 -1
  39. package/src/prelude/values/object.hpp +6 -4
  40. package/src/prelude/values/promise.hpp +5 -2
  41. package/src/prelude/values/prototypes/array.hpp +22 -22
  42. package/src/prelude/values/prototypes/async_iterator.hpp +3 -10
  43. package/src/prelude/values/prototypes/iterator.hpp +51 -58
  44. package/src/prelude/values/prototypes/promise.hpp +32 -28
  45. package/src/prelude/values/prototypes/string.hpp +5 -5
  46. package/src/prelude/values/prototypes/symbol.hpp +1 -1
  47. package/src/prelude/values/string.hpp +3 -1
  48. package/src/prelude/values/symbol.hpp +101 -102
@@ -5,184 +5,250 @@
5
5
  #include "any_value.hpp"
6
6
  #include "values/prototypes/promise.hpp"
7
7
 
8
- namespace jspp {
8
+ namespace jspp
9
+ {
9
10
 
10
- inline PromiseState::PromiseState() : result(std::make_shared<AnyValue>(AnyValue::make_undefined())) {}
11
+ inline PromiseState::PromiseState() : result(Constants::UNDEFINED) {}
11
12
 
12
13
  inline JsPromise::JsPromise() : state(std::make_shared<PromiseState>()) {}
13
14
 
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;
15
+ inline void JsPromise::resolve(const AnyValue &value)
16
+ {
17
+ if (state->status != PromiseStatus::Pending)
18
+ return;
19
+
20
+ if (value.is_promise())
21
+ {
22
+ auto p = value.as_promise();
23
+ if (p->state == state)
24
+ {
25
+ reject(AnyValue::make_string("TypeError: Chaining cycle detected for promise"));
26
+ return;
27
+ }
28
+
29
+ auto weak_state = std::weak_ptr<PromiseState>(state);
30
+
31
+ p->then(
32
+ [weak_state](const AnyValue &v)
33
+ {
34
+ if (auto s = weak_state.lock())
35
+ {
36
+ // We can't easily use JsPromise here because it's a HeapObject now.
37
+ // But we can manually resolve the state if we have a way.
38
+ // Actually, we can create a temporary AnyValue from the state.
39
+ // But AnyValue expects a JsPromise* which was allocated with new.
40
+ // This is tricky.
41
+ // Let's assume we can just modify the status and result of the state directly.
42
+ s->status = PromiseStatus::Fulfilled;
43
+ s->result = v;
44
+ auto callbacks = s->onFulfilled;
45
+ s->onFulfilled.clear();
46
+ s->onRejected.clear();
47
+ for (auto &cb : callbacks)
48
+ jspp::Scheduler::instance().enqueue([cb, v]()
49
+ { cb(v); });
50
+ }
51
+ },
52
+ [weak_state](const AnyValue &r)
53
+ {
54
+ if (auto s = weak_state.lock())
55
+ {
56
+ s->status = PromiseStatus::Rejected;
57
+ s->result = r;
58
+ auto callbacks = s->onRejected;
59
+ s->onFulfilled.clear();
60
+ s->onRejected.clear();
61
+ for (auto &cb : callbacks)
62
+ jspp::Scheduler::instance().enqueue([cb, r]()
63
+ { cb(r); });
64
+ }
65
+ });
66
+ return;
41
67
  }
42
68
 
43
69
  state->status = PromiseStatus::Fulfilled;
44
- *(state->result) = value;
45
-
70
+ state->result = value;
71
+
46
72
  // Schedule callbacks
47
73
  auto callbacks = state->onFulfilled;
48
74
  state->onFulfilled.clear();
49
75
  state->onRejected.clear();
50
-
51
- for (auto& cb : callbacks) {
52
- jspp::Scheduler::instance().enqueue([cb, value]() {
53
- cb(value);
54
- });
76
+
77
+ for (auto &cb : callbacks)
78
+ {
79
+ jspp::Scheduler::instance().enqueue([cb, value]()
80
+ { cb(value); });
55
81
  }
56
82
  }
57
83
 
58
- inline void JsPromise::reject(const AnyValue& reason) {
59
- if (state->status != PromiseStatus::Pending) return;
84
+ inline void JsPromise::reject(const AnyValue &reason)
85
+ {
86
+ if (state->status != PromiseStatus::Pending)
87
+ return;
60
88
  state->status = PromiseStatus::Rejected;
61
- *(state->result) = reason;
62
-
89
+ state->result = reason;
90
+
63
91
  auto callbacks = state->onRejected;
64
92
  state->onFulfilled.clear();
65
93
  state->onRejected.clear();
66
-
67
- for (auto& cb : callbacks) {
68
- jspp::Scheduler::instance().enqueue([cb, reason]() {
69
- cb(reason);
70
- });
94
+
95
+ for (auto &cb : callbacks)
96
+ {
97
+ jspp::Scheduler::instance().enqueue([cb, reason]()
98
+ { cb(reason); });
71
99
  }
72
100
  }
73
101
 
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
- });
102
+ inline void JsPromise::then(std::function<void(const AnyValue &)> onFulfilled, std::function<void(const AnyValue &)> onRejected)
103
+ {
104
+ if (state->status == PromiseStatus::Fulfilled)
105
+ {
106
+ if (onFulfilled)
107
+ {
108
+ AnyValue val = state->result;
109
+ jspp::Scheduler::instance().enqueue([onFulfilled, val]()
110
+ { onFulfilled(val); });
81
111
  }
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
- });
112
+ }
113
+ else if (state->status == PromiseStatus::Rejected)
114
+ {
115
+ if (onRejected)
116
+ {
117
+ AnyValue val = state->result;
118
+ jspp::Scheduler::instance().enqueue([onRejected, val]()
119
+ { onRejected(val); });
88
120
  }
89
- } else {
90
- if (onFulfilled) state->onFulfilled.push_back(onFulfilled);
91
- if (onRejected) state->onRejected.push_back(onRejected);
121
+ }
122
+ else
123
+ {
124
+ if (onFulfilled)
125
+ state->onFulfilled.push_back(onFulfilled);
126
+ if (onRejected)
127
+ state->onRejected.push_back(onRejected);
92
128
  }
93
129
  }
94
130
 
95
- inline auto JsPromise::operator co_await() const {
131
+ inline auto JsPromise::operator co_await() const
132
+ {
133
+ // This is safe because AnyValue::make_promise copies the JsPromise (which is a HeapObject)
134
+ // Actually, AnyValue::make_promise(const JsPromise&) does from_ptr(new JsPromise(promise)).
96
135
  return AnyValueAwaiter{AnyValue::make_promise(*this)};
97
136
  }
98
137
 
99
- inline std::string JsPromise::to_std_string() const {
138
+ inline std::string JsPromise::to_std_string() const
139
+ {
100
140
  return "[object Promise]";
101
141
  }
102
142
 
103
- inline AnyValue JsPromise::get_property(const std::string& key, const AnyValue& thisVal) {
143
+ inline AnyValue JsPromise::get_property(const std::string &key, const AnyValue &thisVal)
144
+ {
104
145
  // Prototype lookup
105
- auto proto_it = PromisePrototypes::get(key, const_cast<JsPromise*>(this));
106
- if (proto_it.has_value()) {
107
- return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key);
146
+ auto proto_it = PromisePrototypes::get(key, const_cast<JsPromise *>(this));
147
+ if (proto_it.has_value())
148
+ {
149
+ return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key);
108
150
  }
109
-
151
+
110
152
  auto it = props.find(key);
111
- if (it != props.end()) {
112
- return AnyValue::resolve_property_for_read(it->second, thisVal, key);
153
+ if (it != props.end())
154
+ {
155
+ return AnyValue::resolve_property_for_read(it->second, thisVal, key);
113
156
  }
114
- return AnyValue::make_undefined();
157
+ return Constants::UNDEFINED;
115
158
  }
116
159
 
117
- inline AnyValue JsPromise::set_property(const std::string& key, const AnyValue& value, const AnyValue& thisVal) {
118
- // Prototype check (if we had setters on prototype)
119
-
120
- auto it = props.find(key);
121
- if (it != props.end()) {
122
- return AnyValue::resolve_property_for_write(it->second, thisVal, value, key);
123
- } else {
124
- props[key] = value;
125
- return value;
126
- }
160
+ inline AnyValue JsPromise::set_property(const std::string &key, const AnyValue &value, const AnyValue &thisVal)
161
+ {
162
+ auto it = props.find(key);
163
+ if (it != props.end())
164
+ {
165
+ return AnyValue::resolve_property_for_write(it->second, thisVal, value, key);
166
+ }
167
+ else
168
+ {
169
+ props[key] = value;
170
+ return value;
171
+ }
127
172
  }
128
-
173
+
129
174
  // --- Coroutine Methods ---
130
-
131
- inline void JsPromisePromiseType::return_value(const AnyValue& val) {
175
+
176
+ inline void JsPromisePromiseType::return_value(const AnyValue &val)
177
+ {
132
178
  promise.resolve(val);
133
179
  }
134
-
135
- inline void JsPromisePromiseType::unhandled_exception() {
136
- try {
137
- throw;
138
- } catch (const Exception& e) {
139
- promise.reject(*(e.data));
140
- } catch (const std::exception& e) {
141
- promise.reject(AnyValue::make_string(e.what()));
142
- } catch (...) {
143
- promise.reject(AnyValue::make_string("Unknown exception"));
144
- }
180
+
181
+ inline void JsPromisePromiseType::unhandled_exception()
182
+ {
183
+ try
184
+ {
185
+ throw;
186
+ }
187
+ catch (const Exception &e)
188
+ {
189
+ promise.reject(e.data);
190
+ }
191
+ catch (const std::exception &e)
192
+ {
193
+ promise.reject(AnyValue::make_string(e.what()));
194
+ }
195
+ catch (...)
196
+ {
197
+ promise.reject(AnyValue::make_string("Unknown exception"));
198
+ }
145
199
  }
146
-
147
- inline auto JsPromisePromiseType::await_transform(const AnyValue& value) {
148
- return AnyValueAwaiter{value};
200
+
201
+ inline auto JsPromisePromiseType::await_transform(const AnyValue &value)
202
+ {
203
+ return AnyValueAwaiter{value};
149
204
  }
150
205
 
151
- inline auto JsPromisePromiseType::await_transform(const JsPromise& value) {
152
- return AnyValueAwaiter{AnyValue::make_promise(value)};
206
+ inline auto JsPromisePromiseType::await_transform(const JsPromise &value)
207
+ {
208
+ // value is a JsPromise& which is a HeapObject.
209
+ // We wrap it in a temporary AnyValue for Awaiter.
210
+ // Wait, AnyValue::make_promise(value) will allocate a new JsPromise on heap.
211
+ // This is fine for now.
212
+ return AnyValueAwaiter{AnyValue::make_promise(value)};
153
213
  }
154
214
 
155
215
  // --- AnyValueAwaiter ---
156
216
 
157
- inline bool AnyValueAwaiter::await_ready() {
158
- // Always suspend to ensure microtask interleaving, even if already resolved or not a promise.
217
+ inline bool AnyValueAwaiter::await_ready()
218
+ {
159
219
  return false;
160
220
  }
161
221
 
162
- inline void AnyValueAwaiter::await_suspend(std::coroutine_handle<> h) {
163
- if (!value.is_promise()) {
164
- jspp::Scheduler::instance().enqueue([h]() mutable { h.resume(); });
222
+ inline void AnyValueAwaiter::await_suspend(std::coroutine_handle<> h)
223
+ {
224
+ if (!value.is_promise())
225
+ {
226
+ jspp::Scheduler::instance().enqueue([h]() mutable
227
+ { h.resume(); });
165
228
  return;
166
229
  }
167
230
  auto p = value.as_promise();
168
-
169
- // Attach resume to promise resolution.
170
- // Since we are using the Scheduler in .then(), this will be queued.
231
+
171
232
  p->then(
172
- [h](AnyValue v) mutable { h.resume(); },
173
- [h](AnyValue e) mutable { h.resume(); }
174
- );
233
+ [h](AnyValue v) mutable
234
+ { h.resume(); },
235
+ [h](AnyValue e) mutable
236
+ { h.resume(); });
175
237
  }
176
238
 
177
- inline AnyValue AnyValueAwaiter::await_resume() {
178
- if (!value.is_promise()) return value;
239
+ inline AnyValue AnyValueAwaiter::await_resume()
240
+ {
241
+ if (!value.is_promise())
242
+ return value;
179
243
  auto p = value.as_promise();
180
- if (p->state->status == PromiseStatus::Fulfilled) {
181
- return *(p->state->result);
182
- } else {
183
- // Throw exception to be caught by try/catch in coroutine
184
- throw Exception(*(p->state->result));
244
+ if (p->state->status == PromiseStatus::Fulfilled)
245
+ {
246
+ return p->state->result;
247
+ }
248
+ else
249
+ {
250
+ throw Exception(p->state->result);
185
251
  }
186
252
  }
187
253
 
188
- }
254
+ }
@@ -7,12 +7,12 @@
7
7
  #include "any_value.hpp"
8
8
  #include "values/prototypes/string.hpp"
9
9
 
10
- std::string jspp::JsString::to_std_string() const
10
+ inline std::string jspp::JsString::to_std_string() const
11
11
  {
12
12
  return value;
13
13
  }
14
14
 
15
- jspp::JsIterator<jspp::AnyValue> jspp::JsString::get_iterator()
15
+ inline jspp::JsIterator<jspp::AnyValue> jspp::JsString::get_iterator()
16
16
  {
17
17
  size_t strLength = value.length();
18
18
  for (size_t idx = 0; idx < strLength; idx++)
@@ -22,29 +22,26 @@ 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, const AnyValue &thisVal)
25
+ inline jspp::AnyValue jspp::JsString::get_property(const std::string &key, const AnyValue &thisVal)
26
26
  {
27
- // Check for prototype methods
28
27
  auto proto_fn = StringPrototypes::get(key, this);
29
28
  if (proto_fn.has_value())
30
29
  {
31
30
  return AnyValue::resolve_property_for_read(proto_fn.value(), thisVal, key);
32
31
  }
33
- // Handle character access by string index (e.g., "abc"["1"])
34
32
  if (JsArray::is_array_index(key))
35
33
  {
36
34
  uint32_t idx = static_cast<uint32_t>(std::stoull(key));
37
35
  return get_property(idx);
38
36
  }
39
- // not found
40
- return AnyValue::make_undefined();
37
+ return Constants::UNDEFINED;
41
38
  }
42
39
 
43
- jspp::AnyValue jspp::JsString::get_property(uint32_t idx)
40
+ inline jspp::AnyValue jspp::JsString::get_property(uint32_t idx)
44
41
  {
45
42
  if (idx < value.length())
46
43
  {
47
44
  return AnyValue::make_string(std::string(1, value[idx]));
48
45
  }
49
- return AnyValue::make_undefined();
50
- }
46
+ return Constants::UNDEFINED;
47
+ }
@@ -1,23 +1,21 @@
1
- #pragma once
2
-
3
- #include "types.hpp"
4
- #include "values/symbol.hpp"
5
- #include "any_value.hpp"
6
- #include "values/prototypes/symbol.hpp"
7
-
8
- std::string jspp::JsSymbol::to_std_string() const
9
- {
10
- return "Symbol(" + description + ")";
11
- }
12
-
13
- jspp::AnyValue jspp::JsSymbol::get_property(const std::string &key, const AnyValue &thisVal)
14
- {
15
- // check prototype
16
- auto proto_it = SymbolPrototypes::get(key, this);
17
- if (proto_it.has_value())
18
- {
19
- return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key);
20
- }
21
- // not found
22
- return AnyValue::make_undefined();
23
- }
1
+ #pragma once
2
+
3
+ #include "types.hpp"
4
+ #include "values/symbol.hpp"
5
+ #include "any_value.hpp"
6
+ #include "values/prototypes/symbol.hpp"
7
+
8
+ inline std::string jspp::JsSymbol::to_std_string() const
9
+ {
10
+ return "Symbol(" + description + ")";
11
+ }
12
+
13
+ inline jspp::AnyValue jspp::JsSymbol::get_property(const std::string &key, const AnyValue &thisVal)
14
+ {
15
+ auto proto_it = SymbolPrototypes::get(key, this);
16
+ if (proto_it.has_value())
17
+ {
18
+ return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key);
19
+ }
20
+ return Constants::UNDEFINED;
21
+ }
@@ -13,7 +13,7 @@ namespace jspp
13
13
  class AnyValue;
14
14
 
15
15
  template <typename T>
16
- class JsIterator
16
+ class JsIterator : public HeapObject
17
17
  {
18
18
  public:
19
19
  struct NextResult
@@ -21,6 +21,9 @@ namespace jspp
21
21
  std::optional<T> value;
22
22
  bool done;
23
23
  };
24
+
25
+ JsType get_heap_type() const override { return JsType::Iterator; }
26
+
24
27
  struct promise_type
25
28
  {
26
29
  std::optional<T> current_value;
@@ -10,16 +10,18 @@ namespace jspp
10
10
  // Forward declaration of AnyValue
11
11
  class AnyValue;
12
12
 
13
- struct JsObject
13
+ struct JsObject : HeapObject
14
14
  {
15
15
  std::shared_ptr<Shape> shape;
16
16
  std::vector<AnyValue> storage;
17
- std::shared_ptr<AnyValue> proto;
17
+ AnyValue proto;
18
18
  std::unordered_set<std::string> deleted_keys;
19
19
 
20
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);
21
+ JsObject(std::initializer_list<std::pair<std::string, AnyValue>> p, AnyValue pr);
22
+ JsObject(const std::map<std::string, AnyValue> &p, AnyValue pr);
23
+
24
+ JsType get_heap_type() const override { return JsType::Object; }
23
25
 
24
26
  std::string to_std_string() const;
25
27
  bool has_property(const std::string &key) const;
@@ -1,6 +1,7 @@
1
1
  #pragma once
2
2
 
3
3
  #include "types.hpp"
4
+ #include "any_value.hpp"
4
5
  #include <vector>
5
6
  #include <functional>
6
7
  #include <memory>
@@ -19,7 +20,7 @@ namespace jspp
19
20
  struct PromiseState
20
21
  {
21
22
  PromiseStatus status = PromiseStatus::Pending;
22
- std::shared_ptr<AnyValue> result; // Value if fulfilled, reason if rejected
23
+ AnyValue result; // Value if fulfilled, reason if rejected
23
24
  std::vector<std::function<void(const AnyValue&)>> onFulfilled;
24
25
  std::vector<std::function<void(const AnyValue&)>> onRejected;
25
26
 
@@ -28,7 +29,7 @@ namespace jspp
28
29
 
29
30
  struct JsPromisePromiseType; // Forward declaration
30
31
 
31
- struct JsPromise
32
+ struct JsPromise : HeapObject
32
33
  {
33
34
  using promise_type = JsPromisePromiseType;
34
35
 
@@ -37,6 +38,8 @@ namespace jspp
37
38
 
38
39
  JsPromise();
39
40
 
41
+ JsType get_heap_type() const override { return JsType::Promise; }
42
+
40
43
  // --- Promise Logic ---
41
44
  void resolve(const AnyValue& value);
42
45
  void reject(const AnyValue& reason);