@ugo-studio/jspp 0.1.4 → 0.1.6

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 (71) hide show
  1. package/dist/analysis/scope.js +17 -0
  2. package/dist/analysis/typeAnalyzer.js +7 -1
  3. package/dist/ast/symbols.js +32 -0
  4. package/dist/ast/types.js +0 -6
  5. package/dist/cli-utils/args.js +57 -0
  6. package/dist/cli-utils/colors.js +9 -0
  7. package/dist/cli-utils/file-utils.js +20 -0
  8. package/dist/cli-utils/spinner.js +55 -0
  9. package/dist/cli.js +105 -30
  10. package/dist/core/codegen/class-handlers.js +10 -6
  11. package/dist/core/codegen/control-flow-handlers.js +57 -28
  12. package/dist/core/codegen/declaration-handlers.js +10 -6
  13. package/dist/core/codegen/expression-handlers.js +206 -61
  14. package/dist/core/codegen/function-handlers.js +203 -76
  15. package/dist/core/codegen/helpers.js +125 -28
  16. package/dist/core/codegen/index.js +23 -15
  17. package/dist/core/codegen/literal-handlers.js +15 -6
  18. package/dist/core/codegen/statement-handlers.js +282 -84
  19. package/dist/core/codegen/visitor.js +3 -1
  20. package/package.json +1 -1
  21. package/src/prelude/any_value.hpp +221 -342
  22. package/src/prelude/any_value_access.hpp +168 -81
  23. package/src/prelude/any_value_defines.hpp +74 -35
  24. package/src/prelude/any_value_helpers.hpp +75 -180
  25. package/src/prelude/exception.hpp +1 -0
  26. package/src/prelude/exception_helpers.hpp +4 -4
  27. package/src/prelude/index.hpp +12 -2
  28. package/src/prelude/library/array.hpp +190 -0
  29. package/src/prelude/library/console.hpp +6 -5
  30. package/src/prelude/library/error.hpp +10 -8
  31. package/src/prelude/library/function.hpp +10 -0
  32. package/src/prelude/library/global.hpp +20 -0
  33. package/src/prelude/library/math.hpp +308 -0
  34. package/src/prelude/library/object.hpp +288 -0
  35. package/src/prelude/library/performance.hpp +1 -1
  36. package/src/prelude/library/process.hpp +39 -0
  37. package/src/prelude/library/promise.hpp +57 -55
  38. package/src/prelude/library/symbol.hpp +45 -57
  39. package/src/prelude/library/timer.hpp +6 -6
  40. package/src/prelude/types.hpp +54 -0
  41. package/src/prelude/utils/access.hpp +215 -11
  42. package/src/prelude/utils/assignment_operators.hpp +99 -0
  43. package/src/prelude/utils/log_any_value/array.hpp +8 -8
  44. package/src/prelude/utils/log_any_value/function.hpp +6 -4
  45. package/src/prelude/utils/log_any_value/object.hpp +41 -24
  46. package/src/prelude/utils/log_any_value/primitives.hpp +3 -1
  47. package/src/prelude/utils/operators.hpp +750 -274
  48. package/src/prelude/utils/well_known_symbols.hpp +12 -0
  49. package/src/prelude/values/array.hpp +8 -6
  50. package/src/prelude/values/async_iterator.hpp +79 -0
  51. package/src/prelude/values/descriptors.hpp +2 -2
  52. package/src/prelude/values/function.hpp +72 -62
  53. package/src/prelude/values/helpers/array.hpp +64 -28
  54. package/src/prelude/values/helpers/async_iterator.hpp +275 -0
  55. package/src/prelude/values/helpers/function.hpp +81 -92
  56. package/src/prelude/values/helpers/iterator.hpp +3 -3
  57. package/src/prelude/values/helpers/object.hpp +54 -9
  58. package/src/prelude/values/helpers/promise.hpp +13 -6
  59. package/src/prelude/values/iterator.hpp +1 -1
  60. package/src/prelude/values/object.hpp +10 -3
  61. package/src/prelude/values/promise.hpp +7 -11
  62. package/src/prelude/values/prototypes/array.hpp +851 -12
  63. package/src/prelude/values/prototypes/async_iterator.hpp +50 -0
  64. package/src/prelude/values/prototypes/function.hpp +2 -2
  65. package/src/prelude/values/prototypes/iterator.hpp +5 -5
  66. package/src/prelude/values/prototypes/number.hpp +153 -0
  67. package/src/prelude/values/prototypes/object.hpp +2 -2
  68. package/src/prelude/values/prototypes/promise.hpp +40 -30
  69. package/src/prelude/values/prototypes/string.hpp +28 -28
  70. package/src/prelude/values/prototypes/symbol.hpp +20 -3
  71. package/src/prelude/values/shape.hpp +52 -0
