@ugo-studio/jspp 0.3.2 → 0.3.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.
@@ -2,210 +2,251 @@
2
2
  #include "values/iterator.hpp"
3
3
  #include "values/prototypes/iterator.hpp"
4
4
 
5
- namespace jspp {
6
-
7
- template <typename T>
8
- JsIterator<T>::JsIterator(handle_type h) : handle(h) {}
9
-
10
- template <typename T>
11
- JsIterator<T>::JsIterator(JsIterator &&other) noexcept
12
- : handle(std::exchange(other.handle, nullptr)),
13
- props(std::move(other.props)),
14
- symbol_props(std::move(other.symbol_props)) {}
15
-
16
- template <typename T>
17
- JsIterator<T>::~JsIterator() { if (handle) handle.destroy(); }
18
-
19
- template <typename T>
20
- JsIterator<T> JsIterator<T>::promise_type::get_return_object() {
21
- return JsIterator{std::coroutine_handle<promise_type>::from_promise(*this)};
22
- }
23
-
24
- template <typename T>
25
- std::suspend_always JsIterator<T>::promise_type::initial_suspend() noexcept { return {}; }
26
-
27
- template <typename T>
28
- std::suspend_always JsIterator<T>::promise_type::final_suspend() noexcept { return {}; }
29
-
30
- template <typename T>
31
- void JsIterator<T>::promise_type::unhandled_exception() {
32
- try {
33
- throw;
34
- } catch (const GeneratorReturnException&) {
35
- } catch (...) {
36
- exception_ = std::current_exception();
5
+ namespace jspp
6
+ {
7
+
8
+ template <typename T>
9
+ JsIterator<T>::JsIterator(handle_type h) : handle(h) {}
10
+
11
+ template <typename T>
12
+ JsIterator<T>::JsIterator(JsIterator &&other) noexcept
13
+ : handle(std::exchange(other.handle, nullptr)),
14
+ props(std::move(other.props)),
15
+ symbol_props(std::move(other.symbol_props)) {}
16
+
17
+ template <typename T>
18
+ JsIterator<T>::~JsIterator()
19
+ {
20
+ if (handle)
21
+ handle.destroy();
37
22
  }
38
- }
39
23
 
40
- template <typename T>
41
- std::string JsIterator<T>::to_std_string() const { return "[object Generator]"; }
24
+ template <typename T>
25
+ JsIterator<T> JsIterator<T>::promise_type::get_return_object()
26
+ {
27
+ return JsIterator{std::coroutine_handle<promise_type>::from_promise(*this)};
28
+ }
42
29
 
43
- template <typename T>
44
- typename JsIterator<T>::NextResult JsIterator<T>::next(const T &val)
45
- {
46
- if (!handle || handle.done()) return {std::nullopt, true};
47
- handle.promise().input_value = val;
48
- handle.resume();
49
- if (handle.promise().exception_) std::rethrow_exception(handle.promise().exception_);
50
- bool is_done = handle.done();
51
- return {handle.promise().current_value, is_done};
52
- }
53
-
54
- template <typename T>
55
- typename JsIterator<T>::NextResult JsIterator<T>::return_(const T &val)
56
- {
57
- if (!handle || handle.done()) return {val, true};
58
- handle.promise().pending_return = true;
59
- handle.promise().current_value = val;
60
- handle.resume();
61
- if (handle.promise().exception_) std::rethrow_exception(handle.promise().exception_);
62
- return {handle.promise().current_value, true};
63
- }
64
-
65
- template <typename T>
66
- typename JsIterator<T>::NextResult JsIterator<T>::throw_(const AnyValue &err)
67
- {
68
- if (!handle || handle.done()) throw Exception(err);
69
- handle.promise().pending_exception = std::make_exception_ptr(Exception(err));
70
- handle.resume();
71
- if (handle.promise().exception_) std::rethrow_exception(handle.promise().exception_);
72
- bool is_done = handle.done();
73
- return {handle.promise().current_value, is_done};
74
- }
75
-
76
- template <typename T>
77
- std::vector<T> JsIterator<T>::to_vector()
78
- {
79
- std::vector<T> result;
80
- while (true) {
81
- auto next_res = this->next();
82
- if (next_res.done) break;
83
- result.push_back(next_res.value.value_or(Constants::UNDEFINED));
30
+ template <typename T>
31
+ std::suspend_always JsIterator<T>::promise_type::initial_suspend() noexcept { return {}; }
32
+
33
+ template <typename T>
34
+ std::suspend_always JsIterator<T>::promise_type::final_suspend() noexcept { return {}; }
35
+
36
+ template <typename T>
37
+ void JsIterator<T>::promise_type::unhandled_exception()
38
+ {
39
+ try
40
+ {
41
+ throw;
42
+ }
43
+ catch (const GeneratorReturnException &)
44
+ {
45
+ }
46
+ catch (...)
47
+ {
48
+ exception_ = std::current_exception();
49
+ }
84
50
  }
85
- return result;
86
- }
87
51
 
88
- template <typename T>
89
- bool JsIterator<T>::has_symbol_property(const AnyValue &key) const { return symbol_props.count(key) > 0; }
52
+ template <typename T>
53
+ std::string JsIterator<T>::to_std_string() const { return "[object Generator]"; }
54
+
55
+ template <typename T>
56
+ typename JsIterator<T>::NextResult JsIterator<T>::next(const T &val)
57
+ {
58
+ if (!handle || handle.done())
59
+ return {std::nullopt, true};
60
+ handle.promise().input_value = val;
61
+ handle.resume();
62
+ if (handle.promise().exception_)
63
+ std::rethrow_exception(handle.promise().exception_);
64
+ bool is_done = handle.done();
65
+ return {handle.promise().current_value, is_done};
66
+ }
90
67
 
91
- template <typename T>
92
- AnyValue JsIterator<T>::get_property(const std::string &key, AnyValue thisVal)
93
- {
94
- auto it = props.find(key);
95
- if (it == props.end()) {
96
- if constexpr (std::is_same_v<T, AnyValue>) {
97
- auto proto_it = IteratorPrototypes::get(key);
98
- if (proto_it.has_value()) return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key);
68
+ template <typename T>
69
+ typename JsIterator<T>::NextResult JsIterator<T>::return_(const T &val)
70
+ {
71
+ if (!handle || handle.done())
72
+ return {val, true};
73
+ handle.promise().pending_return = true;
74
+ handle.promise().current_value = val;
75
+ handle.resume();
76
+ if (handle.promise().exception_)
77
+ std::rethrow_exception(handle.promise().exception_);
78
+ return {handle.promise().current_value, true};
79
+ }
80
+
81
+ template <typename T>
82
+ typename JsIterator<T>::NextResult JsIterator<T>::throw_(const AnyValue &err)
83
+ {
84
+ if (!handle || handle.done())
85
+ throw Exception(err);
86
+ handle.promise().pending_exception = std::make_exception_ptr(Exception(err));
87
+ handle.resume();
88
+ if (handle.promise().exception_)
89
+ std::rethrow_exception(handle.promise().exception_);
90
+ bool is_done = handle.done();
91
+ return {handle.promise().current_value, is_done};
92
+ }
93
+
94
+ template <typename T>
95
+ std::vector<T> JsIterator<T>::to_vector()
96
+ {
97
+ std::vector<T> result;
98
+ while (true)
99
+ {
100
+ auto next_res = this->next();
101
+ if (next_res.done)
102
+ break;
103
+ result.push_back(next_res.value.value_or(Constants::UNDEFINED));
99
104
  }
100
- return Constants::UNDEFINED;
105
+ return result;
101
106
  }
102
- return AnyValue::resolve_property_for_read(it->second, thisVal, key);
103
- }
104
107
 
105
- template <typename T>
106
- AnyValue JsIterator<T>::get_symbol_property(const AnyValue &key, AnyValue thisVal)
107
- {
108
- auto it = symbol_props.find(key);
109
- if (it == symbol_props.end()) {
110
- if constexpr (std::is_same_v<T, AnyValue>) {
111
- auto proto_it = IteratorPrototypes::get(key);
112
- if (proto_it.has_value()) return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key.to_std_string());
108
+ template <typename T>
109
+ bool JsIterator<T>::has_symbol_property(const AnyValue &key) const { return symbol_props.count(key) > 0; }
110
+
111
+ template <typename T>
112
+ AnyValue JsIterator<T>::get_property(const std::string &key, AnyValue thisVal)
113
+ {
114
+ auto it = props.find(key);
115
+ if (it == props.end())
116
+ {
117
+ if constexpr (std::is_same_v<T, AnyValue>)
118
+ {
119
+ auto proto_it = IteratorPrototypes::get(key);
120
+ if (proto_it.has_value())
121
+ return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key);
122
+ }
123
+ return Constants::UNDEFINED;
113
124
  }
114
- return Constants::UNDEFINED;
125
+ return AnyValue::resolve_property_for_read(it->second, thisVal, key);
115
126
  }
116
- return AnyValue::resolve_property_for_read(it->second, thisVal, key.to_std_string());
117
- }
118
127
 
119
- template <typename T>
120
- AnyValue JsIterator<T>::set_property(const std::string &key, AnyValue value, AnyValue thisVal)
121
- {
122
- if constexpr (std::is_same_v<T, AnyValue>) {
123
- auto proto_it = IteratorPrototypes::get(key);
124
- if (proto_it.has_value()) {
125
- auto proto_value = proto_it.value();
126
- if (proto_value.is_accessor_descriptor()) return AnyValue::resolve_property_for_write(proto_value, thisVal, value, key);
127
- if (proto_value.is_data_descriptor() && !proto_value.as_data_descriptor()->writable) return AnyValue::resolve_property_for_write(proto_value, thisVal, value, key);
128
+ template <typename T>
129
+ AnyValue JsIterator<T>::get_symbol_property(const AnyValue &key, AnyValue thisVal)
130
+ {
131
+ auto it = symbol_props.find(key);
132
+ if (it == symbol_props.end())
133
+ {
134
+ if constexpr (std::is_same_v<T, AnyValue>)
135
+ {
136
+ auto proto_it = IteratorPrototypes::get(key);
137
+ if (proto_it.has_value())
138
+ return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key.to_std_string());
139
+ }
140
+ return Constants::UNDEFINED;
128
141
  }
142
+ return AnyValue::resolve_property_for_read(it->second, thisVal, key.to_std_string());
129
143
  }
130
- auto it = props.find(key);
131
- if (it != props.end()) return jspp::AnyValue::resolve_property_for_write(it->second, thisVal, value, key);
132
- else { props[key] = value; return value; }
133
- }
134
144
 
135
- template <typename T>
136
- AnyValue JsIterator<T>::set_symbol_property(const AnyValue &key, AnyValue value, AnyValue thisVal)
137
- {
138
- auto it = symbol_props.find(key);
139
- if (it != symbol_props.end()) return AnyValue::resolve_property_for_write(it->second, thisVal, value, key.to_std_string());
140
- else { symbol_props[key] = value; return value; }
141
- }
145
+ template <typename T>
146
+ AnyValue JsIterator<T>::set_property(const std::string &key, AnyValue value, AnyValue thisVal)
147
+ {
148
+ if constexpr (std::is_same_v<T, AnyValue>)
149
+ {
150
+ auto proto_it = IteratorPrototypes::get(key);
151
+ if (proto_it.has_value())
152
+ {
153
+ auto proto_value = proto_it.value();
154
+ if (proto_value.is_accessor_descriptor())
155
+ return AnyValue::resolve_property_for_write(proto_value, thisVal, value, key);
156
+ if (proto_value.is_data_descriptor() && !proto_value.as_data_descriptor()->writable)
157
+ return AnyValue::resolve_property_for_write(proto_value, thisVal, value, key);
158
+ }
159
+ }
160
+ auto it = props.find(key);
161
+ if (it != props.end())
162
+ return jspp::AnyValue::resolve_property_for_write(it->second, thisVal, value, key);
163
+ else
164
+ {
165
+ props[key] = value;
166
+ return value;
167
+ }
168
+ }
142
169
 
143
- // Explicit template instantiation
144
- template class JsIterator<AnyValue>;
170
+ template <typename T>
171
+ AnyValue JsIterator<T>::set_symbol_property(const AnyValue &key, AnyValue value, AnyValue thisVal)
172
+ {
173
+ auto it = symbol_props.find(key);
174
+ if (it != symbol_props.end())
175
+ return AnyValue::resolve_property_for_write(it->second, thisVal, value, key.to_std_string());
176
+ else
177
+ {
178
+ symbol_props[key] = value;
179
+ return value;
180
+ }
181
+ }
145
182
 
146
- namespace IteratorPrototypes {
183
+ // Explicit template instantiation
184
+ template class JsIterator<AnyValue>;
147
185
 
148
- AnyValue &get_toString_fn()
149
- {
150
- static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue>) -> AnyValue
151
- { return AnyValue::make_string(thisVal.as_iterator()->to_std_string()); },
152
- "toString");
153
- return fn;
154
- }
186
+ namespace IteratorPrototypes
187
+ {
155
188
 
156
- AnyValue &get_iterator_fn()
157
- {
158
- static AnyValue fn = AnyValue::make_generator([](const AnyValue &thisVal, std::span<const AnyValue>) -> AnyValue
159
- { return thisVal; },
160
- "Symbol.iterator");
161
- return fn;
162
- }
189
+ AnyValue &get_toString_fn()
190
+ {
191
+ static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue>) -> AnyValue
192
+ { return AnyValue::make_string(thisVal.as_iterator()->to_std_string()); },
193
+ "toString");
194
+ return fn;
195
+ }
163
196
 
164
- AnyValue &get_next_fn()
165
- {
166
- static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
167
- {
197
+ AnyValue &get_iterator_fn()
198
+ {
199
+ static AnyValue fn = AnyValue::make_generator([](const AnyValue &thisVal, std::span<const AnyValue>) -> AnyValue
200
+ { return thisVal; },
201
+ "Symbol.iterator");
202
+ return fn;
203
+ }
204
+
205
+ AnyValue &get_next_fn()
206
+ {
207
+ static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
208
+ {
168
209
  AnyValue val = args.empty() ? Constants::UNDEFINED : args[0];
169
210
  auto res = thisVal.as_iterator()->next(val);
170
211
  return AnyValue::make_object({{"value", res.value.value_or(Constants::UNDEFINED)}, {"done", AnyValue::make_boolean(res.done)}}); },
171
- "next");
172
- return fn;
173
- }
212
+ "next");
213
+ return fn;
214
+ }
174
215
 
175
- AnyValue &get_return_fn()
176
- {
177
- static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
178
- {
216
+ AnyValue &get_return_fn()
217
+ {
218
+ static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
219
+ {
179
220
  AnyValue val = args.empty() ? Constants::UNDEFINED : args[0];
180
221
  auto res = thisVal.as_iterator()->return_(val);
181
222
  return AnyValue::make_object({{"value", res.value.value_or(Constants::UNDEFINED)}, {"done", AnyValue::make_boolean(res.done)}}); },
182
- "return");
183
- return fn;
184
- }
223
+ "return");
224
+ return fn;
225
+ }
185
226
 
186
- AnyValue &get_throw_fn()
187
- {
188
- static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
189
- {
227
+ AnyValue &get_throw_fn()
228
+ {
229
+ static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
230
+ {
190
231
  AnyValue err = args.empty() ? Constants::UNDEFINED : args[0];
191
232
  auto res = thisVal.as_iterator()->throw_(err);
192
233
  return AnyValue::make_object({{"value", res.value.value_or(Constants::UNDEFINED)}, {"done", AnyValue::make_boolean(res.done)}}); },
193
- "throw");
194
- return fn;
195
- }
234
+ "throw");
235
+ return fn;
236
+ }
196
237
 
197
- AnyValue &get_toArray_fn()
198
- {
199
- static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue>) -> AnyValue
200
- { return AnyValue::make_array(thisVal.as_iterator()->to_vector()); },
201
- "toArray");
202
- return fn;
203
- }
238
+ AnyValue &get_toArray_fn()
239
+ {
240
+ static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue>) -> AnyValue
241
+ { return AnyValue::make_array(thisVal.as_iterator()->to_vector()); },
242
+ "toArray");
243
+ return fn;
244
+ }
204
245
 
