@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
@@ -1,275 +1,751 @@
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
-
8
- namespace jspp
9
- {
10
- // Private namespace for helper functions that implement JS type conversions.
11
- namespace Operators_Private
12
- {
13
- // Implements the ToNumber abstract operation from ECMA-262.
14
- inline double ToNumber(const AnyValue &val)
15
- {
16
- switch (val.get_type())
17
- {
18
- case JsType::Number:
19
- return val.as_double();
20
- case JsType::Null:
21
- return 0.0;
22
- case JsType::Uninitialized:
23
- case JsType::Undefined:
24
- return std::numeric_limits<double>::quiet_NaN();
25
- case JsType::Boolean:
26
- return val.as_boolean() ? 1.0 : 0.0;
27
- case JsType::String:
28
- {
29
- const std::string &s = val.as_string()->value;
30
- // JS considers empty or whitespace-only strings as 0.
31
- if (s.empty() || std::all_of(s.begin(), s.end(), isspace))
32
- return 0.0;
33
- try
34
- {
35
- size_t pos;
36
- double num = std::stod(s, &pos);
37
- // Ensure the entire string was parsed, allowing for trailing whitespace.
38
- while (pos < s.length() && std::isspace(s[pos]))
39
- pos++;
40
- if (pos != s.length())
41
- return std::numeric_limits<double>::quiet_NaN();
42
- return num;
43
- }
44
- catch (...)
45
- {
46
- return std::numeric_limits<double>::quiet_NaN();
47
- }
48
- }
49
- default:
50
- // In a full engine, objects would be converted via valueOf/toString.
51
- // Here we simplify and return NaN.
52
- return std::numeric_limits<double>::quiet_NaN();
53
- }
54
- }
55
- // Implements the ToInt32 abstract operation from ECMA-262.
56
- inline int32_t ToInt32(const AnyValue &val)
57
- {
58
- double num = ToNumber(val);
59
-
60
- if (std::isnan(num) || std::isinf(num) || num == 0)
61
- return 0;
62
-
63
- double posInt = std::signbit(num) ? -std::floor(std::abs(num)) : std::floor(std::abs(num));
64
- double int32bit = fmod(posInt, 4294967296.0); // 2^32
65
-
66
- if (int32bit >= 2147483648.0) // 2^31
67
- return static_cast<int32_t>(int32bit - 4294967296.0);
68
- else
69
- return static_cast<int32_t>(int32bit);
70
- }
71
- }
72
-
73
- // --- BASIC ARITHEMETIC
74
- inline AnyValue operator+(const AnyValue &lhs, const AnyValue &rhs)
75
- {
76
- // Special case for addition: string concatenation has priority
77
- if (lhs.is_string() || rhs.is_string())
78
- return AnyValue::make_string(lhs.to_std_string() + rhs.to_std_string());
79
- if (lhs.is_number() && rhs.is_number())
80
- return AnyValue::make_number(lhs.as_double() + rhs.as_double());
81
- // Fallback to numeric conversion
82
- return AnyValue::make_number(Operators_Private::ToNumber(lhs) + Operators_Private::ToNumber(rhs));
83
- }
84
- inline AnyValue operator-(const AnyValue &lhs, const AnyValue &rhs)
85
- {
86
- return AnyValue::make_number(Operators_Private::ToNumber(lhs) - Operators_Private::ToNumber(rhs));
87
- }
88
- inline AnyValue operator*(const AnyValue &lhs, const AnyValue &rhs)
89
- {
90
- return AnyValue::make_number(Operators_Private::ToNumber(lhs) * Operators_Private::ToNumber(rhs));
91
- }
92
- inline AnyValue operator/(const AnyValue &lhs, const AnyValue &rhs)
93
- {
94
- return AnyValue::make_number(Operators_Private::ToNumber(lhs) / Operators_Private::ToNumber(rhs));
95
- }
96
- inline AnyValue operator%(const AnyValue &lhs, const AnyValue &rhs)
97
- {
98
- return AnyValue::make_number(std::fmod(Operators_Private::ToNumber(lhs), Operators_Private::ToNumber(rhs)));
99
- }
100
-
101
- // --- UNARY OPERATORS
102
- inline AnyValue operator-(const AnyValue &val)
103
- {
104
- return AnyValue::make_number(-Operators_Private::ToNumber(val));
105
- }
106
- inline AnyValue operator~(const AnyValue &val)
107
- {
108
- return AnyValue::make_number(~Operators_Private::ToInt32(val));
109
- }
110
-
111
- // --- EXPONENTIATION
112
- inline AnyValue pow(const AnyValue &lhs, const AnyValue &rhs)
113
- {
114
- double base = Operators_Private::ToNumber(lhs);
115
- double exp = Operators_Private::ToNumber(rhs);
116
- return AnyValue::make_number(std::pow(base, exp));
117
- }
118
-
119
- // --- COMPARISON OPERATORS
120
- inline AnyValue operator<(const AnyValue &lhs, const AnyValue &rhs)
121
- {
122
- // Simplified Abstract Relational Comparison
123
- if (lhs.is_string() && rhs.is_string())
124
- return AnyValue::make_boolean(lhs.as_string()->value < rhs.as_string()->value);
125
-
126
- double l = Operators_Private::ToNumber(lhs);
127
- double r = Operators_Private::ToNumber(rhs);
128
-
129
- if (std::isnan(l) || std::isnan(r))
130
- return AnyValue::make_boolean(false); // Comparison with NaN is false
131
-
132
- return AnyValue::make_boolean(l < r);
133
- }
134
- inline AnyValue operator>(const AnyValue &lhs, const AnyValue &rhs)
135
- {
136
- return rhs < lhs;
137
- }
138
- inline AnyValue operator<=(const AnyValue &lhs, const AnyValue &rhs)
139
- {
140
- // a <= b is equivalent to !(b < a)
141
- AnyValue result = rhs < lhs;
142
- return AnyValue::make_boolean(!result.as_boolean());
143
- }
144
- inline AnyValue operator>=(const AnyValue &lhs, const AnyValue &rhs)
145
- {
146
- // a >= b is equivalent to !(a < b)
147
- AnyValue result = lhs < rhs;
148
- return AnyValue::make_boolean(!result.as_boolean());
149
- }
150
- inline AnyValue operator==(const AnyValue &lhs, const AnyValue &rhs)
151
- {
152
- return AnyValue::make_boolean(lhs.is_equal_to_primitive(rhs));
153
- }
154
- inline AnyValue operator!=(const AnyValue &lhs, const AnyValue &rhs)
155
- {
156
- return AnyValue::make_boolean(!lhs.is_equal_to_primitive(rhs));
157
- }
158
-
159
- // --- LOGICAL OPERATORS
160
- inline AnyValue operator||(const AnyValue &lhs, const AnyValue &rhs)
161
- {
162
- if (lhs.is_truthy())
163
- return lhs;
164
- return rhs;
165
- }
166
- inline AnyValue operator&&(const AnyValue &lhs, const AnyValue &rhs)
167
- {
168
- if (!lhs.is_truthy())
169
- return lhs;
170
- return rhs;
171
- }
172
-
173
- // --- BITWISE OPERATORS
174
- inline AnyValue operator^(const AnyValue &lhs, const AnyValue &rhs)
175
- {
176
- return AnyValue::make_number(Operators_Private::ToInt32(lhs) ^ Operators_Private::ToInt32(rhs));
177
- }
178
- inline AnyValue operator&(const AnyValue &lhs, const AnyValue &rhs)
179
- {
180
- return AnyValue::make_number(Operators_Private::ToInt32(lhs) & Operators_Private::ToInt32(rhs));
181
- }
182
- inline AnyValue operator|(const AnyValue &lhs, const AnyValue &rhs)
183
- {
184
- return AnyValue::make_number(Operators_Private::ToInt32(lhs) | Operators_Private::ToInt32(rhs));
185
- }
186
-
187
- // --- SHIFT OPERATORS
188
- inline AnyValue operator<<(const AnyValue &lhs, const AnyValue &rhs)
189
- {
190
- // The right operand is treated as an unsigned 32-bit integer, and only the lower 5 bits are used.
191
- return AnyValue::make_number(Operators_Private::ToInt32(lhs) << (Operators_Private::ToInt32(rhs) & 0x1F));
192
- }
193
- inline AnyValue operator>>(const AnyValue &lhs, const AnyValue &rhs)
194
- {
195
- return AnyValue::make_number(Operators_Private::ToInt32(lhs) >> (Operators_Private::ToInt32(rhs) & 0x1F));
196
- }
197
-
198
- // --- INCREMENT / DECREMENT
199
- inline AnyValue &operator++(AnyValue &val) // pre-increment
200
- {
201
- double num = Operators_Private::ToNumber(val);
202
- val = AnyValue::make_number(num + 1.0);
203
- return val;
204
- }
205
- inline AnyValue operator++(AnyValue &val, int) // post-increment
206
- {
207
- AnyValue old = AnyValue::make_number(Operators_Private::ToNumber(val));
208
- ++val;
209
- return old;
210
- }
211
- inline AnyValue &operator--(AnyValue &val) // pre-decrement
212
- {
213
- double num = Operators_Private::ToNumber(val);
214
- val = AnyValue::make_number(num - 1.0);
215
- return val;
216
- }
217
- inline AnyValue operator--(AnyValue &val, int) // post-decrement
218
- {
219
- AnyValue old = AnyValue::make_number(Operators_Private::ToNumber(val));
220
- --val;
221
- return old;
222
- }
223
-
224
- // --- COMPOUND ASSIGNMENT
225
- inline AnyValue &operator+=(AnyValue &lhs, const AnyValue &rhs)
226
- {
227
- lhs = lhs + rhs;
228
- return lhs;
229
- }
230
- inline AnyValue &operator-=(AnyValue &lhs, const AnyValue &rhs)
231
- {
232
- lhs = lhs - rhs;
233
- return lhs;
234
- }
235
- inline AnyValue &operator*=(AnyValue &lhs, const AnyValue &rhs)
236
- {
237
- lhs = lhs * rhs;
238
- return lhs;
239
- }
240
- inline AnyValue &operator/=(AnyValue &lhs, const AnyValue &rhs)
241
- {
242
- lhs = lhs / rhs;
243
- return lhs;
244
- }
245
- inline AnyValue &operator%=(AnyValue &lhs, const AnyValue &rhs)
246
- {
247
- lhs = lhs % rhs;
248
- return lhs;
249
- }
250
- inline AnyValue &operator^=(AnyValue &lhs, const AnyValue &rhs)
251
- {
252
- lhs = lhs ^ rhs;
253
- return lhs;
254
- }
255
- inline AnyValue &operator&=(AnyValue &lhs, const AnyValue &rhs)
256
- {
257
- lhs = lhs & rhs;
258
- return lhs;
259
- }
260
- inline AnyValue &operator|=(AnyValue &lhs, const AnyValue &rhs)
261
- {
262
- lhs = lhs | rhs;
263
- return lhs;
264
- }
265
- inline AnyValue &operator<<=(AnyValue &lhs, const AnyValue &rhs)
266
- {
267
- lhs = lhs << rhs;
268
- return lhs;
269
- }
270
- inline AnyValue &operator>>=(AnyValue &lhs, const AnyValue &rhs)
271
- {
272
- lhs = lhs >> rhs;
273
- return lhs;
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
  }