@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.
- package/dist/analysis/scope.js +17 -0
- package/dist/analysis/typeAnalyzer.js +7 -1
- package/dist/ast/symbols.js +32 -0
- package/dist/ast/types.js +0 -6
- package/dist/cli-utils/args.js +57 -0
- package/dist/cli-utils/colors.js +9 -0
- package/dist/cli-utils/file-utils.js +20 -0
- package/dist/cli-utils/spinner.js +55 -0
- package/dist/cli.js +105 -30
- package/dist/core/codegen/class-handlers.js +10 -6
- package/dist/core/codegen/control-flow-handlers.js +57 -28
- package/dist/core/codegen/declaration-handlers.js +10 -6
- package/dist/core/codegen/expression-handlers.js +206 -61
- package/dist/core/codegen/function-handlers.js +203 -76
- package/dist/core/codegen/helpers.js +125 -28
- package/dist/core/codegen/index.js +23 -15
- package/dist/core/codegen/literal-handlers.js +15 -6
- package/dist/core/codegen/statement-handlers.js +282 -84
- package/dist/core/codegen/visitor.js +3 -1
- package/package.json +1 -1
- package/src/prelude/any_value.hpp +221 -342
- package/src/prelude/any_value_access.hpp +168 -81
- package/src/prelude/any_value_defines.hpp +74 -35
- package/src/prelude/any_value_helpers.hpp +75 -180
- package/src/prelude/exception.hpp +1 -0
- package/src/prelude/exception_helpers.hpp +4 -4
- package/src/prelude/index.hpp +12 -2
- package/src/prelude/library/array.hpp +190 -0
- package/src/prelude/library/console.hpp +6 -5
- package/src/prelude/library/error.hpp +10 -8
- package/src/prelude/library/function.hpp +10 -0
- package/src/prelude/library/global.hpp +20 -0
- package/src/prelude/library/math.hpp +308 -0
- package/src/prelude/library/object.hpp +288 -0
- package/src/prelude/library/performance.hpp +1 -1
- package/src/prelude/library/process.hpp +39 -0
- package/src/prelude/library/promise.hpp +57 -55
- package/src/prelude/library/symbol.hpp +45 -57
- package/src/prelude/library/timer.hpp +6 -6
- package/src/prelude/types.hpp +54 -0
- package/src/prelude/utils/access.hpp +215 -11
- package/src/prelude/utils/assignment_operators.hpp +99 -0
- package/src/prelude/utils/log_any_value/array.hpp +8 -8
- package/src/prelude/utils/log_any_value/function.hpp +6 -4
- package/src/prelude/utils/log_any_value/object.hpp +41 -24
- package/src/prelude/utils/log_any_value/primitives.hpp +3 -1
- package/src/prelude/utils/operators.hpp +750 -274
- package/src/prelude/utils/well_known_symbols.hpp +12 -0
- package/src/prelude/values/array.hpp +8 -6
- package/src/prelude/values/async_iterator.hpp +79 -0
- package/src/prelude/values/descriptors.hpp +2 -2
- package/src/prelude/values/function.hpp +72 -62
- package/src/prelude/values/helpers/array.hpp +64 -28
- package/src/prelude/values/helpers/async_iterator.hpp +275 -0
- package/src/prelude/values/helpers/function.hpp +81 -92
- package/src/prelude/values/helpers/iterator.hpp +3 -3
- package/src/prelude/values/helpers/object.hpp +54 -9
- package/src/prelude/values/helpers/promise.hpp +13 -6
- package/src/prelude/values/iterator.hpp +1 -1
- package/src/prelude/values/object.hpp +10 -3
- package/src/prelude/values/promise.hpp +7 -11
- package/src/prelude/values/prototypes/array.hpp +851 -12
- package/src/prelude/values/prototypes/async_iterator.hpp +50 -0
- package/src/prelude/values/prototypes/function.hpp +2 -2
- package/src/prelude/values/prototypes/iterator.hpp +5 -5
- package/src/prelude/values/prototypes/number.hpp +153 -0
- package/src/prelude/values/prototypes/object.hpp +2 -2
- package/src/prelude/values/prototypes/promise.hpp +40 -30
- package/src/prelude/values/prototypes/string.hpp +28 -28
- package/src/prelude/values/prototypes/symbol.hpp +20 -3
- 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
|
-
|
|
10
|
+
std::string AnyValue::to_std_string() const
|
|
10
11
|
{
|
|
11
|
-
switch (
|
|
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
|
|
19
|
+
return std::get<bool>(storage) ? "true" : "false";
|
|
178
20
|
case JsType::String:
|
|
179
|
-
return storage
|
|
21
|
+
return std::get<std::shared_ptr<JsString>>(storage)->to_std_string();
|
|
180
22
|
case JsType::Object:
|
|
181
|
-
return storage
|
|
23
|
+
return std::get<std::shared_ptr<JsObject>>(storage)->to_std_string();
|
|
182
24
|
case JsType::Array:
|
|
183
|
-
return storage
|
|
25
|
+
return std::get<std::shared_ptr<JsArray>>(storage)->to_std_string();
|
|
184
26
|
case JsType::Function:
|
|
185
|
-
return storage
|
|
27
|
+
return std::get<std::shared_ptr<JsFunction>>(storage)->to_std_string();
|
|
186
28
|
case JsType::Iterator:
|
|
187
|
-
return storage
|
|
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
|
|
33
|
+
return std::get<std::shared_ptr<JsPromise>>(storage)->to_std_string();
|
|
190
34
|
case JsType::Symbol:
|
|
191
|
-
return storage
|
|
35
|
+
return std::get<std::shared_ptr<JsSymbol>>(storage)->to_std_string();
|
|
192
36
|
case JsType::DataDescriptor:
|
|
193
|
-
return storage
|
|
37
|
+
return std::get<std::shared_ptr<DataDescriptor>>(storage)->value->to_std_string();
|
|
194
38
|
case JsType::AccessorDescriptor:
|
|
195
39
|
{
|
|
196
|
-
if (storage
|
|
197
|
-
return storage
|
|
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
|
-
|
|
47
|
+
double num = std::get<double>(storage);
|
|
48
|
+
if (std::isnan(num))
|
|
204
49
|
{
|
|
205
50
|
return "NaN";
|
|
206
51
|
}
|
|
207
|
-
if (std::abs(
|
|
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) <<
|
|
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 <<
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
}
|
|
@@ -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 = {
|
|
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)
|
package/src/prelude/index.hpp
CHANGED
|
@@ -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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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";
|