205
- AnyValue &get_drop_fn()
206
- {
207
- static AnyValue fn = AnyValue::make_generator([](AnyValue thisVal, std::vector<AnyValue> args) -> JsIterator<AnyValue>
208
- {
246
+ AnyValue &get_drop_fn()
247
+ {
248
+ static AnyValue fn = AnyValue::make_generator([](AnyValue thisVal, std::vector<AnyValue> args) -> JsIterator<AnyValue>
249
+ {
209
250
  auto self = thisVal.as_iterator();
210
251
  size_t skip_count = 0;
211
252
  if (!args.empty()) {
@@ -224,14 +265,14 @@ AnyValue &get_drop_fn()
224
265
  co_yield next_res.value.value_or(Constants::UNDEFINED);
225
266
  }
226
267
  co_return jspp::Constants::UNDEFINED; },
227
- "drop");
228
- return fn;
229
- }
268
+ "drop");
269
+ return fn;
270
+ }
230
271
 
231
- AnyValue &get_take_fn()
232
- {
233
- static AnyValue fn = AnyValue::make_generator([](AnyValue thisVal, std::vector<AnyValue> args) -> JsIterator<AnyValue>
234
- {
272
+ AnyValue &get_take_fn()
273
+ {
274
+ static AnyValue fn = AnyValue::make_generator([](AnyValue thisVal, std::vector<AnyValue> args) -> JsIterator<AnyValue>
275
+ {
235
276
  auto self = thisVal.as_iterator();
236
277
  size_t take_count = 0;
237
278
  if (!args.empty()) {
@@ -254,14 +295,14 @@ AnyValue &get_take_fn()
254
295
  }
255
296
  }
256
297
  co_return jspp::Constants::UNDEFINED; },
257
- "take");
258
- return fn;
259
- }
298
+ "take");
299
+ return fn;
300
+ }
260
301
 
261
- AnyValue &get_some_fn()
262
- {
263
- static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
264
- {
302
+ AnyValue &get_some_fn()
303
+ {
304
+ static AnyValue fn = AnyValue::make_function([](const AnyValue &thisVal, std::span<const AnyValue> args) -> AnyValue
305
+ {
265
306
  auto self = thisVal.as_iterator();
266
307
  if (args.empty() || !args[0].is_function()) throw Exception::make_exception("callback is not a function", "TypeError");
267
308
  auto callback = args[0].as_function();
@@ -269,7 +310,8 @@ AnyValue &get_some_fn()
269
310
  {
270
311
  auto next_res = self->next();
271
312
  if (next_res.done) { break; }
272
- if (is_truthy(callback->call(thisVal, std::span<const AnyValue>((const jspp::AnyValue[]){next_res.value.value_or(Constants::UNDEFINED)}, 1))))
313
+ AnyValue cb_arg = next_res.value.value_or(Constants::UNDEFINED);
314
+ if (is_truthy(callback->call(thisVal, std::span<const AnyValue>(&cb_arg, 1))))
273
315
  {
274
316
  self->return_();
275
317
  return Constants::TRUE;
@@ -277,33 +319,43 @@ AnyValue &get_some_fn()
277
319
  }
278
320
  return jspp::Constants::FALSE; },
279
321
  "some");
280
- return fn;
281
- }
322
+ return fn;
323
+ }
282
324
 
283
- std::optional<AnyValue> get(const std::string &key)
284
- {
285
- if (key == "toString") return get_toString_fn();
286
- if (key == "next") return get_next_fn();
287
- if (key == "return") return get_return_fn();
288
- if (key == "throw") return get_throw_fn();
289
- if (key == "toArray") return get_toArray_fn();
290
- if (key == "drop") return get_drop_fn();
291
- if (key == "take") return get_take_fn();
292
- if (key == "some") return get_some_fn();
293
- return std::nullopt;
294
- }
295
-
296
- std::optional<AnyValue> get(const AnyValue &key)
297
- {
298
- if (key.is_string())
299
- return get(key.as_string()->value);
325
+ std::optional<AnyValue> get(const std::string &key)
326
+ {
327
+ if (key == "toString")
328
+ return get_toString_fn();
329
+ if (key == "next")
330
+ return get_next_fn();
331
+ if (key == "return")
332
+ return get_return_fn();
333
+ if (key == "throw")
334
+ return get_throw_fn();
335
+ if (key == "toArray")
336
+ return get_toArray_fn();
337
+ if (key == "drop")
338
+ return get_drop_fn();
339
+ if (key == "take")
340
+ return get_take_fn();
341
+ if (key == "some")
342
+ return get_some_fn();
343
+ return std::nullopt;
344
+ }
345
+
346
+ std::optional<AnyValue> get(const AnyValue &key)
347
+ {
348
+ if (key.is_string())
349
+ return get(key.as_string()->value);
300
350
 
301
- if (key == AnyValue::from_symbol(WellKnownSymbols::toStringTag)) return get_toString_fn();
302
- if (key == AnyValue::from_symbol(WellKnownSymbols::iterator)) return get_iterator_fn();
351
+ if (key == AnyValue::from_symbol(WellKnownSymbols::toStringTag))
352
+ return get_toString_fn();
353
+ if (key == AnyValue::from_symbol(WellKnownSymbols::iterator))
354
+ return get_iterator_fn();
303
355
 
304
- return std::nullopt;
305
- }
356
+ return std::nullopt;
357
+ }
306
358
 
307
- } // namespace IteratorPrototypes
359
+ } // namespace IteratorPrototypes
308
360
 
309
361
  } // namespace jspp