@@ -3,217 +3,62 @@
3
3
  #include "types.hpp"
4
4
  #include "any_value.hpp"
5
5
  #include "values/string.hpp"
6
+ #include "exception.hpp"
6
7
 
7
8
  namespace jspp
8
9
  {
9
- const bool AnyValue::is_truthy() const noexcept
10
+ std::string AnyValue::to_std_string() const
10
11
  {
11
- switch (storage.type)
12
- {
13
- case JsType::Boolean:
14
- return storage.boolean;
15
- case JsType::Number:
16
- return storage.number != 0.0;
17
- case JsType::String:
18
- return !storage.str->value.empty();
19
- case JsType::Undefined:
20
- return false;
21
- case JsType::Null:
22
- return false;
23
- case JsType::Uninitialized:
24
- return false;
25
- default:
26
- return true;
27
- }
28
- }
29
-
30
- const bool AnyValue::is_strictly_equal_to_primitive(const AnyValue &other) const noexcept
31
- {
32
- if (storage.type == other.storage.type)
33
- {
34
- switch (storage.type)
35
- {
36
- case JsType::Boolean:
37
- return storage.boolean == other.storage.boolean;
38
- case JsType::Number:
39
- return storage.number == other.storage.number;
40
- case JsType::String:
41
- return (storage.str->value == other.storage.str->value);
42
- case JsType::Array:
43
- return (storage.array == other.storage.array);
44
- case JsType::Object:
45
- return (storage.object == other.storage.object);
46
- case JsType::Function:
47
- return (storage.function == other.storage.function);
48
- case JsType::Iterator:
49
- return (storage.iterator == other.storage.iterator);
50
- case JsType::Promise:
51
- return (storage.promise == other.storage.promise);
52
- case JsType::Symbol:
53
- // Symbols are unique by reference/pointer identity
54
- return (storage.symbol == other.storage.symbol);
55
- case JsType::DataDescriptor:
56
- return storage.data_desc == other.storage.data_desc;
57
- case JsType::AccessorDescriptor:
58
- return storage.accessor_desc == other.storage.accessor_desc;
59
- default:
60
- return true;
61
- }
62
- }
63
- return false;
64
- }
65
- const bool AnyValue::is_equal_to_primitive(const AnyValue &other) const noexcept
66
- {
67
- // Implements JavaScript's Abstract Equality Comparison Algorithm (==)
68
- // Step 1: If types are the same, use strict equality (===)
69
- if (storage.type == other.storage.type)
70
- {
71
- return is_strictly_equal_to_primitive(other);
72
- }
73
- // Steps 2 & 3: null == undefined
74
- if ((is_null() && other.is_undefined()) || (is_undefined() && other.is_null()))
75
- {
76
- return true;
77
- }
78
- // Step 4 & 5: number == string
79
- if (is_number() && other.is_string())
80
- {
81
- double num_this = this->as_double();
82
- double num_other;
83
- try
84
- {
85
- const std::string &s = other.as_string()->value;
86
- // JS considers empty string or whitespace-only string to be 0
87
- if (s.empty() || std::all_of(s.begin(), s.end(), [](unsigned char c)
88
- { return std::isspace(c); }))
89
- {
90
- num_other = 0.0;
91
- }
92
- else
93
- {
94
- size_t pos;
95
- num_other = std::stod(s, &pos);
96
- // Check if the entire string was consumed, allowing for trailing whitespace
97
- while (pos < s.length() && std::isspace(static_cast<unsigned char>(s[pos])))
98
- {
99
- pos++;
100
- }
101
- if (pos != s.length())
102
- {
103
- num_other = std::numeric_limits<double>::quiet_NaN();
104
- }
105
- }
106
- }
107
- catch (...)
108
- {
109
- num_other = std::numeric_limits<double>::quiet_NaN();
110
- }
111
- return num_this == num_other;
112
- }
113
- if (is_string() && other.is_number())
114
- {
115
- // Delegate to the other operand to avoid code duplication
116
- return other.is_equal_to_primitive(*this);
117
- }
118
- // Step 6 & 7: boolean == any
119
- if (is_boolean())
120
- {
121
- // Convert boolean to number and re-compare
122
- return AnyValue::make_number(as_boolean() ? 1.0 : 0.0).is_equal_to_primitive(other);
123
- }
124
- if (other.is_boolean())
125
- {
126
- // Convert boolean to number and re-compare
127
- return is_equal_to_primitive(AnyValue::make_number(other.as_boolean() ? 1.0 : 0.0));
128
- }
129
- // Step 8 & 9: object == (string or number or symbol)
130
- // Simplified: Objects convert to primitives.
131
- if ((is_object() || is_array() || is_function() || is_promise() || is_iterator()) && (other.is_string() || other.is_number() || other.is_symbol()))
132
- {
133
- // Convert object to primitive (string) and re-compare.
134
- // This is a simplification of JS's ToPrimitive.
135
- return AnyValue::make_string(to_std_string()).is_equal_to_primitive(other);
136
- }
137
- if ((other.is_object() || other.is_array() || other.is_function() || other.is_promise() || other.is_iterator()) && (is_string() || is_number() || is_symbol()))
138
- {
139
- return other.is_equal_to_primitive(*this);
140
- }
141
- // Step 10: Datacriptor or accessor descriptor
142
- if (is_data_descriptor() || is_accessor_descriptor())
143
- {
144
- return (*this).is_strictly_equal_to_primitive(other);
145
- }
146
- // Step 11: All other cases (e.g., object == null) are false.
147
- return false;
148
- }
149
-
150
- const AnyValue AnyValue::is_strictly_equal_to(const AnyValue &other) const noexcept
151
- {
152
- return AnyValue::make_boolean(is_strictly_equal_to_primitive(other));
153
- }
154
- const AnyValue AnyValue::is_equal_to(const AnyValue &other) const noexcept
155
- {
156
- return AnyValue::make_boolean(is_equal_to_primitive(other));
157
- }
158
-
159
- const AnyValue AnyValue::not_strictly_equal_to(const AnyValue &other) const noexcept
160
- {
161
- return AnyValue::make_boolean(!is_strictly_equal_to_primitive(other));
162
- }
163
- const AnyValue AnyValue::not_equal_to(const AnyValue &other) const noexcept
164
- {
165
- return AnyValue::make_boolean(!is_equal_to_primitive(other));
166
- }
167
-
168
- const std::string AnyValue::to_std_string() const noexcept
169
- {
170
- switch (storage.type)
12
+ switch (get_type())
171
13
  {
172
14
  case JsType::Undefined:
173
15
  return "undefined";
174
16
  case JsType::Null:
175
17
  return "null";
176
18
  case JsType::Boolean:
177
- return storage.boolean ? "true" : "false";
19
+ return std::get<bool>(storage) ? "true" : "false";
178
20
  case JsType::String:
179
- return storage.str->to_std_string();
21
+ return std::get<std::shared_ptr<JsString>>(storage)->to_std_string();
180
22
  case JsType::Object:
181
- return storage.object->to_std_string();
23
+ return std::get<std::shared_ptr<JsObject>>(storage)->to_std_string();
182
24
  case JsType::Array:
183
- return storage.array->to_std_string();
25
+ return std::get<std::shared_ptr<JsArray>>(storage)->to_std_string();
184
26
  case JsType::Function:
185
- return storage.function->to_std_string();
27
+ return std::get<std::shared_ptr<JsFunction>>(storage)->to_std_string();
186
28
  case JsType::Iterator:
187
- return storage.iterator->to_std_string();
29
+ return std::get<std::shared_ptr<JsIterator<AnyValue>>>(storage)->to_std_string();
30
+ case JsType::AsyncIterator:
31
+ return std::get<std::shared_ptr<JsAsyncIterator<AnyValue>>>(storage)->to_std_string();
188
32
  case JsType::Promise:
189
- return storage.promise->to_std_string();
33
+ return std::get<std::shared_ptr<JsPromise>>(storage)->to_std_string();
190
34
  case JsType::Symbol:
191
- return storage.symbol->to_std_string();
35
+ return std::get<std::shared_ptr<JsSymbol>>(storage)->to_std_string();
192
36
  case JsType::DataDescriptor:
193
- return storage.data_desc->value->to_std_string();
37
+ return std::get<std::shared_ptr<DataDescriptor>>(storage)->value->to_std_string();
194
38
  case JsType::AccessorDescriptor:
195
39
  {
196
- if (storage.accessor_desc->get.has_value())
197
- return storage.accessor_desc->get.value()(*this, {}).to_std_string();
40
+ if (std::get<std::shared_ptr<AccessorDescriptor>>(storage)->get.has_value())
41
+ return std::get<std::shared_ptr<AccessorDescriptor>>(storage)->get.value()(*this, {}).to_std_string();
198
42
  else
199
43
  return "undefined";
200
44
  }
201
45
  case JsType::Number:
202
46
  {
203
- if (std::isnan(storage.number))
47
+ double num = std::get<double>(storage);
48
+ if (std::isnan(num))
204
49
  {
205
50
  return "NaN";
206
51
  }
207
- if (std::abs(storage.number) >= 1e21 || (std::abs(storage.number) > 0 && std::abs(storage.number) < 1e-6))
52
+ if (std::abs(num) >= 1e21 || (std::abs(num) > 0 && std::abs(num) < 1e-6))
208
53
  {
209
54
  std::ostringstream oss;
210
- oss << std::scientific << std::setprecision(4) << storage.number;
55
+ oss << std::scientific << std::setprecision(4) << num;
211
56
  return oss.str();
212
57
  }
213
58
  else
214
59
  {
215
60
  std::ostringstream oss;
216
- oss << std::setprecision(6) << std::fixed << storage.number;
61
+ oss << std::setprecision(6) << std::fixed << num;
217
62
  std::string s = oss.str();
218
63
  s.erase(s.find_last_not_of('0') + 1, std::string::npos);
219
64
  if (!s.empty() && s.back() == '.')
@@ -223,9 +68,8 @@ namespace jspp
223
68
  return s;
224
69
  }
225
70
  }
226
- // Uninitialized and default should not be reached under normal circumstances
227
71
  case JsType::Uninitialized:
228
- return "<uninitialized>";
72
+ Exception::throw_uninitialized_reference("#<Object>");
229
73
  default:
230
74
  return "";
231
75
  }
@@ -235,12 +79,63 @@ namespace jspp
235
79
  {
236
80
  if (is_object())
237
81
  {
238
- storage.object->proto = std::make_shared<AnyValue>(proto);
82
+ std::get<std::shared_ptr<JsObject>>(storage)->proto = std::make_shared<AnyValue>(proto);
83
+ }
84
+ else if (is_array())
85
+ {
86
+ std::get<std::shared_ptr<JsArray>>(storage)->proto = std::make_shared<AnyValue>(proto);
239
87
  }
240
88
  else if (is_function())
241
89
  {
242
- storage.function->proto = std::make_shared<AnyValue>(proto);
90
+ std::get<std::shared_ptr<JsFunction>>(storage)->proto = std::make_shared<AnyValue>(proto);
91
+ }
92
+ else if (is_uninitialized())
93
+ {
94
+ Exception::throw_uninitialized_reference("#<Object>");
95
+ }
96
+ }
97
+
98
+ // AnyValue::call implementation
99
+ const AnyValue AnyValue::call(const AnyValue &thisVal, std::span<const AnyValue> args, const std::optional<std::string> &expr = std::nullopt) const
100
+ {
101
+ if (!is_function())
102
+ {
103
+ throw Exception::make_exception(expr.value_or(to_std_string()) + " is not a function", "TypeError");
104
+ }
105
+ return as_function()->call(thisVal, args); // Convert to function before calling, to avoid an infinite loop
106
+ }
107
+
108
+ // AnyValue::construct implementation
109
+ const AnyValue AnyValue::construct(std::span<const AnyValue> args, const std::optional<std::string> &name) const
110
+ {
111
+ if (!is_function() || !as_function()->is_constructor)
112
+ {
113
+ // std::cerr << "Construct fail: " << name.value_or(to_std_string()) << " is_function=" << is_function() << " is_constructor=" << (is_function() ? as_function()->is_constructor : false) << std::endl;
114
+ throw Exception::make_exception(name.value_or(to_std_string()) + " is not a constructor", "TypeError");
115
+ }
116
+
117
+ // 1. Get prototype
118
+ AnyValue proto = get_own_property("prototype");
119
+ // If prototype is not an object, default to a plain object (which ideally inherits from Object.prototype)
120
+ // Here we just make a plain object.
121
+ if (!proto.is_object())
122
+ {
123
+ proto = AnyValue::make_object({});
124
+ }
125
+
126
+ // 2. Create instance
127
+ AnyValue instance = AnyValue::make_object_with_proto({}, proto);
128
+
129
+ // 3. Call function
130
+ // We pass 'instance' as 'this'
131
+ AnyValue result = call(instance, args);
132
+
133
+ // 4. Return result if object, else instance
134
+ if (result.is_object() || result.is_function() || result.is_array() || result.is_promise())
135
+ {
136
+ return result;
243
137
  }
138
+ return instance;
244
139
  }
245
140
 
246
141
  }
@@ -1,6 +1,7 @@
1
1
 
2
2
  #pragma once
3
3
 
4
+ #include <exception>
4
5
  #include "types.hpp"
5
6
 
6
7
  namespace jspp
@@ -12,10 +12,10 @@ const char *jspp::Exception::what() const noexcept
12
12
  jspp::Exception jspp::Exception::make_exception(const std::string &message, const std::string &name = "Error")
13
13
  {
14
14
  // Use the global Error object to construct the exception
15
- std::vector<AnyValue> args = { AnyValue::make_string(message) };
16
- AnyValue errorObj = ::Error.construct(args);
17
- errorObj.define_data_property("name", AnyValue::make_string(name));
18
-
15
+ std::vector<AnyValue> args = {AnyValue::make_string(message)};
16
+ AnyValue errorObj = ::Error.construct(args, name);
17
+ errorObj.define_data_property("name", AnyValue::make_string(name), true, false, true);
18
+
19
19
  return Exception(errorObj);
20
20
  }
21
21
  jspp::AnyValue jspp::Exception::exception_to_any_value(const std::exception &ex)
@@ -4,18 +4,19 @@
4
4
  #include "utils/well_known_symbols.hpp"
5
5
 
6
6
  // values
7
+ #include "values/shape.hpp"
7
8
  #include "values/symbol.hpp"
8
9
  #include "values/non_values.hpp"
9
10
  #include "values/object.hpp"
10
11
  #include "values/array.hpp"
11
12
  #include "values/function.hpp"
12
13
  #include "values/iterator.hpp"
14
+ #include "values/async_iterator.hpp"
13
15
  #include "values/promise.hpp"
14
16
  #include "values/string.hpp"
15
17
 
16
- #include "exception.hpp"
17
- #include "values/descriptors.hpp"
18
18
  #include "any_value.hpp"
19
+ #include "values/descriptors.hpp"
19
20
  #include "any_value_helpers.hpp"
20
21
  #include "any_value_access.hpp"
21
22
  #include "any_value_defines.hpp"
@@ -28,25 +29,34 @@
28
29
  #include "values/prototypes/array.hpp"
29
30
  #include "values/prototypes/function.hpp"
30
31
  #include "values/prototypes/iterator.hpp"
32
+ #include "values/prototypes/async_iterator.hpp"
31
33
  #include "values/prototypes/promise.hpp"
32
34
  #include "values/prototypes/string.hpp"
35
+ #include "values/prototypes/number.hpp"
33
36
 
34
37
  #include "values/helpers/symbol.hpp"
35
38
  #include "values/helpers/object.hpp"
36
39
  #include "values/helpers/array.hpp"
37
40
  #include "values/helpers/function.hpp"
38
41
  #include "values/helpers/iterator.hpp"
42
+ #include "values/helpers/async_iterator.hpp"
39
43
  #include "values/helpers/promise.hpp"
40
44
  #include "values/helpers/string.hpp"
41
45
 
42
46
  // utilities
43
47
  #include "utils/operators.hpp"
48
+ #include "utils/assignment_operators.hpp"
44
49
  #include "utils/access.hpp"
45
50
  #include "utils/log_any_value/log_any_value.hpp"
46
51
 
47
52
  // js standard libraries
48
53
  #include "library/symbol.hpp"
54
+ #include "library/process.hpp"
55
+ #include "library/function.hpp"
49
56
  #include "library/console.hpp"
50
57
  #include "library/performance.hpp"
51
58
  #include "library/promise.hpp"
59
+ #include "library/math.hpp"
60
+ #include "library/object.hpp"
61
+ #include "library/array.hpp"
52
62
  #include "library/global.hpp"
@@ -0,0 +1,190 @@
1
+ #pragma once
2
+
3
+ #include "types.hpp"
4
+ #include "any_value.hpp"
5
+ #include "utils/operators.hpp"
6
+ #include "utils/access.hpp"
7
+
8
+ inline auto Array = jspp::AnyValue::make_class([](const jspp::AnyValue &thisVal, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
9
+ {
10
+ if (args.size() == 1 && args[0].is_number()) {
11
+ double len = args[0].as_double();
12
+ if (len < 0 || len > 4294967295.0) { // Max uint32
13
+ throw jspp::Exception::make_exception("Invalid array length", "RangeError");
14
+ }
15
+ auto arr = jspp::AnyValue::make_array(std::vector<jspp::AnyValue>());
16
+ arr.as_array()->length = static_cast<uint64_t>(len);
17
+ arr.as_array()->dense.resize(static_cast<size_t>(len), jspp::AnyValue::make_uninitialized());
18
+ return arr;
19
+ }
20
+ std::vector<jspp::AnyValue> elements;
21
+ for(const auto& arg : args) {
22
+ elements.push_back(arg);
23
+ }
24
+ return jspp::AnyValue::make_array(std::move(elements)); }, "Array");
25
+
26
+ struct ArrayInit
27
+ {
28
+ ArrayInit()
29
+ {
30
+ // Set Array.prototype.proto to Object.prototype
31
+ // Array.get_own_property("prototype").set_prototype(::Object.get_own_property("prototype"));
32
+
33
+ // Array.isArray(value)
34
+ Array.define_data_property("isArray", jspp::AnyValue::make_function([](const jspp::AnyValue &, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
35
+ {
36
+ if (args.empty()) return jspp::Constants::FALSE;
37
+ return jspp::AnyValue::make_boolean(args[0].is_array()); }, "isArray"));
38
+
39
+ // Array.of(...elements)
40
+ Array.define_data_property("of", jspp::AnyValue::make_function([](const jspp::AnyValue &, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
41
+ {
42
+ std::vector<jspp::AnyValue> elements;
43
+ for(const auto& arg : args) {
44
+ elements.push_back(arg);
45
+ }
46
+ return jspp::AnyValue::make_array(std::move(elements)); }, "of"));
47
+
48
+ // Array.from(arrayLike, mapFn?, thisArg?)
49
+ Array.define_data_property("from", jspp::AnyValue::make_function([](const jspp::AnyValue &, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
50
+ {
51
+ if (args.empty() || args[0].is_null() || args[0].is_undefined()) {
52
+ throw jspp::Exception::make_exception("Array.from requires an array-like object", "TypeError");
53
+ }
54
+
55
+ const auto& items = args[0];
56
+ const auto& mapFn = (args.size() > 1 && args[1].is_function()) ? args[1] : jspp::Constants::UNDEFINED;
57
+ const auto& thisArg = (args.size() > 2) ? args[2] : jspp::Constants::UNDEFINED;
58
+
59
+ std::vector<jspp::AnyValue> result;
60
+
61
+ // Check if iterable
62
+ // Simple check: does it have [Symbol.iterator]?
63
+ auto iteratorSym = jspp::WellKnownSymbols::iterator;
64
+ if (items.has_property(iteratorSym->key)) {
65
+ auto iter = jspp::Access::get_object_value_iterator(items, "Array.from source");
66
+ auto nextFn = iter.get_own_property("next");
67
+
68
+ size_t k = 0;
69
+ while (true) {
70
+ auto nextRes = nextFn.call(iter, std::span<const jspp::AnyValue>{}, "next");
71
+ if (jspp::is_truthy(nextRes.get_own_property("done"))) break;
72
+
73
+ auto val = nextRes.get_own_property("value");
74
+ if (mapFn.is_function()) {
75
+ jspp::AnyValue kVal = jspp::AnyValue::make_number(k);
76
+ const jspp::AnyValue mapArgs[] = {val, kVal};
77
+ val = mapFn.call(thisArg, std::span<const jspp::AnyValue>(mapArgs, 2));
78
+ }
79
+ result.push_back(val);
80
+ k++;
81
+ }
82
+ } else {
83
+ // Array-like (length property)
84
+ auto lenVal = items.get_property_with_receiver("length", items);
85
+ size_t len = static_cast<size_t>(jspp::Operators_Private::ToUint32(lenVal));
86
+
87
+ for (size_t k = 0; k < len; ++k) {
88
+ auto kVal = items.get_property_with_receiver(std::to_string(k), items);
89
+ if (mapFn.is_function()) {
90
+ jspp::AnyValue kNum = jspp::AnyValue::make_number(k);
91
+ const jspp::AnyValue mapArgs[] = {kVal, kNum};
92
+ kVal = mapFn.call(thisArg, std::span<const jspp::AnyValue>(mapArgs, 2));
93
+ }
94
+ result.push_back(kVal);
95
+ }
96
+ }
97
+
98
+ return jspp::AnyValue::make_array(std::move(result)); }, "from"));
99
+
100
+ // Array.fromAsync(iterableOrArrayLike, mapFn?, thisArg?)
101
+ Array.define_data_property("fromAsync", jspp::AnyValue::make_async_function([](const jspp::AnyValue &, std::span<const jspp::AnyValue> args) -> jspp::JsPromise
102
+ {
103
+ if (args.empty() || args[0].is_null() || args[0].is_undefined()) {
104
+ throw jspp::Exception::make_exception("Array.fromAsync requires an iterable or array-like object", "TypeError");
105
+ }
106
+
107
+ const auto& items = args[0];
108
+ const auto& mapFn = (args.size() > 1 && args[1].is_function()) ? args[1] : jspp::Constants::UNDEFINED;
109
+ const auto& thisArg = (args.size() > 2) ? args[2] : jspp::Constants::UNDEFINED;
110
+
111
+ std::vector<jspp::AnyValue> result;
112
+
113
+ bool isAsync = false;
114
+ jspp::AnyValue iter;
115
+ jspp::AnyValue nextFn;
116
+
117
+ if (items.has_property(jspp::WellKnownSymbols::asyncIterator->key)) {
118
+ auto method = items.get_property_with_receiver(jspp::WellKnownSymbols::asyncIterator->key, items);
119
+ if (method.is_function()) {
120
+ iter = method.call(items, {});
121
+ nextFn = iter.get_own_property("next");
122
+ isAsync = true;
123
+ }
124
+ }
125
+
126
+ if (!isAsync && items.has_property(jspp::WellKnownSymbols::iterator->key)) {
127
+ auto method = items.get_property_with_receiver(jspp::WellKnownSymbols::iterator->key, items);
128
+ if (method.is_function()) {
129
+ iter = method.call(items, {});
130
+ nextFn = iter.get_own_property("next");
131
+ }
132
+ }
133
+
134
+ if (!iter.is_undefined()) {
135
+ size_t k = 0;
136
+ while (true) {
137
+ auto nextRes = nextFn.call(iter, {});
138
+
139
+ if (nextRes.is_promise()) {
140
+ nextRes = co_await nextRes;
141
+ }
142
+
143
+ if (jspp::is_truthy(nextRes.get_own_property("done"))) break;
144
+
145
+ auto val = nextRes.get_own_property("value");
146
+
147
+ if (mapFn.is_function()) {
148
+ jspp::AnyValue kVal = jspp::AnyValue::make_number(k);
149
+ const jspp::AnyValue mapArgs[] = {val, kVal};
150
+ auto mapRes = mapFn.call(thisArg, std::span<const jspp::AnyValue>(mapArgs, 2));
151
+ if (mapRes.is_promise()) {
152
+ val = co_await mapRes;
153
+ } else {
154
+ val = mapRes;
155
+ }
156
+ }
157
+ result.push_back(val);
158
+ k++;
159
+ }
160
+ } else {
161
+ auto lenVal = items.get_property_with_receiver("length", items);
162
+ size_t len = static_cast<size_t>(jspp::Operators_Private::ToUint32(lenVal));
163
+
164
+ for (size_t k = 0; k < len; ++k) {
165
+ auto kVal = items.get_property_with_receiver(std::to_string(k), items);
166
+ if (kVal.is_promise()) {
167
+ kVal = co_await kVal;
168
+ }
169
+
170
+ if (mapFn.is_function()) {
171
+ jspp::AnyValue kNum = jspp::AnyValue::make_number(k);
172
+ const jspp::AnyValue mapArgs[] = {kVal, kNum};
173
+ auto mapRes = mapFn.call(thisArg, std::span<const jspp::AnyValue>(mapArgs, 2));
174
+ if (mapRes.is_promise()) {
175
+ kVal = co_await mapRes;
176
+ } else {
177
+ kVal = mapRes;
178
+ }
179
+ }
180
+ result.push_back(kVal);
181
+ }
182
+ }
183
+
184
+ co_return jspp::AnyValue::make_array(std::move(result)); }, "fromAsync"));
185
+
186
+ // Array[Symbol.species]
187
+ Array.define_getter(jspp::AnyValue::from_symbol(jspp::WellKnownSymbols::species), jspp::AnyValue::make_function([](const jspp::AnyValue &thisVal, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
188
+ { return thisVal; }, "get [Symbol.species]"));
189
+ }
190
+ } arrayInit;
@@ -6,6 +6,7 @@
6
6
  #include "values/object.hpp"
7
7
  #include "values/function.hpp"
8
8
  #include "utils/operators.hpp"
9
+ #include "exception.hpp"
9
10
  #include "utils/log_any_value/log_any_value.hpp"
10
11
 
11
12
  #include <cmath>
@@ -14,7 +15,7 @@
14
15
 
15
16
  static std::map<std::string, std::chrono::steady_clock::time_point> timers = {};
16
17
 
17
- auto logFn = jspp::AnyValue::make_function([](const jspp::AnyValue &thisVal, const std::vector<jspp::AnyValue> &args)
18
+ auto logFn = jspp::AnyValue::make_function([](const jspp::AnyValue &thisVal, std::span<const jspp::AnyValue> args)
18
19
  {
19
20
  for (size_t i = 0; i < args.size(); ++i)
20
21
  {
@@ -24,7 +25,7 @@ auto logFn = jspp::AnyValue::make_function([](const jspp::AnyValue &thisVal, con
24
25
  }
25
26
  std::cout << "\n" << std::flush;
26
27
  return jspp::AnyValue::make_undefined(); }, "log");
27
- auto warnFn = jspp::AnyValue::make_function([](const jspp::AnyValue &thisVal, const std::vector<jspp::AnyValue> &args)
28
+ auto warnFn = jspp::AnyValue::make_function([](const jspp::AnyValue &thisVal, std::span<const jspp::AnyValue> args)
28
29
  {
29
30
  std::cerr << "\033[33m";
30
31
  for (size_t i = 0; i < args.size(); ++i)
@@ -35,7 +36,7 @@ auto warnFn = jspp::AnyValue::make_function([](const jspp::AnyValue &thisVal, co
35
36
  }
36
37
  std::cerr << "\033[0m" << "\n" << std::flush; // reset
37
38
  return jspp::AnyValue::make_undefined(); }, "warn");
38
- auto errorFn = jspp::AnyValue::make_function([](const jspp::AnyValue &thisVal, const std::vector<jspp::AnyValue> &args)
39
+ auto errorFn = jspp::AnyValue::make_function([](const jspp::AnyValue &thisVal, std::span<const jspp::AnyValue> args)
39
40
  {
40
41
  std::cerr << "\033[31m";
41
42
  for (size_t i = 0; i < args.size(); ++i)
@@ -46,7 +47,7 @@ auto errorFn = jspp::AnyValue::make_function([](const jspp::AnyValue &thisVal, c
46
47
  }
47
48
  std::cerr << "\033[0m" << "\n" << std::flush; // reset
48
49
  return jspp::AnyValue::make_undefined(); }, "error");
49
- auto timeFn = jspp::AnyValue::make_function([](const jspp::AnyValue &thisVal, const std::vector<jspp::AnyValue> &args)
50
+ auto timeFn = jspp::AnyValue::make_function([](const jspp::AnyValue &thisVal, std::span<const jspp::AnyValue> args)
50
51
  {
51
52
  auto start = std::chrono::steady_clock::now(); // capture immediately
52
53
  auto key_str = args.size() > 0 ? args[0].to_std_string() : "default";
@@ -83,7 +84,7 @@ static auto format_duration = [](double ms) -> std::string
83
84
  return ss.str();
84
85
  };
85
86
 
86
- auto timeEndFn = jspp::AnyValue::make_function([](const jspp::AnyValue &thisVal, const std::vector<jspp::AnyValue> &args)
87
+ auto timeEndFn = jspp::AnyValue::make_function([](const jspp::AnyValue &thisVal, std::span<const jspp::AnyValue> args)
87
88
  {
88
89
  auto end = std::chrono::steady_clock::now(); // capture immediately
89
90
  auto key_str = args.size() > 0 ? args[0].to_std_string() : "default";