@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
|
@@ -1,275 +1,751 @@
|
|
|
1
|
-
#pragma once
|
|
2
|
-
|
|
3
|
-
#include "types.hpp"
|
|
4
|
-
#include "any_value.hpp"
|
|
5
|
-
#include <cstdint>
|
|
6
|
-
#include <cmath>
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
case JsType::
|
|
24
|
-
return
|
|
25
|
-
case JsType::
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
return
|
|
164
|
-
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
return rhs;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "types.hpp"
|
|
4
|
+
#include "any_value.hpp"
|
|
5
|
+
#include <cstdint> // For int32_t
|
|
6
|
+
#include <cmath> // For fmod, isnan, isinf, floor, abs, pow
|
|
7
|
+
#include <string> // For std::to_string, std::stod
|
|
8
|
+
#include <algorithm> // For std::all_of
|
|
9
|
+
#include <limits> // For numeric_limits
|
|
10
|
+
|
|
11
|
+
namespace jspp
|
|
12
|
+
{
|
|
13
|
+
// Private namespace for helper functions that implement JS type conversions.
|
|
14
|
+
namespace Operators_Private
|
|
15
|
+
{
|
|
16
|
+
// Implements the ToNumber abstract operation from ECMA-262.
|
|
17
|
+
inline double ToNumber(const AnyValue &val)
|
|
18
|
+
{
|
|
19
|
+
switch (val.get_type())
|
|
20
|
+
{
|
|
21
|
+
case JsType::Number:
|
|
22
|
+
return val.as_double();
|
|
23
|
+
case JsType::Null:
|
|
24
|
+
return 0.0;
|
|
25
|
+
case JsType::Uninitialized:
|
|
26
|
+
case JsType::Undefined:
|
|
27
|
+
return std::numeric_limits<double>::quiet_NaN();
|
|
28
|
+
case JsType::Boolean:
|
|
29
|
+
return val.as_boolean() ? 1.0 : 0.0;
|
|
30
|
+
case JsType::String:
|
|
31
|
+
{
|
|
32
|
+
const std::string &s = val.as_string()->value;
|
|
33
|
+
// JS considers empty or whitespace-only strings as 0.
|
|
34
|
+
if (s.empty() || std::all_of(s.begin(), s.end(), isspace))
|
|
35
|
+
return 0.0;
|
|
36
|
+
try
|
|
37
|
+
{
|
|
38
|
+
size_t pos;
|
|
39
|
+
double num = std::stod(s, &pos);
|
|
40
|
+
// Ensure the entire string was parsed, allowing for trailing whitespace.
|
|
41
|
+
while (pos < s.length() && std::isspace(s[pos]))
|
|
42
|
+
pos++;
|
|
43
|
+
if (pos != s.length())
|
|
44
|
+
return std::numeric_limits<double>::quiet_NaN();
|
|
45
|
+
return num;
|
|
46
|
+
}
|
|
47
|
+
catch (...)
|
|
48
|
+
{
|
|
49
|
+
return std::numeric_limits<double>::quiet_NaN();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
default:
|
|
53
|
+
// In a full engine, objects would be converted via valueOf/toString.
|
|
54
|
+
// Here we simplify and return NaN.
|
|
55
|
+
return std::numeric_limits<double>::quiet_NaN();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Implements the ToInt32 abstract operation from ECMA-262.
|
|
59
|
+
inline int32_t ToInt32(const AnyValue &val)
|
|
60
|
+
{
|
|
61
|
+
double num = ToNumber(val);
|
|
62
|
+
|
|
63
|
+
if (std::isnan(num) || std::isinf(num) || num == 0)
|
|
64
|
+
return 0;
|
|
65
|
+
|
|
66
|
+
double posInt = std::signbit(num) ? -std::floor(std::abs(num)) : std::floor(std::abs(num));
|
|
67
|
+
double int32bit = fmod(posInt, 4294967296.0); // 2^32
|
|
68
|
+
|
|
69
|
+
if (int32bit >= 2147483648.0) // 2^31
|
|
70
|
+
return static_cast<int32_t>(int32bit - 4294967296.0);
|
|
71
|
+
else
|
|
72
|
+
return static_cast<int32_t>(int32bit);
|
|
73
|
+
}
|
|
74
|
+
// Implements the ToUint32 abstract operation from ECMA-262.
|
|
75
|
+
inline uint32_t ToUint32(const AnyValue &val)
|
|
76
|
+
{
|
|
77
|
+
double num = ToNumber(val);
|
|
78
|
+
if (std::isnan(num) || std::isinf(num) || num == 0)
|
|
79
|
+
return 0;
|
|
80
|
+
double posInt = std::signbit(num) ? -std::floor(std::abs(num)) : std::floor(std::abs(num));
|
|
81
|
+
uint32_t uint32bit = static_cast<uint32_t>(fmod(posInt, 4294967296.0));
|
|
82
|
+
return uint32bit;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// --- TRUTHY CHECKER ---
|
|
87
|
+
const bool is_truthy(const double &val) noexcept
|
|
88
|
+
{
|
|
89
|
+
return val != 0.0 && !std::isnan(val);
|
|
90
|
+
}
|
|
91
|
+
const bool is_truthy(const std::string &val) noexcept
|
|
92
|
+
{
|
|
93
|
+
return !val.empty();
|
|
94
|
+
}
|
|
95
|
+
const bool is_truthy(const AnyValue &val) noexcept
|
|
96
|
+
{
|
|
97
|
+
switch (val.get_type())
|
|
98
|
+
{
|
|
99
|
+
case JsType::Boolean:
|
|
100
|
+
return val.as_boolean();
|
|
101
|
+
case JsType::Number:
|
|
102
|
+
return is_truthy(val.as_double());
|
|
103
|
+
case JsType::String:
|
|
104
|
+
return !val.as_string()->value.empty();
|
|
105
|
+
case JsType::Undefined:
|
|
106
|
+
return false;
|
|
107
|
+
case JsType::Null:
|
|
108
|
+
return false;
|
|
109
|
+
case JsType::Uninitialized:
|
|
110
|
+
return false;
|
|
111
|
+
default:
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// --- BASIC EQUALITY ---
|
|
117
|
+
|
|
118
|
+
// Operator === (returns primitive boolean)
|
|
119
|
+
inline const bool is_strictly_equal_to_primitive(const AnyValue &lhs, const double &rhs) noexcept
|
|
120
|
+
{
|
|
121
|
+
return is_strictly_equal_to_primitive(rhs, lhs);
|
|
122
|
+
}
|
|
123
|
+
inline const bool is_strictly_equal_to_primitive(const double &lhs, const AnyValue &rhs) noexcept
|
|
124
|
+
{
|
|
125
|
+
if (rhs.is_number())
|
|
126
|
+
return lhs == rhs.as_double();
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
inline const bool is_strictly_equal_to_primitive(const double &lhs, const double &rhs) noexcept
|
|
130
|
+
{
|
|
131
|
+
return lhs == rhs;
|
|
132
|
+
}
|
|
133
|
+
inline const bool is_strictly_equal_to_primitive(const AnyValue &lhs, const AnyValue &rhs) noexcept
|
|
134
|
+
{
|
|
135
|
+
JsType type = lhs.get_type();
|
|
136
|
+
if (type != rhs.get_type())
|
|
137
|
+
return false;
|
|
138
|
+
switch (type)
|
|
139
|
+
{
|
|
140
|
+
case JsType::Boolean:
|
|
141
|
+
return lhs.as_boolean() == rhs.as_boolean();
|
|
142
|
+
case JsType::Number:
|
|
143
|
+
return lhs.as_double() == rhs.as_double();
|
|
144
|
+
case JsType::String:
|
|
145
|
+
return lhs.as_string()->value == rhs.as_string()->value;
|
|
146
|
+
case JsType::Array:
|
|
147
|
+
return lhs.as_array() == rhs.as_array();
|
|
148
|
+
case JsType::Object:
|
|
149
|
+
return lhs.as_object() == rhs.as_object();
|
|
150
|
+
case JsType::Function:
|
|
151
|
+
return lhs.as_function() == rhs.as_function();
|
|
152
|
+
case JsType::Iterator:
|
|
153
|
+
return lhs.as_iterator() == rhs.as_iterator();
|
|
154
|
+
case JsType::Promise:
|
|
155
|
+
return lhs.as_promise() == rhs.as_promise();
|
|
156
|
+
case JsType::Symbol:
|
|
157
|
+
return lhs.as_symbol() == rhs.as_symbol();
|
|
158
|
+
case JsType::DataDescriptor:
|
|
159
|
+
return lhs.as_data_descriptor() == rhs.as_data_descriptor();
|
|
160
|
+
case JsType::AccessorDescriptor:
|
|
161
|
+
return lhs.as_accessor_descriptor() == rhs.as_accessor_descriptor();
|
|
162
|
+
default:
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Operator == (returns primitive boolean)
|
|
168
|
+
inline const bool is_equal_to_primitive(const AnyValue &lhs, const double &rhs) noexcept
|
|
169
|
+
{
|
|
170
|
+
return is_equal_to_primitive(rhs, lhs);
|
|
171
|
+
}
|
|
172
|
+
inline const bool is_equal_to_primitive(const double &lhs, const AnyValue &rhs) noexcept
|
|
173
|
+
{
|
|
174
|
+
JsType rhs_type = rhs.get_type();
|
|
175
|
+
if (rhs_type == JsType::Number)
|
|
176
|
+
{
|
|
177
|
+
return lhs == rhs.as_double();
|
|
178
|
+
}
|
|
179
|
+
if (rhs_type == JsType::String)
|
|
180
|
+
{
|
|
181
|
+
double num_rhs;
|
|
182
|
+
try
|
|
183
|
+
{
|
|
184
|
+
const std::string &s = rhs.as_string()->value;
|
|
185
|
+
// JS considers empty string or whitespace-only string to be 0
|
|
186
|
+
if (s.empty() || std::all_of(s.begin(), s.end(), [](unsigned char c)
|
|
187
|
+
{ return std::isspace(c); }))
|
|
188
|
+
{
|
|
189
|
+
num_rhs = 0.0;
|
|
190
|
+
}
|
|
191
|
+
else
|
|
192
|
+
{
|
|
193
|
+
size_t pos;
|
|
194
|
+
num_rhs = std::stod(s, &pos);
|
|
195
|
+
// Check if the entire string was consumed, allowing for trailing whitespace
|
|
196
|
+
while (pos < s.length() && std::isspace(static_cast<unsigned char>(s[pos])))
|
|
197
|
+
{
|
|
198
|
+
pos++;
|
|
199
|
+
}
|
|
200
|
+
if (pos != s.length())
|
|
201
|
+
{
|
|
202
|
+
num_rhs = std::numeric_limits<double>::quiet_NaN();
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
catch (...)
|
|
207
|
+
{
|
|
208
|
+
num_rhs = std::numeric_limits<double>::quiet_NaN();
|
|
209
|
+
}
|
|
210
|
+
return lhs == num_rhs;
|
|
211
|
+
}
|
|
212
|
+
return is_equal_to_primitive(rhs, AnyValue::make_number(lhs));
|
|
213
|
+
}
|
|
214
|
+
inline const bool is_equal_to_primitive(const double &lhs, const double &rhs) noexcept
|
|
215
|
+
{
|
|
216
|
+
return lhs == rhs;
|
|
217
|
+
}
|
|
218
|
+
inline const bool is_equal_to_primitive(const AnyValue &lhs, const AnyValue &rhs) noexcept
|
|
219
|
+
{
|
|
220
|
+
JsType lhs_type = lhs.get_type();
|
|
221
|
+
JsType rhs_type = rhs.get_type();
|
|
222
|
+
// Implements JavaScript's Abstract Equality Comparison Algorithm (==)
|
|
223
|
+
// Step 1: If types are the same, use strict equality (===)
|
|
224
|
+
if (lhs_type == rhs_type)
|
|
225
|
+
{
|
|
226
|
+
return is_strictly_equal_to_primitive(lhs, rhs);
|
|
227
|
+
}
|
|
228
|
+
// Steps 2 & 3: null == undefined
|
|
229
|
+
if ((lhs_type == JsType::Null && rhs_type == JsType::Undefined) || (lhs_type == JsType::Undefined && rhs_type == JsType::Null))
|
|
230
|
+
{
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
// Step 4 & 5: number == string
|
|
234
|
+
if (lhs_type == JsType::Number && rhs_type == JsType::String)
|
|
235
|
+
{
|
|
236
|
+
return is_equal_to_primitive(lhs.as_double(), rhs);
|
|
237
|
+
}
|
|
238
|
+
if (lhs_type == JsType::String && rhs_type == JsType::Number)
|
|
239
|
+
{
|
|
240
|
+
// Delegate to the other operand to avoid code duplication
|
|
241
|
+
return is_equal_to_primitive(rhs.as_double(), lhs);
|
|
242
|
+
}
|
|
243
|
+
// Step 6 & 7: boolean == any
|
|
244
|
+
if (lhs_type == JsType::Boolean)
|
|
245
|
+
{
|
|
246
|
+
// Convert boolean to number and re-compare
|
|
247
|
+
return is_equal_to_primitive(lhs.as_boolean() ? 1.0 : 0.0, rhs);
|
|
248
|
+
}
|
|
249
|
+
if (rhs_type == JsType::Boolean)
|
|
250
|
+
{
|
|
251
|
+
// Convert boolean to number and re-compare
|
|
252
|
+
return is_equal_to_primitive(lhs, AnyValue::make_number(rhs.as_boolean() ? 1.0 : 0.0));
|
|
253
|
+
}
|
|
254
|
+
// Step 8 & 9: object == (string or number or symbol)
|
|
255
|
+
// Simplified: Objects convert to primitives.
|
|
256
|
+
if ((lhs_type == JsType::Object || lhs_type == JsType::Array || lhs_type == JsType::Function || lhs_type == JsType::Promise || lhs_type == JsType::Iterator) &&
|
|
257
|
+
(rhs_type == JsType::String || rhs_type == JsType::Number || rhs_type == JsType::Symbol))
|
|
258
|
+
{
|
|
259
|
+
// Convert object to primitive (string) and re-compare.
|
|
260
|
+
// This is a simplification of JS's ToPrimitive.
|
|
261
|
+
return is_equal_to_primitive(AnyValue::make_string(lhs.to_std_string()), rhs);
|
|
262
|
+
}
|
|
263
|
+
if ((rhs_type == JsType::Object || rhs_type == JsType::Array || rhs_type == JsType::Function || rhs_type == JsType::Promise || rhs_type == JsType::Iterator) &&
|
|
264
|
+
(lhs_type == JsType::String || lhs_type == JsType::Number || lhs_type == JsType::Symbol))
|
|
265
|
+
{
|
|
266
|
+
return is_equal_to_primitive(rhs, lhs);
|
|
267
|
+
}
|
|
268
|
+
// Step 10: Datacriptor or accessor descriptor
|
|
269
|
+
if (lhs_type == JsType::DataDescriptor || lhs_type == JsType::AccessorDescriptor)
|
|
270
|
+
{
|
|
271
|
+
return is_strictly_equal_to_primitive(lhs, rhs);
|
|
272
|
+
}
|
|
273
|
+
// Step 11: All other cases (e.g., object == null) are false.
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Operator === (returns boolean wrapped in AnyValue)
|
|
278
|
+
inline const AnyValue is_strictly_equal_to(const AnyValue &lhs, const double &rhs) noexcept
|
|
279
|
+
{
|
|
280
|
+
return AnyValue::make_boolean(is_strictly_equal_to_primitive(lhs, rhs));
|
|
281
|
+
}
|
|
282
|
+
inline const AnyValue is_strictly_equal_to(const double &lhs, const AnyValue &rhs) noexcept
|
|
283
|
+
{
|
|
284
|
+
return AnyValue::make_boolean(is_strictly_equal_to_primitive(lhs, rhs));
|
|
285
|
+
}
|
|
286
|
+
inline const AnyValue is_strictly_equal_to(const double &lhs, const double &rhs) noexcept
|
|
287
|
+
{
|
|
288
|
+
return AnyValue::make_boolean(is_strictly_equal_to_primitive(lhs, rhs));
|
|
289
|
+
}
|
|
290
|
+
inline const AnyValue is_strictly_equal_to(const AnyValue &lhs, const AnyValue &rhs) noexcept
|
|
291
|
+
{
|
|
292
|
+
return AnyValue::make_boolean(is_strictly_equal_to_primitive(lhs, rhs));
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Operator == (returns boolean wrapped in AnyValue)
|
|
296
|
+
inline const AnyValue is_equal_to(const AnyValue &lhs, const double &rhs) noexcept
|
|
297
|
+
{
|
|
298
|
+
return AnyValue::make_boolean(is_equal_to_primitive(lhs, rhs));
|
|
299
|
+
}
|
|
300
|
+
inline const AnyValue is_equal_to(const double &lhs, const AnyValue &rhs) noexcept
|
|
301
|
+
{
|
|
302
|
+
return AnyValue::make_boolean(is_equal_to_primitive(lhs, rhs));
|
|
303
|
+
}
|
|
304
|
+
inline const AnyValue is_equal_to(const double &lhs, const double &rhs) noexcept
|
|
305
|
+
{
|
|
306
|
+
return AnyValue::make_boolean(is_equal_to_primitive(lhs, rhs));
|
|
307
|
+
}
|
|
308
|
+
inline const AnyValue is_equal_to(const AnyValue &lhs, const AnyValue &rhs) noexcept
|
|
309
|
+
{
|
|
310
|
+
return AnyValue::make_boolean(is_equal_to_primitive(lhs, rhs));
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Operator !== (returns boolean wrapped in AnyValue)
|
|
314
|
+
inline const AnyValue not_strictly_equal_to(const AnyValue &lhs, const double &rhs) noexcept
|
|
315
|
+
{
|
|
316
|
+
return AnyValue::make_boolean(!is_strictly_equal_to_primitive(lhs, rhs));
|
|
317
|
+
}
|
|
318
|
+
inline const AnyValue not_strictly_equal_to(const double &lhs, const AnyValue &rhs) noexcept
|
|
319
|
+
{
|
|
320
|
+
return AnyValue::make_boolean(!is_strictly_equal_to_primitive(lhs, rhs));
|
|
321
|
+
}
|
|
322
|
+
inline const AnyValue not_strictly_equal_to(const double &lhs, const double &rhs) noexcept
|
|
323
|
+
{
|
|
324
|
+
return AnyValue::make_boolean(!is_strictly_equal_to_primitive(lhs, rhs));
|
|
325
|
+
}
|
|
326
|
+
inline const AnyValue not_strictly_equal_to(const AnyValue &lhs, const AnyValue &rhs) noexcept
|
|
327
|
+
{
|
|
328
|
+
return AnyValue::make_boolean(!is_strictly_equal_to_primitive(lhs, rhs));
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Operator != (returns boolean wrapped in AnyValue)
|
|
332
|
+
inline const AnyValue not_equal_to(const AnyValue &lhs, const double &rhs) noexcept
|
|
333
|
+
{
|
|
334
|
+
return AnyValue::make_boolean(!is_equal_to_primitive(lhs, rhs));
|
|
335
|
+
}
|
|
336
|
+
inline const AnyValue not_equal_to(const double &lhs, const AnyValue &rhs) noexcept
|
|
337
|
+
{
|
|
338
|
+
return AnyValue::make_boolean(!is_equal_to_primitive(lhs, rhs));
|
|
339
|
+
}
|
|
340
|
+
inline const AnyValue not_equal_to(const double &lhs, const double &rhs) noexcept
|
|
341
|
+
{
|
|
342
|
+
return AnyValue::make_boolean(!is_equal_to_primitive(lhs, rhs));
|
|
343
|
+
}
|
|
344
|
+
inline const AnyValue not_equal_to(const AnyValue &lhs, const AnyValue &rhs) noexcept
|
|
345
|
+
{
|
|
346
|
+
return AnyValue::make_boolean(!is_equal_to_primitive(lhs, rhs));
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// --- BASIC ARITHMETIC ---
|
|
350
|
+
|
|
351
|
+
// Operator +
|
|
352
|
+
inline AnyValue operator+(const AnyValue &lhs, const AnyValue &rhs)
|
|
353
|
+
{
|
|
354
|
+
// Check for number optimization
|
|
355
|
+
if (lhs.is_number() && rhs.is_number())
|
|
356
|
+
return AnyValue::make_number(lhs.as_double() + rhs.as_double());
|
|
357
|
+
// String concatenation priority
|
|
358
|
+
if (lhs.is_string() || rhs.is_string())
|
|
359
|
+
return AnyValue::make_string(lhs.to_std_string() + rhs.to_std_string());
|
|
360
|
+
// Fallback
|
|
361
|
+
return AnyValue::make_number(Operators_Private::ToNumber(lhs) + Operators_Private::ToNumber(rhs));
|
|
362
|
+
}
|
|
363
|
+
inline AnyValue operator+(const AnyValue &lhs, const double &rhs)
|
|
364
|
+
{
|
|
365
|
+
if (lhs.is_number())
|
|
366
|
+
return AnyValue::make_number(lhs.as_double() + rhs);
|
|
367
|
+
if (lhs.is_string())
|
|
368
|
+
return AnyValue::make_string(lhs.to_std_string() + std::to_string(rhs));
|
|
369
|
+
return AnyValue::make_number(Operators_Private::ToNumber(lhs) + rhs);
|
|
370
|
+
}
|
|
371
|
+
inline AnyValue operator+(const double &lhs, const AnyValue &rhs)
|
|
372
|
+
{
|
|
373
|
+
if (rhs.is_number())
|
|
374
|
+
return AnyValue::make_number(lhs + rhs.as_double());
|
|
375
|
+
if (rhs.is_string())
|
|
376
|
+
return AnyValue::make_string(std::to_string(lhs) + rhs.to_std_string());
|
|
377
|
+
return AnyValue::make_number(lhs + Operators_Private::ToNumber(rhs));
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// Operator -
|
|
381
|
+
inline AnyValue operator-(const AnyValue &lhs, const AnyValue &rhs)
|
|
382
|
+
{
|
|
383
|
+
if (lhs.is_number() && rhs.is_number())
|
|
384
|
+
return AnyValue::make_number(lhs.as_double() - rhs.as_double());
|
|
385
|
+
return AnyValue::make_number(Operators_Private::ToNumber(lhs) - Operators_Private::ToNumber(rhs));
|
|
386
|
+
}
|
|
387
|
+
inline AnyValue operator-(const AnyValue &lhs, const double &rhs)
|
|
388
|
+
{
|
|
389
|
+
if (lhs.is_number())
|
|
390
|
+
return AnyValue::make_number(lhs.as_double() - rhs);
|
|
391
|
+
return AnyValue::make_number(Operators_Private::ToNumber(lhs) - rhs);
|
|
392
|
+
}
|
|
393
|
+
inline AnyValue operator-(const double &lhs, const AnyValue &rhs)
|
|
394
|
+
{
|
|
395
|
+
if (rhs.is_number())
|
|
396
|
+
return AnyValue::make_number(lhs - rhs.as_double());
|
|
397
|
+
return AnyValue::make_number(lhs - Operators_Private::ToNumber(rhs));
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Operator *
|
|
401
|
+
inline AnyValue operator*(const AnyValue &lhs, const AnyValue &rhs)
|
|
402
|
+
{
|
|
403
|
+
if (lhs.is_number() && rhs.is_number())
|
|
404
|
+
return AnyValue::make_number(lhs.as_double() * rhs.as_double());
|
|
405
|
+
return AnyValue::make_number(Operators_Private::ToNumber(lhs) * Operators_Private::ToNumber(rhs));
|
|
406
|
+
}
|
|
407
|
+
inline AnyValue operator*(const AnyValue &lhs, const double &rhs)
|
|
408
|
+
{
|
|
409
|
+
if (lhs.is_number())
|
|
410
|
+
return AnyValue::make_number(lhs.as_double() * rhs);
|
|
411
|
+
return AnyValue::make_number(Operators_Private::ToNumber(lhs) * rhs);
|
|
412
|
+
}
|
|
413
|
+
inline AnyValue operator*(const double &lhs, const AnyValue &rhs)
|
|
414
|
+
{
|
|
415
|
+
if (rhs.is_number())
|
|
416
|
+
return AnyValue::make_number(lhs * rhs.as_double());
|
|
417
|
+
return AnyValue::make_number(lhs * Operators_Private::ToNumber(rhs));
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Operator /
|
|
421
|
+
inline AnyValue operator/(const AnyValue &lhs, const AnyValue &rhs)
|
|
422
|
+
{
|
|
423
|
+
if (lhs.is_number() && rhs.is_number())
|
|
424
|
+
return AnyValue::make_number(lhs.as_double() / rhs.as_double());
|
|
425
|
+
return AnyValue::make_number(Operators_Private::ToNumber(lhs) / Operators_Private::ToNumber(rhs));
|
|
426
|
+
}
|
|
427
|
+
inline AnyValue operator/(const AnyValue &lhs, const double &rhs)
|
|
428
|
+
{
|
|
429
|
+
if (lhs.is_number())
|
|
430
|
+
return AnyValue::make_number(lhs.as_double() / rhs);
|
|
431
|
+
return AnyValue::make_number(Operators_Private::ToNumber(lhs) / rhs);
|
|
432
|
+
}
|
|
433
|
+
inline AnyValue operator/(const double &lhs, const AnyValue &rhs)
|
|
434
|
+
{
|
|
435
|
+
if (rhs.is_number())
|
|
436
|
+
return AnyValue::make_number(lhs / rhs.as_double());
|
|
437
|
+
return AnyValue::make_number(lhs / Operators_Private::ToNumber(rhs));
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Operator %
|
|
441
|
+
inline AnyValue operator%(const AnyValue &lhs, const AnyValue &rhs)
|
|
442
|
+
{
|
|
443
|
+
if (lhs.is_number() && rhs.is_number())
|
|
444
|
+
return AnyValue::make_number(std::fmod(lhs.as_double(), rhs.as_double()));
|
|
445
|
+
return AnyValue::make_number(std::fmod(Operators_Private::ToNumber(lhs), Operators_Private::ToNumber(rhs)));
|
|
446
|
+
}
|
|
447
|
+
inline AnyValue operator%(const AnyValue &lhs, const double &rhs)
|
|
448
|
+
{
|
|
449
|
+
if (lhs.is_number())
|
|
450
|
+
return AnyValue::make_number(std::fmod(lhs.as_double(), rhs));
|
|
451
|
+
return AnyValue::make_number(std::fmod(Operators_Private::ToNumber(lhs), rhs));
|
|
452
|
+
}
|
|
453
|
+
inline AnyValue operator%(const double &lhs, const AnyValue &rhs)
|
|
454
|
+
{
|
|
455
|
+
if (rhs.is_number())
|
|
456
|
+
return AnyValue::make_number(std::fmod(lhs, rhs.as_double()));
|
|
457
|
+
return AnyValue::make_number(std::fmod(lhs, Operators_Private::ToNumber(rhs)));
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// --- UNARY OPERATORS ---
|
|
461
|
+
inline AnyValue operator+(const AnyValue &val)
|
|
462
|
+
{
|
|
463
|
+
return AnyValue::make_number(Operators_Private::ToNumber(val));
|
|
464
|
+
}
|
|
465
|
+
inline AnyValue operator-(const AnyValue &val)
|
|
466
|
+
{
|
|
467
|
+
return AnyValue::make_number(-Operators_Private::ToNumber(val));
|
|
468
|
+
}
|
|
469
|
+
inline AnyValue operator~(const AnyValue &val)
|
|
470
|
+
{
|
|
471
|
+
return AnyValue::make_number(~Operators_Private::ToInt32(val));
|
|
472
|
+
}
|
|
473
|
+
inline AnyValue operator!(const AnyValue &val)
|
|
474
|
+
{
|
|
475
|
+
return AnyValue::make_boolean(!is_truthy(val));
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// --- EXPONENTIATION ---
|
|
479
|
+
inline AnyValue pow(const AnyValue &lhs, const AnyValue &rhs)
|
|
480
|
+
{
|
|
481
|
+
double base = Operators_Private::ToNumber(lhs);
|
|
482
|
+
double exp = Operators_Private::ToNumber(rhs);
|
|
483
|
+
return AnyValue::make_number(std::pow(base, exp));
|
|
484
|
+
}
|
|
485
|
+
inline AnyValue pow(const AnyValue &lhs, const double &rhs)
|
|
486
|
+
{
|
|
487
|
+
double base = Operators_Private::ToNumber(lhs);
|
|
488
|
+
return AnyValue::make_number(std::pow(base, rhs));
|
|
489
|
+
}
|
|
490
|
+
inline AnyValue pow(const double &lhs, const AnyValue &rhs)
|
|
491
|
+
{
|
|
492
|
+
double exp = Operators_Private::ToNumber(rhs);
|
|
493
|
+
return AnyValue::make_number(std::pow(lhs, exp));
|
|
494
|
+
}
|
|
495
|
+
inline AnyValue pow(const double &lhs, const double &rhs)
|
|
496
|
+
{
|
|
497
|
+
return AnyValue::make_number(std::pow(lhs, rhs));
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// --- COMPARISON OPERATORS ---
|
|
501
|
+
|
|
502
|
+
// Less than <
|
|
503
|
+
inline AnyValue operator<(const AnyValue &lhs, const AnyValue &rhs)
|
|
504
|
+
{
|
|
505
|
+
if (lhs.is_number() && rhs.is_number())
|
|
506
|
+
return AnyValue::make_boolean(lhs.as_double() < rhs.as_double());
|
|
507
|
+
|
|
508
|
+
// String comparison support
|
|
509
|
+
if (lhs.is_string() && rhs.is_string())
|
|
510
|
+
return AnyValue::make_boolean(lhs.as_string()->value < rhs.as_string()->value);
|
|
511
|
+
|
|
512
|
+
double l = Operators_Private::ToNumber(lhs);
|
|
513
|
+
double r = Operators_Private::ToNumber(rhs);
|
|
514
|
+
|
|
515
|
+
if (std::isnan(l) || std::isnan(r))
|
|
516
|
+
return AnyValue::make_boolean(false);
|
|
517
|
+
|
|
518
|
+
return AnyValue::make_boolean(l < r);
|
|
519
|
+
}
|
|
520
|
+
inline AnyValue operator<(const AnyValue &lhs, const double &rhs)
|
|
521
|
+
{
|
|
522
|
+
if (lhs.is_number())
|
|
523
|
+
return AnyValue::make_boolean(lhs.as_double() < rhs);
|
|
524
|
+
|
|
525
|
+
double l = Operators_Private::ToNumber(lhs);
|
|
526
|
+
if (std::isnan(l) || std::isnan(rhs))
|
|
527
|
+
return AnyValue::make_boolean(false);
|
|
528
|
+
|
|
529
|
+
return AnyValue::make_boolean(l < rhs);
|
|
530
|
+
}
|
|
531
|
+
inline AnyValue operator<(const double &lhs, const AnyValue &rhs)
|
|
532
|
+
{
|
|
533
|
+
if (rhs.is_number())
|
|
534
|
+
return AnyValue::make_boolean(lhs < rhs.as_double());
|
|
535
|
+
|
|
536
|
+
double r = Operators_Private::ToNumber(rhs);
|
|
537
|
+
if (std::isnan(lhs) || std::isnan(r))
|
|
538
|
+
return AnyValue::make_boolean(false);
|
|
539
|
+
|
|
540
|
+
return AnyValue::make_boolean(lhs < r);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// Greater than > (Derived from <)
|
|
544
|
+
inline AnyValue operator>(const AnyValue &lhs, const AnyValue &rhs) { return rhs < lhs; }
|
|
545
|
+
inline AnyValue operator>(const AnyValue &lhs, const double &rhs) { return operator<(rhs, lhs); }
|
|
546
|
+
inline AnyValue operator>(const double &lhs, const AnyValue &rhs) { return operator<(rhs, lhs); }
|
|
547
|
+
|
|
548
|
+
// Less than or equal <= (Derived from >)
|
|
549
|
+
inline AnyValue operator<=(const AnyValue &lhs, const AnyValue &rhs)
|
|
550
|
+
{
|
|
551
|
+
AnyValue result = rhs < lhs;
|
|
552
|
+
return AnyValue::make_boolean(!result.as_boolean());
|
|
553
|
+
}
|
|
554
|
+
inline AnyValue operator<=(const AnyValue &lhs, const double &rhs)
|
|
555
|
+
{
|
|
556
|
+
// a <= b is equivalent to !(b < a) -> !(rhs < lhs)
|
|
557
|
+
AnyValue result = operator<(rhs, lhs);
|
|
558
|
+
return AnyValue::make_boolean(!result.as_boolean());
|
|
559
|
+
}
|
|
560
|
+
inline AnyValue operator<=(const double &lhs, const AnyValue &rhs)
|
|
561
|
+
{
|
|
562
|
+
// a <= b is equivalent to !(b < a) -> !(rhs < lhs)
|
|
563
|
+
AnyValue result = operator<(rhs, lhs);
|
|
564
|
+
return AnyValue::make_boolean(!result.as_boolean());
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// Greater than or equal >= (Derived from <)
|
|
568
|
+
inline AnyValue operator>=(const AnyValue &lhs, const AnyValue &rhs)
|
|
569
|
+
{
|
|
570
|
+
AnyValue result = lhs < rhs;
|
|
571
|
+
return AnyValue::make_boolean(!result.as_boolean());
|
|
572
|
+
}
|
|
573
|
+
inline AnyValue operator>=(const AnyValue &lhs, const double &rhs)
|
|
574
|
+
{
|
|
575
|
+
AnyValue result = operator<(lhs, rhs);
|
|
576
|
+
return AnyValue::make_boolean(!result.as_boolean());
|
|
577
|
+
}
|
|
578
|
+
inline AnyValue operator>=(const double &lhs, const AnyValue &rhs)
|
|
579
|
+
{
|
|
580
|
+
AnyValue result = operator<(lhs, rhs);
|
|
581
|
+
return AnyValue::make_boolean(!result.as_boolean());
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// Equality ==
|
|
585
|
+
inline AnyValue operator==(const AnyValue &lhs, const AnyValue &rhs)
|
|
586
|
+
{
|
|
587
|
+
return AnyValue::make_boolean(is_equal_to_primitive(lhs, rhs));
|
|
588
|
+
}
|
|
589
|
+
inline AnyValue operator==(const AnyValue &lhs, const double &rhs)
|
|
590
|
+
{
|
|
591
|
+
// Optimization: check if lhs is number first
|
|
592
|
+
if (lhs.is_number())
|
|
593
|
+
return AnyValue::make_boolean(lhs.as_double() == rhs);
|
|
594
|
+
return AnyValue::make_boolean(is_equal_to_primitive(lhs, AnyValue::make_number(rhs)));
|
|
595
|
+
}
|
|
596
|
+
inline AnyValue operator==(const double &lhs, const AnyValue &rhs)
|
|
597
|
+
{
|
|
598
|
+
if (rhs.is_number())
|
|
599
|
+
return AnyValue::make_boolean(lhs == rhs.as_double());
|
|
600
|
+
return AnyValue::make_boolean(is_equal_to_primitive(rhs, AnyValue::make_number(lhs)));
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// Inequality !=
|
|
604
|
+
inline AnyValue operator!=(const AnyValue &lhs, const AnyValue &rhs) { return AnyValue::make_boolean(!is_equal_to_primitive(lhs, rhs)); }
|
|
605
|
+
inline AnyValue operator!=(const AnyValue &lhs, const double &rhs) { return AnyValue::make_boolean(!operator==(lhs, rhs).as_boolean()); }
|
|
606
|
+
inline AnyValue operator!=(const double &lhs, const AnyValue &rhs) { return AnyValue::make_boolean(!operator==(lhs, rhs).as_boolean()); }
|
|
607
|
+
|
|
608
|
+
// --- LOGICAL OPERATORS ---
|
|
609
|
+
inline AnyValue operator||(const AnyValue &lhs, const AnyValue &rhs)
|
|
610
|
+
{
|
|
611
|
+
if (is_truthy(lhs))
|
|
612
|
+
return lhs;
|
|
613
|
+
return rhs;
|
|
614
|
+
}
|
|
615
|
+
inline AnyValue operator&&(const AnyValue &lhs, const AnyValue &rhs)
|
|
616
|
+
{
|
|
617
|
+
if (!is_truthy(lhs))
|
|
618
|
+
return lhs;
|
|
619
|
+
return rhs;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// --- BITWISE OPERATORS ---
|
|
623
|
+
inline AnyValue operator^(const AnyValue &lhs, const AnyValue &rhs)
|
|
624
|
+
{
|
|
625
|
+
return AnyValue::make_number(Operators_Private::ToInt32(lhs) ^ Operators_Private::ToInt32(rhs));
|
|
626
|
+
}
|
|
627
|
+
inline AnyValue operator^(const AnyValue &lhs, const double &rhs)
|
|
628
|
+
{
|
|
629
|
+
return AnyValue::make_number(Operators_Private::ToInt32(lhs) ^ static_cast<int32_t>(rhs));
|
|
630
|
+
}
|
|
631
|
+
inline AnyValue operator^(const double &lhs, const AnyValue &rhs)
|
|
632
|
+
{
|
|
633
|
+
return AnyValue::make_number(static_cast<int32_t>(lhs) ^ Operators_Private::ToInt32(rhs));
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
inline AnyValue operator&(const AnyValue &lhs, const AnyValue &rhs)
|
|
637
|
+
{
|
|
638
|
+
return AnyValue::make_number(Operators_Private::ToInt32(lhs) & Operators_Private::ToInt32(rhs));
|
|
639
|
+
}
|
|
640
|
+
inline AnyValue operator&(const AnyValue &lhs, const double &rhs)
|
|
641
|
+
{
|
|
642
|
+
return AnyValue::make_number(Operators_Private::ToInt32(lhs) & static_cast<int32_t>(rhs));
|
|
643
|
+
}
|
|
644
|
+
inline AnyValue operator&(const double &lhs, const AnyValue &rhs)
|
|
645
|
+
{
|
|
646
|
+
return AnyValue::make_number(static_cast<int32_t>(lhs) & Operators_Private::ToInt32(rhs));
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
inline AnyValue operator|(const AnyValue &lhs, const AnyValue &rhs)
|
|
650
|
+
{
|
|
651
|
+
return AnyValue::make_number(Operators_Private::ToInt32(lhs) | Operators_Private::ToInt32(rhs));
|
|
652
|
+
}
|
|
653
|
+
inline AnyValue operator|(const AnyValue &lhs, const double &rhs)
|
|
654
|
+
{
|
|
655
|
+
return AnyValue::make_number(Operators_Private::ToInt32(lhs) | static_cast<int32_t>(rhs));
|
|
656
|
+
}
|
|
657
|
+
inline AnyValue operator|(const double &lhs, const AnyValue &rhs)
|
|
658
|
+
{
|
|
659
|
+
return AnyValue::make_number(static_cast<int32_t>(lhs) | Operators_Private::ToInt32(rhs));
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
// --- SHIFT OPERATORS ---
|
|
663
|
+
inline AnyValue operator<<(const AnyValue &lhs, const AnyValue &rhs)
|
|
664
|
+
{
|
|
665
|
+
return AnyValue::make_number(Operators_Private::ToInt32(lhs) << (Operators_Private::ToInt32(rhs) & 0x1F));
|
|
666
|
+
}
|
|
667
|
+
inline AnyValue operator<<(const AnyValue &lhs, const double &rhs)
|
|
668
|
+
{
|
|
669
|
+
return AnyValue::make_number(Operators_Private::ToInt32(lhs) << (static_cast<int32_t>(rhs) & 0x1F));
|
|
670
|
+
}
|
|
671
|
+
inline AnyValue operator<<(const double &lhs, const AnyValue &rhs)
|
|
672
|
+
{
|
|
673
|
+
return AnyValue::make_number(static_cast<int32_t>(lhs) << (Operators_Private::ToInt32(rhs) & 0x1F));
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
inline AnyValue operator>>(const AnyValue &lhs, const AnyValue &rhs)
|
|
677
|
+
{
|
|
678
|
+
return AnyValue::make_number(Operators_Private::ToInt32(lhs) >> (Operators_Private::ToInt32(rhs) & 0x1F));
|
|
679
|
+
}
|
|
680
|
+
inline AnyValue operator>>(const AnyValue &lhs, const double &rhs)
|
|
681
|
+
{
|
|
682
|
+
return AnyValue::make_number(Operators_Private::ToInt32(lhs) >> (static_cast<int32_t>(rhs) & 0x1F));
|
|
683
|
+
}
|
|
684
|
+
inline AnyValue operator>>(const double &lhs, const AnyValue &rhs)
|
|
685
|
+
{
|
|
686
|
+
return AnyValue::make_number(static_cast<int32_t>(lhs) >> (Operators_Private::ToInt32(rhs) & 0x1F));
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
inline AnyValue unsigned_right_shift(const AnyValue &lhs, const AnyValue &rhs)
|
|
690
|
+
{
|
|
691
|
+
return AnyValue::make_number(static_cast<double>(Operators_Private::ToUint32(lhs) >> (Operators_Private::ToInt32(rhs) & 0x1F)));
|
|
692
|
+
}
|
|
693
|
+
inline AnyValue unsigned_right_shift(const AnyValue &lhs, const double &rhs)
|
|
694
|
+
{
|
|
695
|
+
return AnyValue::make_number(static_cast<double>(Operators_Private::ToUint32(lhs) >> (static_cast<int32_t>(rhs) & 0x1F)));
|
|
696
|
+
}
|
|
697
|
+
inline AnyValue unsigned_right_shift(const double &lhs, const AnyValue &rhs)
|
|
698
|
+
{
|
|
699
|
+
uint32_t l = static_cast<uint32_t>(fmod(lhs, 4294967296.0));
|
|
700
|
+
return AnyValue::make_number(static_cast<double>(l >> (Operators_Private::ToInt32(rhs) & 0x1F)));
|
|
701
|
+
}
|
|
702
|
+
inline AnyValue unsigned_right_shift(const double &lhs, const double &rhs)
|
|
703
|
+
{
|
|
704
|
+
uint32_t l = static_cast<uint32_t>(fmod(lhs, 4294967296.0));
|
|
705
|
+
return AnyValue::make_number(static_cast<double>(l >> (static_cast<int32_t>(rhs) & 0x1F)));
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
// --- LOGICAL SHORT-CIRCUITING HELPERS ---
|
|
709
|
+
inline AnyValue logical_and(const AnyValue &lhs, const AnyValue &rhs)
|
|
710
|
+
{
|
|
711
|
+
if (!is_truthy(lhs))
|
|
712
|
+
return lhs;
|
|
713
|
+
return rhs;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
inline AnyValue logical_or(const AnyValue &lhs, const AnyValue &rhs)
|
|
717
|
+
{
|
|
718
|
+
if (is_truthy(lhs))
|
|
719
|
+
return lhs;
|
|
720
|
+
return rhs;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
inline AnyValue nullish_coalesce(const AnyValue &lhs, const AnyValue &rhs)
|
|
724
|
+
{
|
|
725
|
+
if (!lhs.is_null() && !lhs.is_undefined())
|
|
726
|
+
return lhs;
|
|
727
|
+
return rhs;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
// --- LOGICAL ASSIGNMENT HELPERS ---
|
|
731
|
+
inline AnyValue &logical_and_assign(AnyValue &lhs, const AnyValue &rhs)
|
|
732
|
+
{
|
|
733
|
+
if (is_truthy(lhs))
|
|
734
|
+
lhs = rhs;
|
|
735
|
+
return lhs;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
inline AnyValue &logical_or_assign(AnyValue &lhs, const AnyValue &rhs)
|
|
739
|
+
{
|
|
740
|
+
if (!is_truthy(lhs))
|
|
741
|
+
lhs = rhs;
|
|
742
|
+
return lhs;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
inline AnyValue &nullish_coalesce_assign(AnyValue &lhs, const AnyValue &rhs)
|
|
746
|
+
{
|
|
747
|
+
if (lhs.is_null() || lhs.is_undefined())
|
|
748
|
+
lhs = rhs;
|
|
749
|
+
return lhs;
|
|
750
|
+
}
|
|
275
751
|
}
|