@@ -87,7 +87,7 @@ namespace jspp
87
87
  int digits = -1;
88
88
  if (!args.empty() && !args[0].is_undefined())
89
89
  {
90
- digits = Operators_Private::ToInt32(args[0]);
90
+ digits = NumberOperators::ToInt32(args[0]);
91
91
  if (digits < 0 || digits > 100)
92
92
  {
93
93
  throw Exception::make_exception("toExponential() digits argument must be between 0 and 100", "RangeError");
@@ -118,7 +118,7 @@ namespace jspp
118
118
  int digits = 0;
119
119
  if (!args.empty() && !args[0].is_undefined())
120
120
  {
121
- digits = Operators_Private::ToInt32(args[0]);
121
+ digits = NumberOperators::ToInt32(args[0]);
122
122
  }
123
123
  if (digits < 0 || digits > 100)
124
124
  {
@@ -141,7 +141,7 @@ namespace jspp
141
141
  {
142
142
  return AnyValue::make_number(self).get_own_property("toString").call(AnyValue::make_number(self), {}, "toString");
143
143
  }
144
- int precision = Operators_Private::ToInt32(args[0]);
144
+ int precision = NumberOperators::ToInt32(args[0]);
145
145
  if (precision < 1 || precision > 100)
146
146
  {
147
147
  throw Exception::make_exception("toPrecision() precision argument must be between 1 and 100", "RangeError");
@@ -162,7 +162,7 @@ namespace jspp
162
162
  int radix = 10;
163
163
  if (!args.empty() && !args[0].is_undefined())
164
164
  {
165
- radix = Operators_Private::ToInt32(args[0]);
165
+ radix = NumberOperators::ToInt32(args[0]);
166
166
  }
167
167
  if (radix < 2 || radix > 36)
168
168
  {