/src/serenity/Userland/Libraries/LibJS/Runtime/Value.cpp
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> |
3 | | * Copyright (c) 2020-2023, Linus Groh <linusg@serenityos.org> |
4 | | * Copyright (c) 2022, David Tuin <davidot@serenityos.org> |
5 | | * |
6 | | * SPDX-License-Identifier: BSD-2-Clause |
7 | | */ |
8 | | |
9 | | #include <AK/AllOf.h> |
10 | | #include <AK/Assertions.h> |
11 | | #include <AK/ByteString.h> |
12 | | #include <AK/CharacterTypes.h> |
13 | | #include <AK/FloatingPointStringConversions.h> |
14 | | #include <AK/StringBuilder.h> |
15 | | #include <AK/StringFloatingPointConversions.h> |
16 | | #include <AK/Utf8View.h> |
17 | | #include <LibCrypto/BigInt/SignedBigInteger.h> |
18 | | #include <LibCrypto/NumberTheory/ModularFunctions.h> |
19 | | #include <LibJS/Runtime/AbstractOperations.h> |
20 | | #include <LibJS/Runtime/Accessor.h> |
21 | | #include <LibJS/Runtime/Array.h> |
22 | | #include <LibJS/Runtime/BigInt.h> |
23 | | #include <LibJS/Runtime/BigIntObject.h> |
24 | | #include <LibJS/Runtime/BooleanObject.h> |
25 | | #include <LibJS/Runtime/BoundFunction.h> |
26 | | #include <LibJS/Runtime/Completion.h> |
27 | | #include <LibJS/Runtime/Error.h> |
28 | | #include <LibJS/Runtime/FunctionObject.h> |
29 | | #include <LibJS/Runtime/GlobalObject.h> |
30 | | #include <LibJS/Runtime/NativeFunction.h> |
31 | | #include <LibJS/Runtime/NumberObject.h> |
32 | | #include <LibJS/Runtime/Object.h> |
33 | | #include <LibJS/Runtime/PrimitiveString.h> |
34 | | #include <LibJS/Runtime/ProxyObject.h> |
35 | | #include <LibJS/Runtime/RegExpObject.h> |
36 | | #include <LibJS/Runtime/StringObject.h> |
37 | | #include <LibJS/Runtime/StringPrototype.h> |
38 | | #include <LibJS/Runtime/SymbolObject.h> |
39 | | #include <LibJS/Runtime/Utf16String.h> |
40 | | #include <LibJS/Runtime/VM.h> |
41 | | #include <LibJS/Runtime/Value.h> |
42 | | #include <LibJS/Runtime/ValueInlines.h> |
43 | | #include <math.h> |
44 | | |
45 | | namespace JS { |
46 | | |
47 | | static inline bool same_type_for_equality(Value const& lhs, Value const& rhs) |
48 | 0 | { |
49 | | // If the top two bytes are identical then either: |
50 | | // both are NaN boxed Values with the same type |
51 | | // or they are doubles which happen to have the same top bytes. |
52 | 0 | if ((lhs.encoded() & TAG_EXTRACTION) == (rhs.encoded() & TAG_EXTRACTION)) |
53 | 0 | return true; |
54 | | |
55 | 0 | if (lhs.is_number() && rhs.is_number()) |
56 | 0 | return true; |
57 | | |
58 | | // One of the Values is not a number and they do not have the same tag |
59 | 0 | return false; |
60 | 0 | } |
61 | | |
62 | | static Crypto::SignedBigInteger const BIGINT_ZERO { 0 }; |
63 | | |
64 | | ALWAYS_INLINE bool both_number(Value const& lhs, Value const& rhs) |
65 | 0 | { |
66 | 0 | return lhs.is_number() && rhs.is_number(); |
67 | 0 | } |
68 | | |
69 | | ALWAYS_INLINE bool both_bigint(Value const& lhs, Value const& rhs) |
70 | 0 | { |
71 | 0 | return lhs.is_bigint() && rhs.is_bigint(); |
72 | 0 | } |
73 | | |
74 | | // 6.1.6.1.20 Number::toString ( x ), https://tc39.es/ecma262/#sec-numeric-types-number-tostring |
75 | | // Implementation for radix = 10 |
76 | | static void number_to_string_impl(StringBuilder& builder, double d, NumberToStringMode mode) |
77 | 0 | { |
78 | 0 | auto convert_to_decimal_digits_array = [](auto x, auto& digits, auto& length) { |
79 | 0 | for (; x; x /= 10) |
80 | 0 | digits[length++] = x % 10 | '0'; |
81 | 0 | for (i32 i = 0; 2 * i + 1 < length; ++i) |
82 | 0 | swap(digits[i], digits[length - i - 1]); |
83 | 0 | }; Unexecuted instantiation: Value.cpp:auto JS::number_to_string_impl(AK::StringBuilder&, double, JS::NumberToStringMode)::$_0::operator()<unsigned long, AK::Array<char, 20ul>, int>(unsigned long, AK::Array<char, 20ul>&, int&) const Unexecuted instantiation: Value.cpp:auto JS::number_to_string_impl(AK::StringBuilder&, double, JS::NumberToStringMode)::$_0::operator()<int, AK::Array<char, 5ul>, int>(int, AK::Array<char, 5ul>&, int&) const |
84 | | |
85 | | // 1. If x is NaN, return "NaN". |
86 | 0 | if (isnan(d)) { |
87 | 0 | builder.append("NaN"sv); |
88 | 0 | return; |
89 | 0 | } |
90 | | |
91 | | // 2. If x is +0𝔽 or -0𝔽, return "0". |
92 | 0 | if (d == +0.0 || d == -0.0) { |
93 | 0 | builder.append("0"sv); |
94 | 0 | return; |
95 | 0 | } |
96 | | |
97 | | // 4. If x is +∞𝔽, return "Infinity". |
98 | 0 | if (isinf(d)) { |
99 | 0 | if (d > 0) { |
100 | 0 | builder.append("Infinity"sv); |
101 | 0 | return; |
102 | 0 | } |
103 | | |
104 | 0 | builder.append("-Infinity"sv); |
105 | 0 | return; |
106 | 0 | } |
107 | | |
108 | | // 5. Let n, k, and s be integers such that k ≥ 1, radix ^ (k - 1) ≤ s < radix ^ k, |
109 | | // 𝔽(s × radix ^ (n - k)) is x, and k is as small as possible. Note that k is the number of |
110 | | // digits in the representation of s using radix radix, that s is not divisible by radix, and |
111 | | // that the least significant digit of s is not necessarily uniquely determined by these criteria. |
112 | | // |
113 | | // Note: guarantees provided by convert_floating_point_to_decimal_exponential_form satisfy |
114 | | // requirements of NOTE 2. |
115 | 0 | auto [sign, mantissa, exponent] = convert_floating_point_to_decimal_exponential_form(d); |
116 | 0 | i32 k = 0; |
117 | 0 | AK::Array<char, 20> mantissa_digits; |
118 | 0 | convert_to_decimal_digits_array(mantissa, mantissa_digits, k); |
119 | |
|
120 | 0 | i32 n = exponent + k; // s = mantissa |
121 | | |
122 | | // 3. If x < -0𝔽, return the string-concatenation of "-" and Number::toString(-x, radix). |
123 | 0 | if (sign) |
124 | 0 | builder.append('-'); |
125 | | |
126 | | // Non-standard: Intl needs number-to-string conversions for extremely large numbers without any |
127 | | // exponential formatting, as it will handle such formatting itself in a locale-aware way. |
128 | 0 | bool force_no_exponent = mode == NumberToStringMode::WithoutExponent; |
129 | | |
130 | | // 6. If radix ≠ 10 or n is in the inclusive interval from -5 to 21, then |
131 | 0 | if ((n >= -5 && n <= 21) || force_no_exponent) { |
132 | | // a. If n ≥ k, then |
133 | 0 | if (n >= k) { |
134 | | // i. Return the string-concatenation of: |
135 | | // the code units of the k digits of the representation of s using radix radix |
136 | 0 | builder.append(mantissa_digits.data(), k); |
137 | | // n - k occurrences of the code unit 0x0030 (DIGIT ZERO) |
138 | 0 | builder.append_repeated('0', n - k); |
139 | | // b. Else if n > 0, then |
140 | 0 | } else if (n > 0) { |
141 | | // i. Return the string-concatenation of: |
142 | | // the code units of the most significant n digits of the representation of s using radix radix |
143 | 0 | builder.append(mantissa_digits.data(), n); |
144 | | // the code unit 0x002E (FULL STOP) |
145 | 0 | builder.append('.'); |
146 | | // the code units of the remaining k - n digits of the representation of s using radix radix |
147 | 0 | builder.append(mantissa_digits.data() + n, k - n); |
148 | | // c. Else, |
149 | 0 | } else { |
150 | | // i. Assert: n ≤ 0. |
151 | 0 | VERIFY(n <= 0); |
152 | | // ii. Return the string-concatenation of: |
153 | | // the code unit 0x0030 (DIGIT ZERO) |
154 | 0 | builder.append('0'); |
155 | | // the code unit 0x002E (FULL STOP) |
156 | 0 | builder.append('.'); |
157 | | // -n occurrences of the code unit 0x0030 (DIGIT ZERO) |
158 | 0 | builder.append_repeated('0', -n); |
159 | | // the code units of the k digits of the representation of s using radix radix |
160 | 0 | builder.append(mantissa_digits.data(), k); |
161 | 0 | } |
162 | | |
163 | 0 | return; |
164 | 0 | } |
165 | | |
166 | | // 7. NOTE: In this case, the input will be represented using scientific E notation, such as 1.2e+3. |
167 | | |
168 | | // 9. If n < 0, then |
169 | | // a. Let exponentSign be the code unit 0x002D (HYPHEN-MINUS). |
170 | | // 10. Else, |
171 | | // a. Let exponentSign be the code unit 0x002B (PLUS SIGN). |
172 | 0 | char exponent_sign = n < 0 ? '-' : '+'; |
173 | |
|
174 | 0 | AK::Array<char, 5> exponent_digits; |
175 | 0 | i32 exponent_length = 0; |
176 | 0 | convert_to_decimal_digits_array(abs(n - 1), exponent_digits, exponent_length); |
177 | | |
178 | | // 11. If k is 1, then |
179 | 0 | if (k == 1) { |
180 | | // a. Return the string-concatenation of: |
181 | | // the code unit of the single digit of s |
182 | 0 | builder.append(mantissa_digits[0]); |
183 | | // the code unit 0x0065 (LATIN SMALL LETTER E) |
184 | 0 | builder.append('e'); |
185 | | // exponentSign |
186 | 0 | builder.append(exponent_sign); |
187 | | // the code units of the decimal representation of abs(n - 1) |
188 | 0 | builder.append(exponent_digits.data(), exponent_length); |
189 | |
|
190 | 0 | return; |
191 | 0 | } |
192 | | |
193 | | // 12. Return the string-concatenation of: |
194 | | // the code unit of the most significant digit of the decimal representation of s |
195 | 0 | builder.append(mantissa_digits[0]); |
196 | | // the code unit 0x002E (FULL STOP) |
197 | 0 | builder.append('.'); |
198 | | // the code units of the remaining k - 1 digits of the decimal representation of s |
199 | 0 | builder.append(mantissa_digits.data() + 1, k - 1); |
200 | | // the code unit 0x0065 (LATIN SMALL LETTER E) |
201 | 0 | builder.append('e'); |
202 | | // exponentSign |
203 | 0 | builder.append(exponent_sign); |
204 | | // the code units of the decimal representation of abs(n - 1) |
205 | 0 | builder.append(exponent_digits.data(), exponent_length); |
206 | 0 | } |
207 | | |
208 | | String number_to_string(double d, NumberToStringMode mode) |
209 | 0 | { |
210 | 0 | StringBuilder builder; |
211 | 0 | number_to_string_impl(builder, d, mode); |
212 | 0 | return builder.to_string().release_value(); |
213 | 0 | } |
214 | | |
215 | | ByteString number_to_byte_string(double d, NumberToStringMode mode) |
216 | 0 | { |
217 | 0 | StringBuilder builder; |
218 | 0 | number_to_string_impl(builder, d, mode); |
219 | 0 | return builder.to_byte_string(); |
220 | 0 | } |
221 | | |
222 | | // 7.2.2 IsArray ( argument ), https://tc39.es/ecma262/#sec-isarray |
223 | | ThrowCompletionOr<bool> Value::is_array(VM& vm) const |
224 | 0 | { |
225 | | // 1. If argument is not an Object, return false. |
226 | 0 | if (!is_object()) |
227 | 0 | return false; |
228 | | |
229 | 0 | auto const& object = as_object(); |
230 | | |
231 | | // 2. If argument is an Array exotic object, return true. |
232 | 0 | if (is<Array>(object)) |
233 | 0 | return true; |
234 | | |
235 | | // 3. If argument is a Proxy exotic object, then |
236 | 0 | if (is<ProxyObject>(object)) { |
237 | 0 | auto const& proxy = static_cast<ProxyObject const&>(object); |
238 | | |
239 | | // a. If argument.[[ProxyHandler]] is null, throw a TypeError exception. |
240 | 0 | if (proxy.is_revoked()) |
241 | 0 | return vm.throw_completion<TypeError>(ErrorType::ProxyRevoked); |
242 | | |
243 | | // b. Let target be argument.[[ProxyTarget]]. |
244 | 0 | auto const& target = proxy.target(); |
245 | | |
246 | | // c. Return ? IsArray(target). |
247 | 0 | return Value(&target).is_array(vm); |
248 | 0 | } |
249 | | |
250 | | // 4. Return false. |
251 | 0 | return false; |
252 | 0 | } |
253 | | |
254 | | Array& Value::as_array() |
255 | 0 | { |
256 | 0 | VERIFY(is_object() && is<Array>(as_object())); |
257 | 0 | return static_cast<Array&>(as_object()); |
258 | 0 | } |
259 | | |
260 | | // 20.5.8.2 IsError ( argument ), https://tc39.es/proposal-is-error/#sec-iserror |
261 | | bool Value::is_error() const |
262 | 0 | { |
263 | | // 1. If argument is not an Object, return false. |
264 | | // 2. If argument has an [[ErrorData]] internal slot, return true. |
265 | | // 3. Return false. |
266 | 0 | return is_object() && is<Error>(as_object()); |
267 | 0 | } |
268 | | |
269 | | // 7.2.3 IsCallable ( argument ), https://tc39.es/ecma262/#sec-iscallable |
270 | | bool Value::is_function() const |
271 | 255 | { |
272 | | // 1. If argument is not an Object, return false. |
273 | | // 2. If argument has a [[Call]] internal method, return true. |
274 | | // 3. Return false. |
275 | 255 | return is_object() && as_object().is_function(); |
276 | 255 | } |
277 | | |
278 | | FunctionObject& Value::as_function() |
279 | 255 | { |
280 | 255 | VERIFY(is_function()); |
281 | 255 | return static_cast<FunctionObject&>(as_object()); |
282 | 255 | } |
283 | | |
284 | | FunctionObject const& Value::as_function() const |
285 | 0 | { |
286 | 0 | VERIFY(is_function()); |
287 | 0 | return static_cast<FunctionObject const&>(as_object()); |
288 | 0 | } |
289 | | |
290 | | // 7.2.4 IsConstructor ( argument ), https://tc39.es/ecma262/#sec-isconstructor |
291 | | bool Value::is_constructor() const |
292 | 0 | { |
293 | | // 1. If Type(argument) is not Object, return false. |
294 | 0 | if (!is_function()) |
295 | 0 | return false; |
296 | | |
297 | | // 2. If argument has a [[Construct]] internal method, return true. |
298 | 0 | if (as_function().has_constructor()) |
299 | 0 | return true; |
300 | | |
301 | | // 3. Return false. |
302 | 0 | return false; |
303 | 0 | } |
304 | | |
305 | | // 7.2.8 IsRegExp ( argument ), https://tc39.es/ecma262/#sec-isregexp |
306 | | ThrowCompletionOr<bool> Value::is_regexp(VM& vm) const |
307 | 0 | { |
308 | | // 1. If argument is not an Object, return false. |
309 | 0 | if (!is_object()) |
310 | 0 | return false; |
311 | | |
312 | | // 2. Let matcher be ? Get(argument, @@match). |
313 | 0 | auto matcher = TRY(as_object().get(vm.well_known_symbol_match())); |
314 | | |
315 | | // 3. If matcher is not undefined, return ToBoolean(matcher). |
316 | 0 | if (!matcher.is_undefined()) |
317 | 0 | return matcher.to_boolean(); |
318 | | |
319 | | // 4. If argument has a [[RegExpMatcher]] internal slot, return true. |
320 | | // 5. Return false. |
321 | 0 | return is<RegExpObject>(as_object()); |
322 | 0 | } |
323 | | |
324 | | // 13.5.3 The typeof Operator, https://tc39.es/ecma262/#sec-typeof-operator |
325 | | NonnullGCPtr<PrimitiveString> Value::typeof_(VM& vm) const |
326 | 0 | { |
327 | | // 9. If val is a Number, return "number". |
328 | 0 | if (is_number()) |
329 | 0 | return *vm.typeof_strings.number; |
330 | | |
331 | 0 | switch (m_value.tag) { |
332 | | // 4. If val is undefined, return "undefined". |
333 | 0 | case UNDEFINED_TAG: |
334 | 0 | return *vm.typeof_strings.undefined; |
335 | | // 5. If val is null, return "object". |
336 | 0 | case NULL_TAG: |
337 | 0 | return *vm.typeof_strings.object; |
338 | | // 6. If val is a String, return "string". |
339 | 0 | case STRING_TAG: |
340 | 0 | return *vm.typeof_strings.string; |
341 | | // 7. If val is a Symbol, return "symbol". |
342 | 0 | case SYMBOL_TAG: |
343 | 0 | return *vm.typeof_strings.symbol; |
344 | | // 8. If val is a Boolean, return "boolean". |
345 | 0 | case BOOLEAN_TAG: |
346 | 0 | return *vm.typeof_strings.boolean; |
347 | | // 10. If val is a BigInt, return "bigint". |
348 | 0 | case BIGINT_TAG: |
349 | 0 | return *vm.typeof_strings.bigint; |
350 | | // 11. Assert: val is an Object. |
351 | 0 | case OBJECT_TAG: |
352 | | // B.3.6.3 Changes to the typeof Operator, https://tc39.es/ecma262/#sec-IsHTMLDDA-internal-slot-typeof |
353 | | // 12. If val has an [[IsHTMLDDA]] internal slot, return "undefined". |
354 | 0 | if (as_object().is_htmldda()) |
355 | 0 | return *vm.typeof_strings.undefined; |
356 | | // 13. If val has a [[Call]] internal slot, return "function". |
357 | 0 | if (is_function()) |
358 | 0 | return *vm.typeof_strings.function; |
359 | | // 14. Return "object". |
360 | 0 | return *vm.typeof_strings.object; |
361 | 0 | default: |
362 | 0 | VERIFY_NOT_REACHED(); |
363 | 0 | } |
364 | 0 | } |
365 | | |
366 | | String Value::to_string_without_side_effects() const |
367 | 1 | { |
368 | 1 | if (is_double()) |
369 | 0 | return number_to_string(m_value.as_double); |
370 | | |
371 | 1 | switch (m_value.tag) { |
372 | 0 | case UNDEFINED_TAG: |
373 | 0 | return "undefined"_string; |
374 | 0 | case NULL_TAG: |
375 | 0 | return "null"_string; |
376 | 0 | case BOOLEAN_TAG: |
377 | 0 | return as_bool() ? "true"_string : "false"_string; |
378 | 1 | case INT32_TAG: |
379 | 1 | return String::number(as_i32()); |
380 | 0 | case STRING_TAG: |
381 | 0 | return as_string().utf8_string(); |
382 | 0 | case SYMBOL_TAG: |
383 | 0 | return as_symbol().descriptive_string().release_value(); |
384 | 0 | case BIGINT_TAG: |
385 | 0 | return as_bigint().to_string().release_value(); |
386 | 0 | case OBJECT_TAG: |
387 | 0 | return String::formatted("[object {}]", as_object().class_name()).release_value(); |
388 | 0 | case ACCESSOR_TAG: |
389 | 0 | return "<accessor>"_string; |
390 | 0 | case EMPTY_TAG: |
391 | 0 | return "<empty>"_string; |
392 | 0 | default: |
393 | 0 | VERIFY_NOT_REACHED(); |
394 | 1 | } |
395 | 1 | } |
396 | | |
397 | | ThrowCompletionOr<NonnullGCPtr<PrimitiveString>> Value::to_primitive_string(VM& vm) |
398 | 0 | { |
399 | 0 | if (is_string()) |
400 | 0 | return as_string(); |
401 | 0 | auto string = TRY(to_string(vm)); |
402 | 0 | return PrimitiveString::create(vm, move(string)); |
403 | 0 | } |
404 | | |
405 | | // 7.1.17 ToString ( argument ), https://tc39.es/ecma262/#sec-tostring |
406 | | ThrowCompletionOr<String> Value::to_string(VM& vm) const |
407 | 0 | { |
408 | 0 | if (is_double()) |
409 | 0 | return number_to_string(m_value.as_double); |
410 | | |
411 | 0 | switch (m_value.tag) { |
412 | | // 1. If argument is a String, return argument. |
413 | 0 | case STRING_TAG: |
414 | 0 | return as_string().utf8_string(); |
415 | | // 2. If argument is a Symbol, throw a TypeError exception. |
416 | 0 | case SYMBOL_TAG: |
417 | 0 | return vm.throw_completion<TypeError>(ErrorType::Convert, "symbol", "string"); |
418 | | // 3. If argument is undefined, return "undefined". |
419 | 0 | case UNDEFINED_TAG: |
420 | 0 | return "undefined"_string; |
421 | | // 4. If argument is null, return "null". |
422 | 0 | case NULL_TAG: |
423 | 0 | return "null"_string; |
424 | | // 5. If argument is true, return "true". |
425 | | // 6. If argument is false, return "false". |
426 | 0 | case BOOLEAN_TAG: |
427 | 0 | return as_bool() ? "true"_string : "false"_string; |
428 | | // 7. If argument is a Number, return Number::toString(argument, 10). |
429 | 0 | case INT32_TAG: |
430 | 0 | return String::number(as_i32()); |
431 | | // 8. If argument is a BigInt, return BigInt::toString(argument, 10). |
432 | 0 | case BIGINT_TAG: |
433 | 0 | return TRY_OR_THROW_OOM(vm, as_bigint().big_integer().to_base(10)); |
434 | | // 9. Assert: argument is an Object. |
435 | 0 | case OBJECT_TAG: { |
436 | | // 10. Let primValue be ? ToPrimitive(argument, string). |
437 | 0 | auto primitive_value = TRY(to_primitive(vm, PreferredType::String)); |
438 | | |
439 | | // 11. Assert: primValue is not an Object. |
440 | 0 | VERIFY(!primitive_value.is_object()); |
441 | | |
442 | | // 12. Return ? ToString(primValue). |
443 | 0 | return primitive_value.to_string(vm); |
444 | 0 | } |
445 | 0 | default: |
446 | 0 | VERIFY_NOT_REACHED(); |
447 | 0 | } |
448 | 0 | } |
449 | | |
450 | | // 7.1.17 ToString ( argument ), https://tc39.es/ecma262/#sec-tostring |
451 | | ThrowCompletionOr<ByteString> Value::to_byte_string(VM& vm) const |
452 | 0 | { |
453 | 0 | return TRY(to_string(vm)).to_byte_string(); |
454 | 0 | } |
455 | | |
456 | | ThrowCompletionOr<Utf16String> Value::to_utf16_string(VM& vm) const |
457 | 0 | { |
458 | 0 | if (is_string()) |
459 | 0 | return as_string().utf16_string(); |
460 | | |
461 | 0 | auto utf8_string = TRY(to_string(vm)); |
462 | 0 | return Utf16String::create(utf8_string.bytes_as_string_view()); |
463 | 0 | } |
464 | | |
465 | | ThrowCompletionOr<String> Value::to_well_formed_string(VM& vm) const |
466 | 0 | { |
467 | 0 | return ::JS::to_well_formed_string(TRY(to_utf16_string(vm))); |
468 | 0 | } |
469 | | |
470 | | // 7.1.2 ToBoolean ( argument ), https://tc39.es/ecma262/#sec-toboolean |
471 | | bool Value::to_boolean_slow_case() const |
472 | 0 | { |
473 | 0 | if (is_double()) { |
474 | 0 | if (is_nan()) |
475 | 0 | return false; |
476 | 0 | return m_value.as_double != 0; |
477 | 0 | } |
478 | | |
479 | 0 | switch (m_value.tag) { |
480 | | // 1. If argument is a Boolean, return argument. |
481 | 0 | case BOOLEAN_TAG: |
482 | 0 | return as_bool(); |
483 | | // 2. If argument is any of undefined, null, +0𝔽, -0𝔽, NaN, 0ℤ, or the empty String, return false. |
484 | 0 | case UNDEFINED_TAG: |
485 | 0 | case NULL_TAG: |
486 | 0 | return false; |
487 | 0 | case INT32_TAG: |
488 | 0 | return as_i32() != 0; |
489 | 0 | case STRING_TAG: |
490 | 0 | return !as_string().is_empty(); |
491 | 0 | case BIGINT_TAG: |
492 | 0 | return as_bigint().big_integer() != BIGINT_ZERO; |
493 | 0 | case OBJECT_TAG: |
494 | | // B.3.6.1 Changes to ToBoolean, https://tc39.es/ecma262/#sec-IsHTMLDDA-internal-slot-to-boolean |
495 | | // 3. If argument is an Object and argument has an [[IsHTMLDDA]] internal slot, return false. |
496 | 0 | if (as_object().is_htmldda()) |
497 | 0 | return false; |
498 | | // 4. Return true. |
499 | 0 | return true; |
500 | 0 | case SYMBOL_TAG: |
501 | 0 | return true; |
502 | 0 | default: |
503 | 0 | VERIFY_NOT_REACHED(); |
504 | 0 | } |
505 | 0 | } |
506 | | |
507 | | // 7.1.1 ToPrimitive ( input [ , preferredType ] ), https://tc39.es/ecma262/#sec-toprimitive |
508 | | ThrowCompletionOr<Value> Value::to_primitive_slow_case(VM& vm, PreferredType preferred_type) const |
509 | 0 | { |
510 | | // 1. If input is an Object, then |
511 | 0 | if (is_object()) { |
512 | | // a. Let exoticToPrim be ? GetMethod(input, @@toPrimitive). |
513 | 0 | auto exotic_to_primitive = TRY(get_method(vm, vm.well_known_symbol_to_primitive())); |
514 | | |
515 | | // b. If exoticToPrim is not undefined, then |
516 | 0 | if (exotic_to_primitive) { |
517 | 0 | auto hint = [&]() -> ByteString { |
518 | 0 | switch (preferred_type) { |
519 | | // i. If preferredType is not present, let hint be "default". |
520 | 0 | case PreferredType::Default: |
521 | 0 | return "default"; |
522 | | // ii. Else if preferredType is string, let hint be "string". |
523 | 0 | case PreferredType::String: |
524 | 0 | return "string"; |
525 | | // iii. Else, |
526 | | // 1. Assert: preferredType is number. |
527 | | // 2. Let hint be "number". |
528 | 0 | case PreferredType::Number: |
529 | 0 | return "number"; |
530 | 0 | default: |
531 | 0 | VERIFY_NOT_REACHED(); |
532 | 0 | } |
533 | 0 | }(); |
534 | | |
535 | | // iv. Let result be ? Call(exoticToPrim, input, « hint »). |
536 | 0 | auto result = TRY(call(vm, *exotic_to_primitive, *this, PrimitiveString::create(vm, hint))); |
537 | | |
538 | | // v. If result is not an Object, return result. |
539 | 0 | if (!result.is_object()) |
540 | 0 | return result; |
541 | | |
542 | | // vi. Throw a TypeError exception. |
543 | 0 | return vm.throw_completion<TypeError>(ErrorType::ToPrimitiveReturnedObject, to_string_without_side_effects(), hint); |
544 | 0 | } |
545 | | |
546 | | // c. If preferredType is not present, let preferredType be number. |
547 | 0 | if (preferred_type == PreferredType::Default) |
548 | 0 | preferred_type = PreferredType::Number; |
549 | | |
550 | | // d. Return ? OrdinaryToPrimitive(input, preferredType). |
551 | 0 | return as_object().ordinary_to_primitive(preferred_type); |
552 | 0 | } |
553 | | |
554 | | // 2. Return input. |
555 | 0 | return *this; |
556 | 0 | } |
557 | | |
558 | | // 7.1.18 ToObject ( argument ), https://tc39.es/ecma262/#sec-toobject |
559 | | ThrowCompletionOr<NonnullGCPtr<Object>> Value::to_object(VM& vm) const |
560 | 0 | { |
561 | 0 | auto& realm = *vm.current_realm(); |
562 | 0 | VERIFY(!is_empty()); |
563 | | |
564 | | // Number |
565 | 0 | if (is_number()) { |
566 | | // Return a new Number object whose [[NumberData]] internal slot is set to argument. See 21.1 for a description of Number objects. |
567 | 0 | return NumberObject::create(realm, as_double()); |
568 | 0 | } |
569 | | |
570 | 0 | switch (m_value.tag) { |
571 | | // Undefined |
572 | | // Null |
573 | 0 | case UNDEFINED_TAG: |
574 | 0 | case NULL_TAG: |
575 | | // Throw a TypeError exception. |
576 | 0 | return vm.throw_completion<TypeError>(ErrorType::ToObjectNullOrUndefined); |
577 | | // Boolean |
578 | 0 | case BOOLEAN_TAG: |
579 | | // Return a new Boolean object whose [[BooleanData]] internal slot is set to argument. See 20.3 for a description of Boolean objects. |
580 | 0 | return BooleanObject::create(realm, as_bool()); |
581 | | // String |
582 | 0 | case STRING_TAG: |
583 | | // Return a new String object whose [[StringData]] internal slot is set to argument. See 22.1 for a description of String objects. |
584 | 0 | return StringObject::create(realm, const_cast<JS::PrimitiveString&>(as_string()), realm.intrinsics().string_prototype()); |
585 | | // Symbol |
586 | 0 | case SYMBOL_TAG: |
587 | | // Return a new Symbol object whose [[SymbolData]] internal slot is set to argument. See 20.4 for a description of Symbol objects. |
588 | 0 | return SymbolObject::create(realm, const_cast<JS::Symbol&>(as_symbol())); |
589 | | // BigInt |
590 | 0 | case BIGINT_TAG: |
591 | | // Return a new BigInt object whose [[BigIntData]] internal slot is set to argument. See 21.2 for a description of BigInt objects. |
592 | 0 | return BigIntObject::create(realm, const_cast<JS::BigInt&>(as_bigint())); |
593 | | // Object |
594 | 0 | case OBJECT_TAG: |
595 | | // Return argument. |
596 | 0 | return const_cast<Object&>(as_object()); |
597 | 0 | default: |
598 | 0 | VERIFY_NOT_REACHED(); |
599 | 0 | } |
600 | 0 | } |
601 | | |
602 | | // 7.1.3 ToNumeric ( value ), https://tc39.es/ecma262/#sec-tonumeric |
603 | | FLATTEN ThrowCompletionOr<Value> Value::to_numeric_slow_case(VM& vm) const |
604 | 0 | { |
605 | | // 1. Let primValue be ? ToPrimitive(value, number). |
606 | 0 | auto primitive_value = TRY(to_primitive(vm, Value::PreferredType::Number)); |
607 | | |
608 | | // 2. If primValue is a BigInt, return primValue. |
609 | 0 | if (primitive_value.is_bigint()) |
610 | 0 | return primitive_value; |
611 | | |
612 | | // 3. Return ? ToNumber(primValue). |
613 | 0 | return primitive_value.to_number(vm); |
614 | 0 | } |
615 | | |
616 | | constexpr bool is_ascii_number(u32 code_point) |
617 | 0 | { |
618 | 0 | return is_ascii_digit(code_point) || code_point == '.' || (code_point == 'e' || code_point == 'E') || code_point == '+' || code_point == '-'; |
619 | 0 | } |
620 | | |
621 | | struct NumberParseResult { |
622 | | StringView literal; |
623 | | u8 base; |
624 | | }; |
625 | | |
626 | | static Optional<NumberParseResult> parse_number_text(StringView text) |
627 | 0 | { |
628 | 0 | NumberParseResult result {}; |
629 | |
|
630 | 0 | auto check_prefix = [&](auto lower_prefix, auto upper_prefix) { |
631 | 0 | if (text.length() <= 2) |
632 | 0 | return false; |
633 | 0 | if (!text.starts_with(lower_prefix) && !text.starts_with(upper_prefix)) |
634 | 0 | return false; |
635 | 0 | return true; |
636 | 0 | }; |
637 | | |
638 | | // https://tc39.es/ecma262/#sec-tonumber-applied-to-the-string-type |
639 | 0 | if (check_prefix("0b"sv, "0B"sv)) { |
640 | 0 | if (!all_of(text.substring_view(2), is_ascii_binary_digit)) |
641 | 0 | return {}; |
642 | | |
643 | 0 | result.literal = text.substring_view(2); |
644 | 0 | result.base = 2; |
645 | 0 | } else if (check_prefix("0o"sv, "0O"sv)) { |
646 | 0 | if (!all_of(text.substring_view(2), is_ascii_octal_digit)) |
647 | 0 | return {}; |
648 | | |
649 | 0 | result.literal = text.substring_view(2); |
650 | 0 | result.base = 8; |
651 | 0 | } else if (check_prefix("0x"sv, "0X"sv)) { |
652 | 0 | if (!all_of(text.substring_view(2), is_ascii_hex_digit)) |
653 | 0 | return {}; |
654 | | |
655 | 0 | result.literal = text.substring_view(2); |
656 | 0 | result.base = 16; |
657 | 0 | } else { |
658 | 0 | if (!all_of(text, is_ascii_number)) |
659 | 0 | return {}; |
660 | | |
661 | 0 | result.literal = text; |
662 | 0 | result.base = 10; |
663 | 0 | } |
664 | | |
665 | 0 | return result; |
666 | 0 | } |
667 | | |
668 | | // 7.1.4.1.1 StringToNumber ( str ), https://tc39.es/ecma262/#sec-stringtonumber |
669 | | double string_to_number(StringView string) |
670 | 0 | { |
671 | | // 1. Let text be StringToCodePoints(str). |
672 | 0 | auto text = Utf8View(string).trim(whitespace_characters, AK::TrimMode::Both).as_string(); |
673 | | |
674 | | // 2. Let literal be ParseText(text, StringNumericLiteral). |
675 | 0 | if (text.is_empty()) |
676 | 0 | return 0; |
677 | 0 | if (text == "Infinity"sv || text == "+Infinity"sv) |
678 | 0 | return INFINITY; |
679 | 0 | if (text == "-Infinity"sv) |
680 | 0 | return -INFINITY; |
681 | | |
682 | 0 | auto result = parse_number_text(text); |
683 | | |
684 | | // 3. If literal is a List of errors, return NaN. |
685 | 0 | if (!result.has_value()) |
686 | 0 | return NAN; |
687 | | |
688 | | // 4. Return StringNumericValue of literal. |
689 | 0 | if (result->base != 10) { |
690 | 0 | auto bigint = MUST(Crypto::UnsignedBigInteger::from_base(result->base, result->literal)); |
691 | 0 | return bigint.to_double(); |
692 | 0 | } |
693 | | |
694 | 0 | auto maybe_double = text.to_number<double>(AK::TrimWhitespace::No); |
695 | 0 | if (!maybe_double.has_value()) |
696 | 0 | return NAN; |
697 | | |
698 | 0 | return *maybe_double; |
699 | 0 | } |
700 | | |
701 | | // 7.1.4 ToNumber ( argument ), https://tc39.es/ecma262/#sec-tonumber |
702 | | ThrowCompletionOr<Value> Value::to_number_slow_case(VM& vm) const |
703 | 0 | { |
704 | 0 | VERIFY(!is_empty()); |
705 | | |
706 | | // 1. If argument is a Number, return argument. |
707 | 0 | if (is_number()) |
708 | 0 | return *this; |
709 | | |
710 | 0 | switch (m_value.tag) { |
711 | | // 2. If argument is either a Symbol or a BigInt, throw a TypeError exception. |
712 | 0 | case SYMBOL_TAG: |
713 | 0 | return vm.throw_completion<TypeError>(ErrorType::Convert, "symbol", "number"); |
714 | 0 | case BIGINT_TAG: |
715 | 0 | return vm.throw_completion<TypeError>(ErrorType::Convert, "BigInt", "number"); |
716 | | // 3. If argument is undefined, return NaN. |
717 | 0 | case UNDEFINED_TAG: |
718 | 0 | return js_nan(); |
719 | | // 4. If argument is either null or false, return +0𝔽. |
720 | 0 | case NULL_TAG: |
721 | 0 | return Value(0); |
722 | | // 5. If argument is true, return 1𝔽. |
723 | 0 | case BOOLEAN_TAG: |
724 | 0 | return Value(as_bool() ? 1 : 0); |
725 | | // 6. If argument is a String, return StringToNumber(argument). |
726 | 0 | case STRING_TAG: |
727 | 0 | return string_to_number(as_string().byte_string()); |
728 | | // 7. Assert: argument is an Object. |
729 | 0 | case OBJECT_TAG: { |
730 | | // 8. Let primValue be ? ToPrimitive(argument, number). |
731 | 0 | auto primitive_value = TRY(to_primitive(vm, PreferredType::Number)); |
732 | | |
733 | | // 9. Assert: primValue is not an Object. |
734 | 0 | VERIFY(!primitive_value.is_object()); |
735 | | |
736 | | // 10. Return ? ToNumber(primValue). |
737 | 0 | return primitive_value.to_number(vm); |
738 | 0 | } |
739 | 0 | default: |
740 | 0 | VERIFY_NOT_REACHED(); |
741 | 0 | } |
742 | 0 | } |
743 | | |
744 | | static Optional<BigInt*> string_to_bigint(VM& vm, StringView string); |
745 | | |
746 | | // 7.1.13 ToBigInt ( argument ), https://tc39.es/ecma262/#sec-tobigint |
747 | | ThrowCompletionOr<NonnullGCPtr<BigInt>> Value::to_bigint(VM& vm) const |
748 | 0 | { |
749 | | // 1. Let prim be ? ToPrimitive(argument, number). |
750 | 0 | auto primitive = TRY(to_primitive(vm, PreferredType::Number)); |
751 | | |
752 | | // 2. Return the value that prim corresponds to in Table 12. |
753 | | |
754 | | // Number |
755 | 0 | if (primitive.is_number()) { |
756 | | // Throw a TypeError exception. |
757 | 0 | return vm.throw_completion<TypeError>(ErrorType::Convert, "number", "BigInt"); |
758 | 0 | } |
759 | | |
760 | 0 | switch (primitive.m_value.tag) { |
761 | | // Undefined |
762 | 0 | case UNDEFINED_TAG: |
763 | | // Throw a TypeError exception. |
764 | 0 | return vm.throw_completion<TypeError>(ErrorType::Convert, "undefined", "BigInt"); |
765 | | // Null |
766 | 0 | case NULL_TAG: |
767 | | // Throw a TypeError exception. |
768 | 0 | return vm.throw_completion<TypeError>(ErrorType::Convert, "null", "BigInt"); |
769 | | // Boolean |
770 | 0 | case BOOLEAN_TAG: { |
771 | | // Return 1n if prim is true and 0n if prim is false. |
772 | 0 | auto value = primitive.as_bool() ? 1 : 0; |
773 | 0 | return BigInt::create(vm, Crypto::SignedBigInteger { value }); |
774 | 0 | } |
775 | | // BigInt |
776 | 0 | case BIGINT_TAG: |
777 | | // Return prim. |
778 | 0 | return primitive.as_bigint(); |
779 | 0 | case STRING_TAG: { |
780 | | // 1. Let n be ! StringToBigInt(prim). |
781 | 0 | auto bigint = string_to_bigint(vm, primitive.as_string().byte_string()); |
782 | | |
783 | | // 2. If n is undefined, throw a SyntaxError exception. |
784 | 0 | if (!bigint.has_value()) |
785 | 0 | return vm.throw_completion<SyntaxError>(ErrorType::BigIntInvalidValue, primitive); |
786 | | |
787 | | // 3. Return n. |
788 | 0 | return *bigint.release_value(); |
789 | 0 | } |
790 | | // Symbol |
791 | 0 | case SYMBOL_TAG: |
792 | | // Throw a TypeError exception. |
793 | 0 | return vm.throw_completion<TypeError>(ErrorType::Convert, "symbol", "BigInt"); |
794 | 0 | default: |
795 | 0 | VERIFY_NOT_REACHED(); |
796 | 0 | } |
797 | 0 | } |
798 | | |
799 | | struct BigIntParseResult { |
800 | | StringView literal; |
801 | | u8 base { 10 }; |
802 | | bool is_negative { false }; |
803 | | }; |
804 | | |
805 | | static Optional<BigIntParseResult> parse_bigint_text(StringView text) |
806 | 0 | { |
807 | 0 | BigIntParseResult result {}; |
808 | |
|
809 | 0 | auto parse_for_prefixed_base = [&](auto lower_prefix, auto upper_prefix, auto validator) { |
810 | 0 | if (text.length() <= 2) |
811 | 0 | return false; |
812 | 0 | if (!text.starts_with(lower_prefix) && !text.starts_with(upper_prefix)) |
813 | 0 | return false; |
814 | 0 | return all_of(text.substring_view(2), validator); |
815 | 0 | }; |
816 | |
|
817 | 0 | if (parse_for_prefixed_base("0b"sv, "0B"sv, is_ascii_binary_digit)) { |
818 | 0 | result.literal = text.substring_view(2); |
819 | 0 | result.base = 2; |
820 | 0 | } else if (parse_for_prefixed_base("0o"sv, "0O"sv, is_ascii_octal_digit)) { |
821 | 0 | result.literal = text.substring_view(2); |
822 | 0 | result.base = 8; |
823 | 0 | } else if (parse_for_prefixed_base("0x"sv, "0X"sv, is_ascii_hex_digit)) { |
824 | 0 | result.literal = text.substring_view(2); |
825 | 0 | result.base = 16; |
826 | 0 | } else { |
827 | 0 | if (text.starts_with('-')) { |
828 | 0 | text = text.substring_view(1); |
829 | 0 | result.is_negative = true; |
830 | 0 | } else if (text.starts_with('+')) { |
831 | 0 | text = text.substring_view(1); |
832 | 0 | } |
833 | |
|
834 | 0 | if (!all_of(text, is_ascii_digit)) |
835 | 0 | return {}; |
836 | | |
837 | 0 | result.literal = text; |
838 | 0 | result.base = 10; |
839 | 0 | } |
840 | | |
841 | 0 | return result; |
842 | 0 | } |
843 | | |
844 | | // 7.1.14 StringToBigInt ( str ), https://tc39.es/ecma262/#sec-stringtobigint |
845 | | static Optional<BigInt*> string_to_bigint(VM& vm, StringView string) |
846 | 0 | { |
847 | | // 1. Let text be StringToCodePoints(str). |
848 | 0 | auto text = Utf8View(string).trim(whitespace_characters, AK::TrimMode::Both).as_string(); |
849 | | |
850 | | // 2. Let literal be ParseText(text, StringIntegerLiteral). |
851 | 0 | auto result = parse_bigint_text(text); |
852 | | |
853 | | // 3. If literal is a List of errors, return undefined. |
854 | 0 | if (!result.has_value()) |
855 | 0 | return {}; |
856 | | |
857 | | // 4. Let mv be the MV of literal. |
858 | | // 5. Assert: mv is an integer. |
859 | 0 | auto bigint = MUST(Crypto::SignedBigInteger::from_base(result->base, result->literal)); |
860 | 0 | if (result->is_negative && (bigint != BIGINT_ZERO)) |
861 | 0 | bigint.negate(); |
862 | | |
863 | | // 6. Return ℤ(mv). |
864 | 0 | return BigInt::create(vm, move(bigint)); |
865 | 0 | } |
866 | | |
867 | | // 7.1.15 ToBigInt64 ( argument ), https://tc39.es/ecma262/#sec-tobigint64 |
868 | | ThrowCompletionOr<i64> Value::to_bigint_int64(VM& vm) const |
869 | 0 | { |
870 | | // 1. Let n be ? ToBigInt(argument). |
871 | 0 | auto bigint = TRY(to_bigint(vm)); |
872 | | |
873 | | // 2. Let int64bit be ℝ(n) modulo 2^64. |
874 | | // 3. If int64bit ≥ 2^63, return ℤ(int64bit - 2^64); otherwise return ℤ(int64bit). |
875 | 0 | return static_cast<i64>(bigint->big_integer().to_u64()); |
876 | 0 | } |
877 | | |
878 | | // 7.1.16 ToBigUint64 ( argument ), https://tc39.es/ecma262/#sec-tobiguint64 |
879 | | ThrowCompletionOr<u64> Value::to_bigint_uint64(VM& vm) const |
880 | 0 | { |
881 | | // 1. Let n be ? ToBigInt(argument). |
882 | 0 | auto bigint = TRY(to_bigint(vm)); |
883 | | |
884 | | // 2. Let int64bit be ℝ(n) modulo 2^64. |
885 | | // 3. Return ℤ(int64bit). |
886 | 0 | return bigint->big_integer().to_u64(); |
887 | 0 | } |
888 | | |
889 | | ThrowCompletionOr<double> Value::to_double(VM& vm) const |
890 | 0 | { |
891 | 0 | return TRY(to_number(vm)).as_double(); |
892 | 0 | } |
893 | | |
894 | | // 7.1.19 ToPropertyKey ( argument ), https://tc39.es/ecma262/#sec-topropertykey |
895 | | ThrowCompletionOr<PropertyKey> Value::to_property_key(VM& vm) const |
896 | 0 | { |
897 | | // OPTIMIZATION: Return the value as a numeric PropertyKey, if possible. |
898 | 0 | if (is_int32() && as_i32() >= 0) |
899 | 0 | return PropertyKey { as_i32() }; |
900 | | |
901 | | // 1. Let key be ? ToPrimitive(argument, string). |
902 | 0 | auto key = TRY(to_primitive(vm, PreferredType::String)); |
903 | | |
904 | | // 2. If key is a Symbol, then |
905 | 0 | if (key.is_symbol()) { |
906 | | // a. Return key. |
907 | 0 | return &key.as_symbol(); |
908 | 0 | } |
909 | | |
910 | | // 3. Return ! ToString(key). |
911 | 0 | return MUST(key.to_byte_string(vm)); |
912 | 0 | } |
913 | | |
914 | | // 7.1.6 ToInt32 ( argument ), https://tc39.es/ecma262/#sec-toint32 |
915 | | ThrowCompletionOr<i32> Value::to_i32_slow_case(VM& vm) const |
916 | 0 | { |
917 | 0 | VERIFY(!is_int32()); |
918 | | |
919 | | // 1. Let number be ? ToNumber(argument). |
920 | 0 | double number = TRY(to_number(vm)).as_double(); |
921 | | |
922 | | // 2. If number is not finite or number is either +0𝔽 or -0𝔽, return +0𝔽. |
923 | 0 | if (!isfinite(number) || number == 0) |
924 | 0 | return 0; |
925 | | |
926 | | // 3. Let int be the mathematical value whose sign is the sign of number and whose magnitude is floor(abs(ℝ(number))). |
927 | 0 | auto abs = fabs(number); |
928 | 0 | auto int_val = floor(abs); |
929 | 0 | if (signbit(number)) |
930 | 0 | int_val = -int_val; |
931 | | |
932 | | // 4. Let int32bit be int modulo 2^32. |
933 | 0 | auto int32bit = modulo(int_val, NumericLimits<u32>::max() + 1.0); |
934 | | |
935 | | // 5. If int32bit ≥ 2^31, return 𝔽(int32bit - 2^32); otherwise return 𝔽(int32bit). |
936 | 0 | if (int32bit >= 2147483648.0) |
937 | 0 | int32bit -= 4294967296.0; |
938 | 0 | return static_cast<i32>(int32bit); |
939 | 0 | } |
940 | | |
941 | | // 7.1.6 ToInt32 ( argument ), https://tc39.es/ecma262/#sec-toint32 |
942 | | ThrowCompletionOr<i32> Value::to_i32(VM& vm) const |
943 | 0 | { |
944 | 0 | if (is_int32()) |
945 | 0 | return as_i32(); |
946 | 0 | return to_i32_slow_case(vm); |
947 | 0 | } |
948 | | |
949 | | // 7.1.7 ToUint32 ( argument ), https://tc39.es/ecma262/#sec-touint32 |
950 | | ThrowCompletionOr<u32> Value::to_u32(VM& vm) const |
951 | 5 | { |
952 | | // OPTIMIZATION: If this value is encoded as a positive i32, return it directly. |
953 | 5 | if (is_int32() && as_i32() >= 0) |
954 | 5 | return as_i32(); |
955 | | |
956 | | // 1. Let number be ? ToNumber(argument). |
957 | 0 | double number = TRY(to_number(vm)).as_double(); |
958 | | |
959 | | // 2. If number is not finite or number is either +0𝔽 or -0𝔽, return +0𝔽. |
960 | 0 | if (!isfinite(number) || number == 0) |
961 | 0 | return 0; |
962 | | |
963 | | // 3. Let int be the mathematical value whose sign is the sign of number and whose magnitude is floor(abs(ℝ(number))). |
964 | 0 | auto int_val = floor(fabs(number)); |
965 | 0 | if (signbit(number)) |
966 | 0 | int_val = -int_val; |
967 | | |
968 | | // 4. Let int32bit be int modulo 2^32. |
969 | 0 | auto int32bit = modulo(int_val, NumericLimits<u32>::max() + 1.0); |
970 | | |
971 | | // 5. Return 𝔽(int32bit). |
972 | | // Cast to i64 here to ensure that the double --> u32 cast doesn't invoke undefined behavior |
973 | | // Otherwise, negative numbers cause a UBSAN warning. |
974 | 0 | return static_cast<u32>(static_cast<i64>(int32bit)); |
975 | 0 | } |
976 | | |
977 | | // 7.1.8 ToInt16 ( argument ), https://tc39.es/ecma262/#sec-toint16 |
978 | | ThrowCompletionOr<i16> Value::to_i16(VM& vm) const |
979 | 0 | { |
980 | | // 1. Let number be ? ToNumber(argument). |
981 | 0 | double number = TRY(to_number(vm)).as_double(); |
982 | | |
983 | | // 2. If number is not finite or number is either +0𝔽 or -0𝔽, return +0𝔽. |
984 | 0 | if (!isfinite(number) || number == 0) |
985 | 0 | return 0; |
986 | | |
987 | | // 3. Let int be the mathematical value whose sign is the sign of number and whose magnitude is floor(abs(ℝ(number))). |
988 | 0 | auto abs = fabs(number); |
989 | 0 | auto int_val = floor(abs); |
990 | 0 | if (signbit(number)) |
991 | 0 | int_val = -int_val; |
992 | | |
993 | | // 4. Let int16bit be int modulo 2^16. |
994 | 0 | auto int16bit = modulo(int_val, NumericLimits<u16>::max() + 1.0); |
995 | | |
996 | | // 5. If int16bit ≥ 2^15, return 𝔽(int16bit - 2^16); otherwise return 𝔽(int16bit). |
997 | 0 | if (int16bit >= 32768.0) |
998 | 0 | int16bit -= 65536.0; |
999 | 0 | return static_cast<i16>(int16bit); |
1000 | 0 | } |
1001 | | |
1002 | | // 7.1.9 ToUint16 ( argument ), https://tc39.es/ecma262/#sec-touint16 |
1003 | | ThrowCompletionOr<u16> Value::to_u16(VM& vm) const |
1004 | 0 | { |
1005 | | // 1. Let number be ? ToNumber(argument). |
1006 | 0 | double number = TRY(to_number(vm)).as_double(); |
1007 | | |
1008 | | // 2. If number is not finite or number is either +0𝔽 or -0𝔽, return +0𝔽. |
1009 | 0 | if (!isfinite(number) || number == 0) |
1010 | 0 | return 0; |
1011 | | |
1012 | | // 3. Let int be the mathematical value whose sign is the sign of number and whose magnitude is floor(abs(ℝ(number))). |
1013 | 0 | auto int_val = floor(fabs(number)); |
1014 | 0 | if (signbit(number)) |
1015 | 0 | int_val = -int_val; |
1016 | | |
1017 | | // 4. Let int16bit be int modulo 2^16. |
1018 | 0 | auto int16bit = modulo(int_val, NumericLimits<u16>::max() + 1.0); |
1019 | | |
1020 | | // 5. Return 𝔽(int16bit). |
1021 | 0 | return static_cast<u16>(int16bit); |
1022 | 0 | } |
1023 | | |
1024 | | // 7.1.10 ToInt8 ( argument ), https://tc39.es/ecma262/#sec-toint8 |
1025 | | ThrowCompletionOr<i8> Value::to_i8(VM& vm) const |
1026 | 0 | { |
1027 | | // 1. Let number be ? ToNumber(argument). |
1028 | 0 | double number = TRY(to_number(vm)).as_double(); |
1029 | | |
1030 | | // 2. If number is not finite or number is either +0𝔽 or -0𝔽, return +0𝔽. |
1031 | 0 | if (!isfinite(number) || number == 0) |
1032 | 0 | return 0; |
1033 | | |
1034 | | // 3. Let int be the mathematical value whose sign is the sign of number and whose magnitude is floor(abs(ℝ(number))). |
1035 | 0 | auto abs = fabs(number); |
1036 | 0 | auto int_val = floor(abs); |
1037 | 0 | if (signbit(number)) |
1038 | 0 | int_val = -int_val; |
1039 | | |
1040 | | // 4. Let int8bit be int modulo 2^8. |
1041 | 0 | auto int8bit = modulo(int_val, NumericLimits<u8>::max() + 1.0); |
1042 | | |
1043 | | // 5. If int8bit ≥ 2^7, return 𝔽(int8bit - 2^8); otherwise return 𝔽(int8bit). |
1044 | 0 | if (int8bit >= 128.0) |
1045 | 0 | int8bit -= 256.0; |
1046 | 0 | return static_cast<i8>(int8bit); |
1047 | 0 | } |
1048 | | |
1049 | | // 7.1.11 ToUint8 ( argument ), https://tc39.es/ecma262/#sec-touint8 |
1050 | | ThrowCompletionOr<u8> Value::to_u8(VM& vm) const |
1051 | 0 | { |
1052 | | // 1. Let number be ? ToNumber(argument). |
1053 | 0 | double number = TRY(to_number(vm)).as_double(); |
1054 | | |
1055 | | // 2. If number is not finite or number is either +0𝔽 or -0𝔽, return +0𝔽. |
1056 | 0 | if (!isfinite(number) || number == 0) |
1057 | 0 | return 0; |
1058 | | |
1059 | | // 3. Let int be the mathematical value whose sign is the sign of number and whose magnitude is floor(abs(ℝ(number))). |
1060 | 0 | auto int_val = floor(fabs(number)); |
1061 | 0 | if (signbit(number)) |
1062 | 0 | int_val = -int_val; |
1063 | | |
1064 | | // 4. Let int8bit be int modulo 2^8. |
1065 | 0 | auto int8bit = modulo(int_val, NumericLimits<u8>::max() + 1.0); |
1066 | | |
1067 | | // 5. Return 𝔽(int8bit). |
1068 | 0 | return static_cast<u8>(int8bit); |
1069 | 0 | } |
1070 | | |
1071 | | // 7.1.12 ToUint8Clamp ( argument ), https://tc39.es/ecma262/#sec-touint8clamp |
1072 | | ThrowCompletionOr<u8> Value::to_u8_clamp(VM& vm) const |
1073 | 0 | { |
1074 | | // 1. Let number be ? ToNumber(argument). |
1075 | 0 | auto number = TRY(to_number(vm)); |
1076 | | |
1077 | | // 2. If number is NaN, return +0𝔽. |
1078 | 0 | if (number.is_nan()) |
1079 | 0 | return 0; |
1080 | | |
1081 | 0 | double value = number.as_double(); |
1082 | | |
1083 | | // 3. If ℝ(number) ≤ 0, return +0𝔽. |
1084 | 0 | if (value <= 0.0) |
1085 | 0 | return 0; |
1086 | | |
1087 | | // 4. If ℝ(number) ≥ 255, return 255𝔽. |
1088 | 0 | if (value >= 255.0) |
1089 | 0 | return 255; |
1090 | | |
1091 | | // 5. Let f be floor(ℝ(number)). |
1092 | 0 | auto int_val = floor(value); |
1093 | | |
1094 | | // 6. If f + 0.5 < ℝ(number), return 𝔽(f + 1). |
1095 | 0 | if (int_val + 0.5 < value) |
1096 | 0 | return static_cast<u8>(int_val + 1.0); |
1097 | | |
1098 | | // 7. If ℝ(number) < f + 0.5, return 𝔽(f). |
1099 | 0 | if (value < int_val + 0.5) |
1100 | 0 | return static_cast<u8>(int_val); |
1101 | | |
1102 | | // 8. If f is odd, return 𝔽(f + 1). |
1103 | 0 | if (fmod(int_val, 2.0) == 1.0) |
1104 | 0 | return static_cast<u8>(int_val + 1.0); |
1105 | | |
1106 | | // 9. Return 𝔽(f). |
1107 | 0 | return static_cast<u8>(int_val); |
1108 | 0 | } |
1109 | | |
1110 | | // 7.1.20 ToLength ( argument ), https://tc39.es/ecma262/#sec-tolength |
1111 | | ThrowCompletionOr<size_t> Value::to_length(VM& vm) const |
1112 | 0 | { |
1113 | | // 1. Let len be ? ToIntegerOrInfinity(argument). |
1114 | 0 | auto len = TRY(to_integer_or_infinity(vm)); |
1115 | | |
1116 | | // 2. If len ≤ 0, return +0𝔽. |
1117 | 0 | if (len <= 0) |
1118 | 0 | return 0; |
1119 | | |
1120 | | // FIXME: The expected output range is 0 - 2^53-1, but we don't want to overflow the size_t on 32-bit platforms. |
1121 | | // Convert this to u64 so it works everywhere. |
1122 | 0 | constexpr double length_limit = sizeof(void*) == 4 ? NumericLimits<size_t>::max() : MAX_ARRAY_LIKE_INDEX; |
1123 | | |
1124 | | // 3. Return 𝔽(min(len, 2^53 - 1)). |
1125 | 0 | return min(len, length_limit); |
1126 | 0 | } |
1127 | | |
1128 | | // 7.1.22 ToIndex ( argument ), https://tc39.es/ecma262/#sec-toindex |
1129 | | ThrowCompletionOr<size_t> Value::to_index(VM& vm) const |
1130 | 0 | { |
1131 | | // 1. If value is undefined, then |
1132 | 0 | if (is_undefined()) { |
1133 | | // a. Return 0. |
1134 | 0 | return 0; |
1135 | 0 | } |
1136 | | |
1137 | | // 2. Else, |
1138 | | // a. Let integer be ? ToIntegerOrInfinity(value). |
1139 | 0 | auto integer = TRY(to_integer_or_infinity(vm)); |
1140 | | |
1141 | | // OPTIMIZATION: If the value is negative, ToLength normalizes it to 0, and we fail the SameValue comparison below. |
1142 | | // Bail out early instead. |
1143 | 0 | if (integer < 0) |
1144 | 0 | return vm.throw_completion<RangeError>(ErrorType::InvalidIndex); |
1145 | | |
1146 | | // b. Let clamped be ! ToLength(𝔽(integer)). |
1147 | 0 | auto clamped = MUST(Value(integer).to_length(vm)); |
1148 | | |
1149 | | // c. If SameValue(𝔽(integer), clamped) is false, throw a RangeError exception. |
1150 | 0 | if (integer != clamped) |
1151 | 0 | return vm.throw_completion<RangeError>(ErrorType::InvalidIndex); |
1152 | | |
1153 | | // d. Assert: 0 ≤ integer ≤ 2^53 - 1. |
1154 | 0 | VERIFY(0 <= integer && integer <= MAX_ARRAY_LIKE_INDEX); |
1155 | | |
1156 | | // e. Return integer. |
1157 | | // NOTE: We return the clamped value here, which already has the right type. |
1158 | 0 | return clamped; |
1159 | 0 | } |
1160 | | |
1161 | | // 7.1.5 ToIntegerOrInfinity ( argument ), https://tc39.es/ecma262/#sec-tointegerorinfinity |
1162 | | ThrowCompletionOr<double> Value::to_integer_or_infinity(VM& vm) const |
1163 | 0 | { |
1164 | | // 1. Let number be ? ToNumber(argument). |
1165 | 0 | auto number = TRY(to_number(vm)); |
1166 | | |
1167 | | // 2. If number is NaN, +0𝔽, or -0𝔽, return 0. |
1168 | 0 | if (number.is_nan() || number.as_double() == 0) |
1169 | 0 | return 0; |
1170 | | |
1171 | | // 3. If number is +∞𝔽, return +∞. |
1172 | | // 4. If number is -∞𝔽, return -∞. |
1173 | 0 | if (number.is_infinity()) |
1174 | 0 | return number.as_double(); |
1175 | | |
1176 | | // 5. Let integer be floor(abs(ℝ(number))). |
1177 | 0 | auto integer = floor(fabs(number.as_double())); |
1178 | | |
1179 | | // 6. If number < -0𝔽, set integer to -integer. |
1180 | | // NOTE: The zero check is required as 'integer' is a double here but an MV in the spec, |
1181 | | // which doesn't have negative zero. |
1182 | 0 | if (number.as_double() < 0 && integer != 0) |
1183 | 0 | integer = -integer; |
1184 | | |
1185 | | // 7. Return integer. |
1186 | 0 | return integer; |
1187 | 0 | } |
1188 | | |
1189 | | // Standalone variant using plain doubles for cases where we already got numbers and know the AO won't throw. |
1190 | | double to_integer_or_infinity(double number) |
1191 | 0 | { |
1192 | | // 1. Let number be ? ToNumber(argument). |
1193 | | |
1194 | | // 2. If number is NaN, +0𝔽, or -0𝔽, return 0. |
1195 | 0 | if (isnan(number) || number == 0) |
1196 | 0 | return 0; |
1197 | | |
1198 | | // 3. If number is +∞𝔽, return +∞. |
1199 | 0 | if (__builtin_isinf_sign(number) > 0) |
1200 | 0 | return static_cast<double>(INFINITY); |
1201 | | |
1202 | | // 4. If number is -∞𝔽, return -∞. |
1203 | 0 | if (__builtin_isinf_sign(number) < 0) |
1204 | 0 | return static_cast<double>(-INFINITY); |
1205 | | |
1206 | | // 5. Let integer be floor(abs(ℝ(number))). |
1207 | 0 | auto integer = floor(fabs(number)); |
1208 | | |
1209 | | // 6. If number < -0𝔽, set integer to -integer. |
1210 | | // NOTE: The zero check is required as 'integer' is a double here but an MV in the spec, |
1211 | | // which doesn't have negative zero. |
1212 | 0 | if (number < 0 && integer != 0) |
1213 | 0 | integer = -integer; |
1214 | | |
1215 | | // 7. Return integer. |
1216 | 0 | return integer; |
1217 | 0 | } |
1218 | | |
1219 | | // 7.3.3 GetV ( V, P ), https://tc39.es/ecma262/#sec-getv |
1220 | | ThrowCompletionOr<Value> Value::get(VM& vm, PropertyKey const& property_key) const |
1221 | 0 | { |
1222 | | // 1. Assert: IsPropertyKey(P) is true. |
1223 | 0 | VERIFY(property_key.is_valid()); |
1224 | | |
1225 | | // 2. Let O be ? ToObject(V). |
1226 | 0 | auto object = TRY(to_object(vm)); |
1227 | | |
1228 | | // 3. Return ? O.[[Get]](P, V). |
1229 | 0 | return TRY(object->internal_get(property_key, *this)); |
1230 | 0 | } |
1231 | | |
1232 | | // 7.3.11 GetMethod ( V, P ), https://tc39.es/ecma262/#sec-getmethod |
1233 | | ThrowCompletionOr<GCPtr<FunctionObject>> Value::get_method(VM& vm, PropertyKey const& property_key) const |
1234 | 0 | { |
1235 | | // 1. Assert: IsPropertyKey(P) is true. |
1236 | 0 | VERIFY(property_key.is_valid()); |
1237 | | |
1238 | | // 2. Let func be ? GetV(V, P). |
1239 | 0 | auto function = TRY(get(vm, property_key)); |
1240 | | |
1241 | | // 3. If func is either undefined or null, return undefined. |
1242 | 0 | if (function.is_nullish()) |
1243 | 0 | return nullptr; |
1244 | | |
1245 | | // 4. If IsCallable(func) is false, throw a TypeError exception. |
1246 | 0 | if (!function.is_function()) |
1247 | 0 | return vm.throw_completion<TypeError>(ErrorType::NotAFunction, function.to_string_without_side_effects()); |
1248 | | |
1249 | | // 5. Return func. |
1250 | 0 | return function.as_function(); |
1251 | 0 | } |
1252 | | |
1253 | | // 13.10 Relational Operators, https://tc39.es/ecma262/#sec-relational-operators |
1254 | | // RelationalExpression : RelationalExpression > ShiftExpression |
1255 | | ThrowCompletionOr<Value> greater_than(VM& vm, Value lhs, Value rhs) |
1256 | 0 | { |
1257 | | // 1. Let lref be ? Evaluation of RelationalExpression. |
1258 | | // 2. Let lval be ? GetValue(lref). |
1259 | | // 3. Let rref be ? Evaluation of ShiftExpression. |
1260 | | // 4. Let rval be ? GetValue(rref). |
1261 | | // NOTE: This is handled in the AST or Bytecode interpreter. |
1262 | | |
1263 | | // OPTIMIZATION: If both values are i32, we can do a direct comparison without calling into IsLessThan. |
1264 | 0 | if (lhs.is_int32() && rhs.is_int32()) |
1265 | 0 | return lhs.as_i32() > rhs.as_i32(); |
1266 | | |
1267 | | // 5. Let r be ? IsLessThan(rval, lval, false). |
1268 | 0 | auto relation = TRY(is_less_than(vm, lhs, rhs, false)); |
1269 | | |
1270 | | // 6. If r is undefined, return false. Otherwise, return r. |
1271 | 0 | if (relation == TriState::Unknown) |
1272 | 0 | return Value(false); |
1273 | 0 | return Value(relation == TriState::True); |
1274 | 0 | } |
1275 | | |
1276 | | // 13.10 Relational Operators, https://tc39.es/ecma262/#sec-relational-operators |
1277 | | // RelationalExpression : RelationalExpression >= ShiftExpression |
1278 | | ThrowCompletionOr<Value> greater_than_equals(VM& vm, Value lhs, Value rhs) |
1279 | 0 | { |
1280 | | // 1. Let lref be ? Evaluation of RelationalExpression. |
1281 | | // 2. Let lval be ? GetValue(lref). |
1282 | | // 3. Let rref be ? Evaluation of ShiftExpression. |
1283 | | // 4. Let rval be ? GetValue(rref). |
1284 | | // NOTE: This is handled in the AST or Bytecode interpreter. |
1285 | | |
1286 | | // OPTIMIZATION: If both values are i32, we can do a direct comparison without calling into IsLessThan. |
1287 | 0 | if (lhs.is_int32() && rhs.is_int32()) |
1288 | 0 | return lhs.as_i32() >= rhs.as_i32(); |
1289 | | |
1290 | | // 5. Let r be ? IsLessThan(lval, rval, true). |
1291 | 0 | auto relation = TRY(is_less_than(vm, lhs, rhs, true)); |
1292 | | |
1293 | | // 6. If r is true or undefined, return false. Otherwise, return true. |
1294 | 0 | if (relation == TriState::Unknown || relation == TriState::True) |
1295 | 0 | return Value(false); |
1296 | 0 | return Value(true); |
1297 | 0 | } |
1298 | | |
1299 | | // 13.10 Relational Operators, https://tc39.es/ecma262/#sec-relational-operators |
1300 | | // RelationalExpression : RelationalExpression < ShiftExpression |
1301 | | ThrowCompletionOr<Value> less_than(VM& vm, Value lhs, Value rhs) |
1302 | 0 | { |
1303 | | // 1. Let lref be ? Evaluation of RelationalExpression. |
1304 | | // 2. Let lval be ? GetValue(lref). |
1305 | | // 3. Let rref be ? Evaluation of ShiftExpression. |
1306 | | // 4. Let rval be ? GetValue(rref). |
1307 | | // NOTE: This is handled in the AST or Bytecode interpreter. |
1308 | | |
1309 | | // OPTIMIZATION: If both values are i32, we can do a direct comparison without calling into IsLessThan. |
1310 | 0 | if (lhs.is_int32() && rhs.is_int32()) |
1311 | 0 | return lhs.as_i32() < rhs.as_i32(); |
1312 | | |
1313 | | // 5. Let r be ? IsLessThan(lval, rval, true). |
1314 | 0 | auto relation = TRY(is_less_than(vm, lhs, rhs, true)); |
1315 | | |
1316 | | // 6. If r is undefined, return false. Otherwise, return r. |
1317 | 0 | if (relation == TriState::Unknown) |
1318 | 0 | return Value(false); |
1319 | 0 | return Value(relation == TriState::True); |
1320 | 0 | } |
1321 | | |
1322 | | // 13.10 Relational Operators, https://tc39.es/ecma262/#sec-relational-operators |
1323 | | // RelationalExpression : RelationalExpression <= ShiftExpression |
1324 | | ThrowCompletionOr<Value> less_than_equals(VM& vm, Value lhs, Value rhs) |
1325 | 0 | { |
1326 | | // 1. Let lref be ? Evaluation of RelationalExpression. |
1327 | | // 2. Let lval be ? GetValue(lref). |
1328 | | // 3. Let rref be ? Evaluation of ShiftExpression. |
1329 | | // 4. Let rval be ? GetValue(rref). |
1330 | | // NOTE: This is handled in the AST or Bytecode interpreter. |
1331 | | |
1332 | | // OPTIMIZATION: If both values are i32, we can do a direct comparison without calling into IsLessThan. |
1333 | 0 | if (lhs.is_int32() && rhs.is_int32()) |
1334 | 0 | return lhs.as_i32() <= rhs.as_i32(); |
1335 | | |
1336 | | // 5. Let r be ? IsLessThan(rval, lval, false). |
1337 | 0 | auto relation = TRY(is_less_than(vm, lhs, rhs, false)); |
1338 | | |
1339 | | // 6. If r is true or undefined, return false. Otherwise, return true. |
1340 | 0 | if (relation == TriState::True || relation == TriState::Unknown) |
1341 | 0 | return Value(false); |
1342 | 0 | return Value(true); |
1343 | 0 | } |
1344 | | |
1345 | | // 13.12 Binary Bitwise Operators, https://tc39.es/ecma262/#sec-binary-bitwise-operators |
1346 | | // BitwiseANDExpression : BitwiseANDExpression & EqualityExpression |
1347 | | ThrowCompletionOr<Value> bitwise_and(VM& vm, Value lhs, Value rhs) |
1348 | 0 | { |
1349 | | // OPTIMIZATION: Fast path when both values are Int32. |
1350 | 0 | if (lhs.is_int32() && rhs.is_int32()) |
1351 | 0 | return Value(lhs.as_i32() & rhs.as_i32()); |
1352 | | |
1353 | | // 13.15.3 ApplyStringOrNumericBinaryOperator ( lval, opText, rval ), https://tc39.es/ecma262/#sec-applystringornumericbinaryoperator |
1354 | | // 1-2, 6. N/A. |
1355 | | |
1356 | | // 3. Let lnum be ? ToNumeric(lval). |
1357 | 0 | auto lhs_numeric = TRY(lhs.to_numeric(vm)); |
1358 | | |
1359 | | // 4. Let rnum be ? ToNumeric(rval). |
1360 | 0 | auto rhs_numeric = TRY(rhs.to_numeric(vm)); |
1361 | | |
1362 | | // 7. Let operation be the abstract operation associated with opText and Type(lnum) in the following table: |
1363 | | // [...] |
1364 | | // 8. Return operation(lnum, rnum). |
1365 | 0 | if (both_number(lhs_numeric, rhs_numeric)) { |
1366 | | // 6.1.6.1.17 Number::bitwiseAND ( x, y ), https://tc39.es/ecma262/#sec-numeric-types-number-bitwiseAND |
1367 | | // 1. Return NumberBitwiseOp(&, x, y). |
1368 | 0 | if (!lhs_numeric.is_finite_number() || !rhs_numeric.is_finite_number()) |
1369 | 0 | return Value(0); |
1370 | 0 | return Value(TRY(lhs_numeric.to_i32(vm)) & TRY(rhs_numeric.to_i32(vm))); |
1371 | 0 | } |
1372 | 0 | if (both_bigint(lhs_numeric, rhs_numeric)) { |
1373 | | // 6.1.6.2.18 BigInt::bitwiseAND ( x, y ), https://tc39.es/ecma262/#sec-numeric-types-bigint-bitwiseAND |
1374 | | // 1. Return BigIntBitwiseOp(&, x, y). |
1375 | 0 | return BigInt::create(vm, lhs_numeric.as_bigint().big_integer().bitwise_and(rhs_numeric.as_bigint().big_integer())); |
1376 | 0 | } |
1377 | | |
1378 | | // 5. If Type(lnum) is different from Type(rnum), throw a TypeError exception. |
1379 | 0 | return vm.throw_completion<TypeError>(ErrorType::BigIntBadOperatorOtherType, "bitwise AND"); |
1380 | 0 | } |
1381 | | |
1382 | | // 13.12 Binary Bitwise Operators, https://tc39.es/ecma262/#sec-binary-bitwise-operators |
1383 | | // BitwiseORExpression : BitwiseORExpression | BitwiseXORExpression |
1384 | | ThrowCompletionOr<Value> bitwise_or(VM& vm, Value lhs, Value rhs) |
1385 | 0 | { |
1386 | | // OPTIMIZATION: Fast path when both values are Int32. |
1387 | 0 | if (lhs.is_int32() && rhs.is_int32()) |
1388 | 0 | return Value(lhs.as_i32() | rhs.as_i32()); |
1389 | | |
1390 | | // 13.15.3 ApplyStringOrNumericBinaryOperator ( lval, opText, rval ), https://tc39.es/ecma262/#sec-applystringornumericbinaryoperator |
1391 | | // 1-2, 6. N/A. |
1392 | | |
1393 | | // 3. Let lnum be ? ToNumeric(lval). |
1394 | 0 | auto lhs_numeric = TRY(lhs.to_numeric(vm)); |
1395 | | |
1396 | | // 4. Let rnum be ? ToNumeric(rval). |
1397 | 0 | auto rhs_numeric = TRY(rhs.to_numeric(vm)); |
1398 | | |
1399 | | // 7. Let operation be the abstract operation associated with opText and Type(lnum) in the following table: |
1400 | | // [...] |
1401 | | // 8. Return operation(lnum, rnum). |
1402 | 0 | if (both_number(lhs_numeric, rhs_numeric)) { |
1403 | | // 6.1.6.1.19 Number::bitwiseOR ( x, y ), https://tc39.es/ecma262/#sec-numeric-types-number-bitwiseOR |
1404 | | // 1. Return NumberBitwiseOp(|, x, y). |
1405 | 0 | if (!lhs_numeric.is_finite_number() && !rhs_numeric.is_finite_number()) |
1406 | 0 | return Value(0); |
1407 | 0 | if (!lhs_numeric.is_finite_number()) |
1408 | 0 | return rhs_numeric; |
1409 | 0 | if (!rhs_numeric.is_finite_number()) |
1410 | 0 | return lhs_numeric; |
1411 | 0 | return Value(TRY(lhs_numeric.to_i32(vm)) | TRY(rhs_numeric.to_i32(vm))); |
1412 | 0 | } |
1413 | 0 | if (both_bigint(lhs_numeric, rhs_numeric)) { |
1414 | | // 6.1.6.2.20 BigInt::bitwiseOR ( x, y ) |
1415 | | // 1. Return BigIntBitwiseOp(|, x, y). |
1416 | 0 | return BigInt::create(vm, lhs_numeric.as_bigint().big_integer().bitwise_or(rhs_numeric.as_bigint().big_integer())); |
1417 | 0 | } |
1418 | | |
1419 | | // 5. If Type(lnum) is different from Type(rnum), throw a TypeError exception. |
1420 | 0 | return vm.throw_completion<TypeError>(ErrorType::BigIntBadOperatorOtherType, "bitwise OR"); |
1421 | 0 | } |
1422 | | |
1423 | | // 13.12 Binary Bitwise Operators, https://tc39.es/ecma262/#sec-binary-bitwise-operators |
1424 | | // BitwiseXORExpression : BitwiseXORExpression ^ BitwiseANDExpression |
1425 | | ThrowCompletionOr<Value> bitwise_xor(VM& vm, Value lhs, Value rhs) |
1426 | 0 | { |
1427 | | // OPTIMIZATION: Fast path when both values are Int32. |
1428 | 0 | if (lhs.is_int32() && rhs.is_int32()) |
1429 | 0 | return Value(lhs.as_i32() ^ rhs.as_i32()); |
1430 | | |
1431 | | // 13.15.3 ApplyStringOrNumericBinaryOperator ( lval, opText, rval ), https://tc39.es/ecma262/#sec-applystringornumericbinaryoperator |
1432 | | // 1-2, 6. N/A. |
1433 | | |
1434 | | // 3. Let lnum be ? ToNumeric(lval). |
1435 | 0 | auto lhs_numeric = TRY(lhs.to_numeric(vm)); |
1436 | | |
1437 | | // 4. Let rnum be ? ToNumeric(rval). |
1438 | 0 | auto rhs_numeric = TRY(rhs.to_numeric(vm)); |
1439 | | |
1440 | | // 7. Let operation be the abstract operation associated with opText and Type(lnum) in the following table: |
1441 | | // [...] |
1442 | | // 8. Return operation(lnum, rnum). |
1443 | 0 | if (both_number(lhs_numeric, rhs_numeric)) { |
1444 | | // 6.1.6.1.18 Number::bitwiseXOR ( x, y ), https://tc39.es/ecma262/#sec-numeric-types-number-bitwiseXOR |
1445 | | // 1. Return NumberBitwiseOp(^, x, y). |
1446 | 0 | if (!lhs_numeric.is_finite_number() && !rhs_numeric.is_finite_number()) |
1447 | 0 | return Value(0); |
1448 | 0 | if (!lhs_numeric.is_finite_number()) |
1449 | 0 | return rhs_numeric; |
1450 | 0 | if (!rhs_numeric.is_finite_number()) |
1451 | 0 | return lhs_numeric; |
1452 | 0 | return Value(TRY(lhs_numeric.to_i32(vm)) ^ TRY(rhs_numeric.to_i32(vm))); |
1453 | 0 | } |
1454 | 0 | if (both_bigint(lhs_numeric, rhs_numeric)) { |
1455 | | // 6.1.6.2.19 BigInt::bitwiseXOR ( x, y ), https://tc39.es/ecma262/#sec-numeric-types-bigint-bitwiseXOR |
1456 | | // 1. Return BigIntBitwiseOp(^, x, y). |
1457 | 0 | return BigInt::create(vm, lhs_numeric.as_bigint().big_integer().bitwise_xor(rhs_numeric.as_bigint().big_integer())); |
1458 | 0 | } |
1459 | | |
1460 | | // 5. If Type(lnum) is different from Type(rnum), throw a TypeError exception. |
1461 | 0 | return vm.throw_completion<TypeError>(ErrorType::BigIntBadOperatorOtherType, "bitwise XOR"); |
1462 | 0 | } |
1463 | | |
1464 | | // 13.5.6 Bitwise NOT Operator ( ~ ), https://tc39.es/ecma262/#sec-bitwise-not-operator |
1465 | | // UnaryExpression : ~ UnaryExpression |
1466 | | ThrowCompletionOr<Value> bitwise_not(VM& vm, Value lhs) |
1467 | 0 | { |
1468 | | // 1. Let expr be ? Evaluation of UnaryExpression. |
1469 | | // NOTE: This is handled in the AST or Bytecode interpreter. |
1470 | | |
1471 | | // 2. Let oldValue be ? ToNumeric(? GetValue(expr)). |
1472 | |
|
1473 | 0 | auto old_value = TRY(lhs.to_numeric(vm)); |
1474 | | |
1475 | | // 3. If oldValue is a Number, then |
1476 | 0 | if (old_value.is_number()) { |
1477 | | // a. Return Number::bitwiseNOT(oldValue). |
1478 | | |
1479 | | // 6.1.6.1.2 Number::bitwiseNOT ( x ), https://tc39.es/ecma262/#sec-numeric-types-number-bitwiseNOT |
1480 | | // 1. Let oldValue be ! ToInt32(x). |
1481 | | // 2. Return the result of applying bitwise complement to oldValue. The mathematical value of the result is |
1482 | | // exactly representable as a 32-bit two's complement bit string. |
1483 | 0 | return Value(~TRY(old_value.to_i32(vm))); |
1484 | 0 | } |
1485 | | |
1486 | | // 4. Else, |
1487 | | // a. Assert: oldValue is a BigInt. |
1488 | 0 | VERIFY(old_value.is_bigint()); |
1489 | | |
1490 | | // b. Return BigInt::bitwiseNOT(oldValue). |
1491 | | |
1492 | | // 6.1.6.2.2 BigInt::bitwiseNOT ( x ), https://tc39.es/ecma262/#sec-numeric-types-bigint-bitwiseNOT |
1493 | | // 1. Return -x - 1ℤ. |
1494 | 0 | return BigInt::create(vm, old_value.as_bigint().big_integer().bitwise_not()); |
1495 | 0 | } |
1496 | | |
1497 | | // 13.5.4 Unary + Operator, https://tc39.es/ecma262/#sec-unary-plus-operator |
1498 | | // UnaryExpression : + UnaryExpression |
1499 | | ThrowCompletionOr<Value> unary_plus(VM& vm, Value lhs) |
1500 | 0 | { |
1501 | | // 1. Let expr be ? Evaluation of UnaryExpression. |
1502 | | // NOTE: This is handled in the AST or Bytecode interpreter. |
1503 | | |
1504 | | // 2. Return ? ToNumber(? GetValue(expr)). |
1505 | 0 | return TRY(lhs.to_number(vm)); |
1506 | 0 | } |
1507 | | |
1508 | | // 13.5.5 Unary - Operator, https://tc39.es/ecma262/#sec-unary-minus-operator |
1509 | | // UnaryExpression : - UnaryExpression |
1510 | | ThrowCompletionOr<Value> unary_minus(VM& vm, Value lhs) |
1511 | 0 | { |
1512 | | // 1. Let expr be ? Evaluation of UnaryExpression. |
1513 | | // NOTE: This is handled in the AST or Bytecode interpreter. |
1514 | | |
1515 | | // 2. Let oldValue be ? ToNumeric(? GetValue(expr)). |
1516 | 0 | auto old_value = TRY(lhs.to_numeric(vm)); |
1517 | | |
1518 | | // 3. If oldValue is a Number, then |
1519 | 0 | if (old_value.is_number()) { |
1520 | | // a. Return Number::unaryMinus(oldValue). |
1521 | | |
1522 | | // 6.1.6.1.1 Number::unaryMinus ( x ), https://tc39.es/ecma262/#sec-numeric-types-number-unaryMinus |
1523 | | // 1. If x is NaN, return NaN. |
1524 | 0 | if (old_value.is_nan()) |
1525 | 0 | return js_nan(); |
1526 | | |
1527 | | // 2. Return the result of negating x; that is, compute a Number with the same magnitude but opposite sign. |
1528 | 0 | return Value(-old_value.as_double()); |
1529 | 0 | } |
1530 | | |
1531 | | // 4. Else, |
1532 | | // a. Assert: oldValue is a BigInt. |
1533 | 0 | VERIFY(old_value.is_bigint()); |
1534 | | |
1535 | | // b. Return BigInt::unaryMinus(oldValue). |
1536 | | |
1537 | | // 6.1.6.2.1 BigInt::unaryMinus ( x ), https://tc39.es/ecma262/#sec-numeric-types-bigint-unaryMinus |
1538 | | // 1. If x is 0ℤ, return 0ℤ. |
1539 | 0 | if (old_value.as_bigint().big_integer() == BIGINT_ZERO) |
1540 | 0 | return BigInt::create(vm, BIGINT_ZERO); |
1541 | | |
1542 | | // 2. Return the BigInt value that represents the negation of ℝ(x). |
1543 | 0 | auto big_integer_negated = old_value.as_bigint().big_integer(); |
1544 | 0 | big_integer_negated.negate(); |
1545 | 0 | return BigInt::create(vm, big_integer_negated); |
1546 | 0 | } |
1547 | | |
1548 | | // 13.9.1 The Left Shift Operator ( << ), https://tc39.es/ecma262/#sec-left-shift-operator |
1549 | | // ShiftExpression : ShiftExpression << AdditiveExpression |
1550 | | ThrowCompletionOr<Value> left_shift(VM& vm, Value lhs, Value rhs) |
1551 | 0 | { |
1552 | | // 13.15.3 ApplyStringOrNumericBinaryOperator ( lval, opText, rval ), https://tc39.es/ecma262/#sec-applystringornumericbinaryoperator |
1553 | | // 1-2, 6. N/A. |
1554 | | |
1555 | | // 3. Let lnum be ? ToNumeric(lval). |
1556 | 0 | auto lhs_numeric = TRY(lhs.to_numeric(vm)); |
1557 | | |
1558 | | // 4. Let rnum be ? ToNumeric(rval). |
1559 | 0 | auto rhs_numeric = TRY(rhs.to_numeric(vm)); |
1560 | | |
1561 | | // 7. Let operation be the abstract operation associated with opText and Type(lnum) in the following table: |
1562 | | // [...] |
1563 | | // 8. Return operation(lnum, rnum). |
1564 | 0 | if (both_number(lhs_numeric, rhs_numeric)) { |
1565 | | // 6.1.6.1.9 Number::leftShift ( x, y ), https://tc39.es/ecma262/#sec-numeric-types-number-leftShift |
1566 | | |
1567 | | // OPTIMIZATION: Handle infinite values according to the results returned by ToInt32/ToUint32. |
1568 | 0 | if (!lhs_numeric.is_finite_number()) |
1569 | 0 | return Value(0); |
1570 | 0 | if (!rhs_numeric.is_finite_number()) |
1571 | 0 | return lhs_numeric; |
1572 | | |
1573 | | // 1. Let lnum be ! ToInt32(x). |
1574 | 0 | auto lhs_i32 = MUST(lhs_numeric.to_i32(vm)); |
1575 | | |
1576 | | // 2. Let rnum be ! ToUint32(y). |
1577 | 0 | auto rhs_u32 = MUST(rhs_numeric.to_u32(vm)); |
1578 | | |
1579 | | // 3. Let shiftCount be ℝ(rnum) modulo 32. |
1580 | 0 | auto shift_count = rhs_u32 % 32; |
1581 | | |
1582 | | // 4. Return the result of left shifting lnum by shiftCount bits. The mathematical value of the result is |
1583 | | // exactly representable as a 32-bit two's complement bit string. |
1584 | 0 | return Value(lhs_i32 << shift_count); |
1585 | 0 | } |
1586 | 0 | if (both_bigint(lhs_numeric, rhs_numeric)) { |
1587 | | // 6.1.6.2.9 BigInt::leftShift ( x, y ), https://tc39.es/ecma262/#sec-numeric-types-bigint-leftShift |
1588 | 0 | auto multiplier_divisor = Crypto::SignedBigInteger { Crypto::NumberTheory::Power(Crypto::UnsignedBigInteger(2), rhs_numeric.as_bigint().big_integer().unsigned_value()) }; |
1589 | | |
1590 | | // 1. If y < 0ℤ, then |
1591 | 0 | if (rhs_numeric.as_bigint().big_integer().is_negative()) { |
1592 | | // a. Return the BigInt value that represents ℝ(x) / 2^-y, rounding down to the nearest integer, including for negative numbers. |
1593 | | // NOTE: Since y is negative we can just do ℝ(x) / 2^|y| |
1594 | 0 | auto const& big_integer = lhs_numeric.as_bigint().big_integer(); |
1595 | 0 | auto division_result = big_integer.divided_by(multiplier_divisor); |
1596 | | |
1597 | | // For positive initial values and no remainder just return quotient |
1598 | 0 | if (division_result.remainder.is_zero() || !big_integer.is_negative()) |
1599 | 0 | return BigInt::create(vm, division_result.quotient); |
1600 | | // For negative round "down" to the next negative number |
1601 | 0 | return BigInt::create(vm, division_result.quotient.minus(Crypto::SignedBigInteger { 1 })); |
1602 | 0 | } |
1603 | | // 2. Return the BigInt value that represents ℝ(x) × 2^y. |
1604 | 0 | return Value(BigInt::create(vm, lhs_numeric.as_bigint().big_integer().multiplied_by(multiplier_divisor))); |
1605 | 0 | } |
1606 | | |
1607 | | // 5. If Type(lnum) is different from Type(rnum), throw a TypeError exception. |
1608 | 0 | return vm.throw_completion<TypeError>(ErrorType::BigIntBadOperatorOtherType, "left-shift"); |
1609 | 0 | } |
1610 | | |
1611 | | // 13.9.2 The Signed Right Shift Operator ( >> ), https://tc39.es/ecma262/#sec-signed-right-shift-operator |
1612 | | // ShiftExpression : ShiftExpression >> AdditiveExpression |
1613 | | ThrowCompletionOr<Value> right_shift(VM& vm, Value lhs, Value rhs) |
1614 | 0 | { |
1615 | | // 13.15.3 ApplyStringOrNumericBinaryOperator ( lval, opText, rval ), https://tc39.es/ecma262/#sec-applystringornumericbinaryoperator |
1616 | | // 1-2, 6. N/A. |
1617 | | |
1618 | | // 3. Let lnum be ? ToNumeric(lval). |
1619 | 0 | auto lhs_numeric = TRY(lhs.to_numeric(vm)); |
1620 | | |
1621 | | // 4. Let rnum be ? ToNumeric(rval). |
1622 | 0 | auto rhs_numeric = TRY(rhs.to_numeric(vm)); |
1623 | | |
1624 | | // 7. Let operation be the abstract operation associated with opText and Type(lnum) in the following table: |
1625 | | // [...] |
1626 | | // 8. Return operation(lnum, rnum). |
1627 | 0 | if (both_number(lhs_numeric, rhs_numeric)) { |
1628 | | // 6.1.6.1.10 Number::signedRightShift ( x, y ), https://tc39.es/ecma262/#sec-numeric-types-number-signedRightShift |
1629 | | |
1630 | | // OPTIMIZATION: Handle infinite values according to the results returned by ToInt32/ToUint32. |
1631 | 0 | if (!lhs_numeric.is_finite_number()) |
1632 | 0 | return Value(0); |
1633 | 0 | if (!rhs_numeric.is_finite_number()) |
1634 | 0 | return lhs_numeric; |
1635 | | |
1636 | | // 1. Let lnum be ! ToInt32(x). |
1637 | 0 | auto lhs_i32 = MUST(lhs_numeric.to_i32(vm)); |
1638 | | |
1639 | | // 2. Let rnum be ! ToUint32(y). |
1640 | 0 | auto rhs_u32 = MUST(rhs_numeric.to_u32(vm)); |
1641 | | |
1642 | | // 3. Let shiftCount be ℝ(rnum) modulo 32. |
1643 | 0 | auto shift_count = rhs_u32 % 32; |
1644 | | |
1645 | | // 4. Return the result of performing a sign-extending right shift of lnum by shiftCount bits. |
1646 | | // The most significant bit is propagated. The mathematical value of the result is exactly representable |
1647 | | // as a 32-bit two's complement bit string. |
1648 | 0 | return Value(lhs_i32 >> shift_count); |
1649 | 0 | } |
1650 | 0 | if (both_bigint(lhs_numeric, rhs_numeric)) { |
1651 | | // 6.1.6.2.10 BigInt::signedRightShift ( x, y ), https://tc39.es/ecma262/#sec-numeric-types-bigint-signedRightShift |
1652 | | // 1. Return BigInt::leftShift(x, -y). |
1653 | 0 | auto rhs_negated = rhs_numeric.as_bigint().big_integer(); |
1654 | 0 | rhs_negated.negate(); |
1655 | 0 | return left_shift(vm, lhs, BigInt::create(vm, rhs_negated)); |
1656 | 0 | } |
1657 | | |
1658 | | // 5. If Type(lnum) is different from Type(rnum), throw a TypeError exception. |
1659 | 0 | return vm.throw_completion<TypeError>(ErrorType::BigIntBadOperatorOtherType, "right-shift"); |
1660 | 0 | } |
1661 | | |
1662 | | // 13.9.3 The Unsigned Right Shift Operator ( >>> ), https://tc39.es/ecma262/#sec-unsigned-right-shift-operator |
1663 | | // ShiftExpression : ShiftExpression >>> AdditiveExpression |
1664 | | ThrowCompletionOr<Value> unsigned_right_shift(VM& vm, Value lhs, Value rhs) |
1665 | 0 | { |
1666 | | // 13.15.3 ApplyStringOrNumericBinaryOperator ( lval, opText, rval ), https://tc39.es/ecma262/#sec-applystringornumericbinaryoperator |
1667 | | // 1-2, 5-6. N/A. |
1668 | | |
1669 | | // 3. Let lnum be ? ToNumeric(lval). |
1670 | 0 | auto lhs_numeric = TRY(lhs.to_numeric(vm)); |
1671 | | |
1672 | | // 4. Let rnum be ? ToNumeric(rval). |
1673 | 0 | auto rhs_numeric = TRY(rhs.to_numeric(vm)); |
1674 | | |
1675 | | // 7. Let operation be the abstract operation associated with opText and Type(lnum) in the following table: |
1676 | | // [...] |
1677 | | // 8. Return operation(lnum, rnum). |
1678 | 0 | if (both_number(lhs_numeric, rhs_numeric)) { |
1679 | | // 6.1.6.1.11 Number::unsignedRightShift ( x, y ), https://tc39.es/ecma262/#sec-numeric-types-number-unsignedRightShift |
1680 | | |
1681 | | // OPTIMIZATION: Handle infinite values according to the results returned by ToUint32. |
1682 | 0 | if (!lhs_numeric.is_finite_number()) |
1683 | 0 | return Value(0); |
1684 | 0 | if (!rhs_numeric.is_finite_number()) |
1685 | 0 | return lhs_numeric; |
1686 | | |
1687 | | // 1. Let lnum be ! ToUint32(x). |
1688 | 0 | auto lhs_u32 = MUST(lhs_numeric.to_u32(vm)); |
1689 | | |
1690 | | // 2. Let rnum be ! ToUint32(y). |
1691 | 0 | auto rhs_u32 = MUST(rhs_numeric.to_u32(vm)); |
1692 | | |
1693 | | // 3. Let shiftCount be ℝ(rnum) modulo 32. |
1694 | 0 | auto shift_count = rhs_u32 % 32; |
1695 | | |
1696 | | // 4. Return the result of performing a zero-filling right shift of lnum by shiftCount bits. |
1697 | | // Vacated bits are filled with zero. The mathematical value of the result is exactly representable |
1698 | | // as a 32-bit unsigned bit string. |
1699 | 0 | return Value(lhs_u32 >> shift_count); |
1700 | 0 | } |
1701 | | |
1702 | | // 6. If lnum is a BigInt, then |
1703 | | // d. If opText is >>>, return ? BigInt::unsignedRightShift(lnum, rnum). |
1704 | | |
1705 | | // 6.1.6.2.11 BigInt::unsignedRightShift ( x, y ), https://tc39.es/ecma262/#sec-numeric-types-bigint-unsignedRightShift |
1706 | | // 1. Throw a TypeError exception. |
1707 | 0 | return vm.throw_completion<TypeError>(ErrorType::BigIntBadOperator, "unsigned right-shift"); |
1708 | 0 | } |
1709 | | |
1710 | | // 13.8.1 The Addition Operator ( + ), https://tc39.es/ecma262/#sec-addition-operator-plus |
1711 | | // AdditiveExpression : AdditiveExpression + MultiplicativeExpression |
1712 | | ThrowCompletionOr<Value> add(VM& vm, Value lhs, Value rhs) |
1713 | 0 | { |
1714 | | // 13.15.3 ApplyStringOrNumericBinaryOperator ( lval, opText, rval ), https://tc39.es/ecma262/#sec-applystringornumericbinaryoperator |
1715 | | |
1716 | | // 1. If opText is +, then |
1717 | | |
1718 | | // OPTIMIZATION: If both values are i32 or double, we can do a direct addition without the type conversions below. |
1719 | 0 | if (both_number(lhs, rhs)) { |
1720 | 0 | if (lhs.is_int32() && rhs.is_int32()) { |
1721 | 0 | Checked<i32> result; |
1722 | 0 | result = MUST(lhs.to_i32(vm)); |
1723 | 0 | result += MUST(rhs.to_i32(vm)); |
1724 | 0 | if (!result.has_overflow()) |
1725 | 0 | return Value(result.value()); |
1726 | 0 | } |
1727 | 0 | return Value(lhs.as_double() + rhs.as_double()); |
1728 | 0 | } |
1729 | | |
1730 | | // a. Let lprim be ? ToPrimitive(lval). |
1731 | 0 | auto lhs_primitive = TRY(lhs.to_primitive(vm)); |
1732 | | |
1733 | | // b. Let rprim be ? ToPrimitive(rval). |
1734 | 0 | auto rhs_primitive = TRY(rhs.to_primitive(vm)); |
1735 | | |
1736 | | // c. If lprim is a String or rprim is a String, then |
1737 | 0 | if (lhs_primitive.is_string() || rhs_primitive.is_string()) { |
1738 | | // i. Let lstr be ? ToString(lprim). |
1739 | 0 | auto lhs_string = TRY(lhs_primitive.to_primitive_string(vm)); |
1740 | | |
1741 | | // ii. Let rstr be ? ToString(rprim). |
1742 | 0 | auto rhs_string = TRY(rhs_primitive.to_primitive_string(vm)); |
1743 | | |
1744 | | // iii. Return the string-concatenation of lstr and rstr. |
1745 | 0 | return PrimitiveString::create(vm, lhs_string, rhs_string); |
1746 | 0 | } |
1747 | | |
1748 | | // d. Set lval to lprim. |
1749 | | // e. Set rval to rprim. |
1750 | | |
1751 | | // 2. NOTE: At this point, it must be a numeric operation. |
1752 | | |
1753 | | // 3. Let lnum be ? ToNumeric(lval). |
1754 | 0 | auto lhs_numeric = TRY(lhs_primitive.to_numeric(vm)); |
1755 | | |
1756 | | // 4. Let rnum be ? ToNumeric(rval). |
1757 | 0 | auto rhs_numeric = TRY(rhs_primitive.to_numeric(vm)); |
1758 | | |
1759 | | // 6. N/A. |
1760 | | |
1761 | | // 7. Let operation be the abstract operation associated with opText and Type(lnum) in the following table: |
1762 | | // [...] |
1763 | | // 8. Return operation(lnum, rnum). |
1764 | 0 | if (both_number(lhs_numeric, rhs_numeric)) { |
1765 | | // 6.1.6.1.7 Number::add ( x, y ), https://tc39.es/ecma262/#sec-numeric-types-number-add |
1766 | 0 | auto x = lhs_numeric.as_double(); |
1767 | 0 | auto y = rhs_numeric.as_double(); |
1768 | 0 | return Value(x + y); |
1769 | 0 | } |
1770 | 0 | if (both_bigint(lhs_numeric, rhs_numeric)) { |
1771 | | // 6.1.6.2.7 BigInt::add ( x, y ), https://tc39.es/ecma262/#sec-numeric-types-bigint-add |
1772 | 0 | auto x = lhs_numeric.as_bigint().big_integer(); |
1773 | 0 | auto y = rhs_numeric.as_bigint().big_integer(); |
1774 | 0 | return BigInt::create(vm, x.plus(y)); |
1775 | 0 | } |
1776 | | |
1777 | | // 5. If Type(lnum) is different from Type(rnum), throw a TypeError exception. |
1778 | 0 | return vm.throw_completion<TypeError>(ErrorType::BigIntBadOperatorOtherType, "addition"); |
1779 | 0 | } |
1780 | | |
1781 | | // 13.8.2 The Subtraction Operator ( - ), https://tc39.es/ecma262/#sec-subtraction-operator-minus |
1782 | | // AdditiveExpression : AdditiveExpression - MultiplicativeExpression |
1783 | | ThrowCompletionOr<Value> sub(VM& vm, Value lhs, Value rhs) |
1784 | 0 | { |
1785 | | // 13.15.3 ApplyStringOrNumericBinaryOperator ( lval, opText, rval ), https://tc39.es/ecma262/#sec-applystringornumericbinaryoperator |
1786 | | // 1-2, 6. N/A. |
1787 | | |
1788 | | // 3. Let lnum be ? ToNumeric(lval). |
1789 | 0 | auto lhs_numeric = TRY(lhs.to_numeric(vm)); |
1790 | | |
1791 | | // 4. Let rnum be ? ToNumeric(rval). |
1792 | 0 | auto rhs_numeric = TRY(rhs.to_numeric(vm)); |
1793 | | |
1794 | | // 7. Let operation be the abstract operation associated with opText and Type(lnum) in the following table: |
1795 | | // [...] |
1796 | | // 8. Return operation(lnum, rnum). |
1797 | 0 | if (both_number(lhs_numeric, rhs_numeric)) { |
1798 | | // 6.1.6.1.8 Number::subtract ( x, y ), https://tc39.es/ecma262/#sec-numeric-types-number-subtract |
1799 | 0 | auto x = lhs_numeric.as_double(); |
1800 | 0 | auto y = rhs_numeric.as_double(); |
1801 | | // 1. Return Number::add(x, Number::unaryMinus(y)). |
1802 | 0 | return Value(x - y); |
1803 | 0 | } |
1804 | 0 | if (both_bigint(lhs_numeric, rhs_numeric)) { |
1805 | | // 6.1.6.2.8 BigInt::subtract ( x, y ), https://tc39.es/ecma262/#sec-numeric-types-bigint-subtract |
1806 | 0 | auto x = lhs_numeric.as_bigint().big_integer(); |
1807 | 0 | auto y = rhs_numeric.as_bigint().big_integer(); |
1808 | | // 1. Return the BigInt value that represents the difference x minus y. |
1809 | 0 | return BigInt::create(vm, x.minus(y)); |
1810 | 0 | } |
1811 | | |
1812 | | // 5. If Type(lnum) is different from Type(rnum), throw a TypeError exception. |
1813 | 0 | return vm.throw_completion<TypeError>(ErrorType::BigIntBadOperatorOtherType, "subtraction"); |
1814 | 0 | } |
1815 | | |
1816 | | // 13.7 Multiplicative Operators, https://tc39.es/ecma262/#sec-multiplicative-operators |
1817 | | // MultiplicativeExpression : MultiplicativeExpression MultiplicativeOperator ExponentiationExpression |
1818 | | ThrowCompletionOr<Value> mul(VM& vm, Value lhs, Value rhs) |
1819 | 0 | { |
1820 | | // OPTIMIZATION: Fast path for multiplication of two Int32 values. |
1821 | 0 | if (lhs.is_int32() && rhs.is_int32()) { |
1822 | 0 | Checked<i32> result = lhs.as_i32(); |
1823 | 0 | result *= rhs.as_i32(); |
1824 | 0 | if (!result.has_overflow()) |
1825 | 0 | return result.value(); |
1826 | 0 | } |
1827 | | |
1828 | | // 13.15.3 ApplyStringOrNumericBinaryOperator ( lval, opText, rval ), https://tc39.es/ecma262/#sec-applystringornumericbinaryoperator |
1829 | | // 1-2, 6. N/A. |
1830 | | |
1831 | | // 3. Let lnum be ? ToNumeric(lval). |
1832 | 0 | auto lhs_numeric = TRY(lhs.to_numeric(vm)); |
1833 | | |
1834 | | // 4. Let rnum be ? ToNumeric(rval). |
1835 | 0 | auto rhs_numeric = TRY(rhs.to_numeric(vm)); |
1836 | | |
1837 | | // 7. Let operation be the abstract operation associated with opText and Type(lnum) in the following table: |
1838 | | // [...] |
1839 | | // 8. Return operation(lnum, rnum). |
1840 | 0 | if (both_number(lhs_numeric, rhs_numeric)) { |
1841 | | // 6.1.6.1.4 Number::multiply ( x, y ), https://tc39.es/ecma262/#sec-numeric-types-number-multiply |
1842 | 0 | auto x = lhs_numeric.as_double(); |
1843 | 0 | auto y = rhs_numeric.as_double(); |
1844 | 0 | return Value(x * y); |
1845 | 0 | } |
1846 | 0 | if (both_bigint(lhs_numeric, rhs_numeric)) { |
1847 | | // 6.1.6.2.4 BigInt::multiply ( x, y ), https://tc39.es/ecma262/#sec-numeric-types-bigint-multiply |
1848 | 0 | auto x = lhs_numeric.as_bigint().big_integer(); |
1849 | 0 | auto y = rhs_numeric.as_bigint().big_integer(); |
1850 | | // 1. Return the BigInt value that represents the product of x and y. |
1851 | 0 | return BigInt::create(vm, x.multiplied_by(y)); |
1852 | 0 | } |
1853 | | |
1854 | | // 5. If Type(lnum) is different from Type(rnum), throw a TypeError exception. |
1855 | 0 | return vm.throw_completion<TypeError>(ErrorType::BigIntBadOperatorOtherType, "multiplication"); |
1856 | 0 | } |
1857 | | |
1858 | | // 13.7 Multiplicative Operators, https://tc39.es/ecma262/#sec-multiplicative-operators |
1859 | | // MultiplicativeExpression : MultiplicativeExpression MultiplicativeOperator ExponentiationExpression |
1860 | | ThrowCompletionOr<Value> div(VM& vm, Value lhs, Value rhs) |
1861 | 0 | { |
1862 | | // 13.15.3 ApplyStringOrNumericBinaryOperator ( lval, opText, rval ), https://tc39.es/ecma262/#sec-applystringornumericbinaryoperator |
1863 | | // 1-2, 6. N/A. |
1864 | | |
1865 | | // 3. Let lnum be ? ToNumeric(lval). |
1866 | 0 | auto lhs_numeric = TRY(lhs.to_numeric(vm)); |
1867 | | |
1868 | | // 4. Let rnum be ? ToNumeric(rval). |
1869 | 0 | auto rhs_numeric = TRY(rhs.to_numeric(vm)); |
1870 | | |
1871 | | // 7. Let operation be the abstract operation associated with opText and Type(lnum) in the following table: |
1872 | | // [...] |
1873 | | // 8. Return operation(lnum, rnum). |
1874 | 0 | if (both_number(lhs_numeric, rhs_numeric)) { |
1875 | | // 6.1.6.1.5 Number::divide ( x, y ), https://tc39.es/ecma262/#sec-numeric-types-number-divide |
1876 | 0 | return Value(lhs_numeric.as_double() / rhs_numeric.as_double()); |
1877 | 0 | } |
1878 | 0 | if (both_bigint(lhs_numeric, rhs_numeric)) { |
1879 | | // 6.1.6.2.5 BigInt::divide ( x, y ), https://tc39.es/ecma262/#sec-numeric-types-bigint-divide |
1880 | 0 | auto x = lhs_numeric.as_bigint().big_integer(); |
1881 | 0 | auto y = rhs_numeric.as_bigint().big_integer(); |
1882 | | // 1. If y is 0ℤ, throw a RangeError exception. |
1883 | 0 | if (y == BIGINT_ZERO) |
1884 | 0 | return vm.throw_completion<RangeError>(ErrorType::DivisionByZero); |
1885 | | // 2. Let quotient be ℝ(x) / ℝ(y). |
1886 | | // 3. Return the BigInt value that represents quotient rounded towards 0 to the next integer value. |
1887 | 0 | return BigInt::create(vm, x.divided_by(y).quotient); |
1888 | 0 | } |
1889 | | |
1890 | | // 5. If Type(lnum) is different from Type(rnum), throw a TypeError exception. |
1891 | 0 | return vm.throw_completion<TypeError>(ErrorType::BigIntBadOperatorOtherType, "division"); |
1892 | 0 | } |
1893 | | |
1894 | | // 13.7 Multiplicative Operators, https://tc39.es/ecma262/#sec-multiplicative-operators |
1895 | | // MultiplicativeExpression : MultiplicativeExpression MultiplicativeOperator ExponentiationExpression |
1896 | | ThrowCompletionOr<Value> mod(VM& vm, Value lhs, Value rhs) |
1897 | 0 | { |
1898 | | // 13.15.3 ApplyStringOrNumericBinaryOperator ( lval, opText, rval ), https://tc39.es/ecma262/#sec-applystringornumericbinaryoperator |
1899 | | // 1-2, 6. N/A. |
1900 | | |
1901 | | // 3. Let lnum be ? ToNumeric(lval). |
1902 | 0 | auto lhs_numeric = TRY(lhs.to_numeric(vm)); |
1903 | | |
1904 | | // 4. Let rnum be ? ToNumeric(rval). |
1905 | 0 | auto rhs_numeric = TRY(rhs.to_numeric(vm)); |
1906 | | |
1907 | | // 7. Let operation be the abstract operation associated with opText and Type(lnum) in the following table: |
1908 | | // [...] |
1909 | | // 8. Return operation(lnum, rnum). |
1910 | 0 | if (both_number(lhs_numeric, rhs_numeric)) { |
1911 | | // 6.1.6.1.6 Number::remainder ( n, d ), https://tc39.es/ecma262/#sec-numeric-types-number-remainder |
1912 | | // The ECMA specification is describing the mathematical definition of modulus |
1913 | | // implemented by fmod. |
1914 | 0 | auto n = lhs_numeric.as_double(); |
1915 | 0 | auto d = rhs_numeric.as_double(); |
1916 | 0 | return Value(fmod(n, d)); |
1917 | 0 | } |
1918 | 0 | if (both_bigint(lhs_numeric, rhs_numeric)) { |
1919 | | // 6.1.6.2.6 BigInt::remainder ( n, d ), https://tc39.es/ecma262/#sec-numeric-types-bigint-remainder |
1920 | 0 | auto n = lhs_numeric.as_bigint().big_integer(); |
1921 | 0 | auto d = rhs_numeric.as_bigint().big_integer(); |
1922 | | // 1. If d is 0ℤ, throw a RangeError exception. |
1923 | 0 | if (d == BIGINT_ZERO) |
1924 | 0 | return vm.throw_completion<RangeError>(ErrorType::DivisionByZero); |
1925 | | // 2. If n is 0ℤ, return 0ℤ. |
1926 | | // 3. Let quotient be ℝ(n) / ℝ(d). |
1927 | | // 4. Let q be the BigInt whose sign is the sign of quotient and whose magnitude is floor(abs(quotient)). |
1928 | | // 5. Return n - (d × q). |
1929 | 0 | return BigInt::create(vm, n.divided_by(d).remainder); |
1930 | 0 | } |
1931 | | |
1932 | | // 5. If Type(lnum) is different from Type(rnum), throw a TypeError exception. |
1933 | 0 | return vm.throw_completion<TypeError>(ErrorType::BigIntBadOperatorOtherType, "modulo"); |
1934 | 0 | } |
1935 | | |
1936 | | // 6.1.6.1.3 Number::exponentiate ( base, exponent ), https://tc39.es/ecma262/#sec-numeric-types-number-exponentiate |
1937 | | static Value exp_double(Value base, Value exponent) |
1938 | 0 | { |
1939 | 0 | VERIFY(both_number(base, exponent)); |
1940 | | |
1941 | | // 1. If exponent is NaN, return NaN. |
1942 | 0 | if (exponent.is_nan()) |
1943 | 0 | return js_nan(); |
1944 | | |
1945 | | // 2. If exponent is +0𝔽 or exponent is -0𝔽, return 1𝔽. |
1946 | 0 | if (exponent.is_positive_zero() || exponent.is_negative_zero()) |
1947 | 0 | return Value(1); |
1948 | | |
1949 | | // 3. If base is NaN, return NaN. |
1950 | 0 | if (base.is_nan()) |
1951 | 0 | return js_nan(); |
1952 | | |
1953 | | // 4. If base is +∞𝔽, then |
1954 | 0 | if (base.is_positive_infinity()) { |
1955 | | // a. If exponent > +0𝔽, return +∞𝔽. Otherwise, return +0𝔽. |
1956 | 0 | return exponent.as_double() > 0 ? js_infinity() : Value(0); |
1957 | 0 | } |
1958 | | |
1959 | | // 5. If base is -∞𝔽, then |
1960 | 0 | if (base.is_negative_infinity()) { |
1961 | 0 | auto is_odd_integral_number = exponent.is_integral_number() && (fmod(exponent.as_double(), 2.0) != 0); |
1962 | | |
1963 | | // a. If exponent > +0𝔽, then |
1964 | 0 | if (exponent.as_double() > 0) { |
1965 | | // i. If exponent is an odd integral Number, return -∞𝔽. Otherwise, return +∞𝔽. |
1966 | 0 | return is_odd_integral_number ? js_negative_infinity() : js_infinity(); |
1967 | 0 | } |
1968 | | // b. Else, |
1969 | 0 | else { |
1970 | | // i. If exponent is an odd integral Number, return -0𝔽. Otherwise, return +0𝔽. |
1971 | 0 | return is_odd_integral_number ? Value(-0.0) : Value(0); |
1972 | 0 | } |
1973 | 0 | } |
1974 | | |
1975 | | // 6. If base is +0𝔽, then |
1976 | 0 | if (base.is_positive_zero()) { |
1977 | | // a. If exponent > +0𝔽, return +0𝔽. Otherwise, return +∞𝔽. |
1978 | 0 | return exponent.as_double() > 0 ? Value(0) : js_infinity(); |
1979 | 0 | } |
1980 | | |
1981 | | // 7. If base is -0𝔽, then |
1982 | 0 | if (base.is_negative_zero()) { |
1983 | 0 | auto is_odd_integral_number = exponent.is_integral_number() && (fmod(exponent.as_double(), 2.0) != 0); |
1984 | | |
1985 | | // a. If exponent > +0𝔽, then |
1986 | 0 | if (exponent.as_double() > 0) { |
1987 | | // i. If exponent is an odd integral Number, return -0𝔽. Otherwise, return +0𝔽. |
1988 | 0 | return is_odd_integral_number ? Value(-0.0) : Value(0); |
1989 | 0 | } |
1990 | | // b. Else, |
1991 | 0 | else { |
1992 | | // i. If exponent is an odd integral Number, return -∞𝔽. Otherwise, return +∞𝔽. |
1993 | 0 | return is_odd_integral_number ? js_negative_infinity() : js_infinity(); |
1994 | 0 | } |
1995 | 0 | } |
1996 | | |
1997 | | // 8. Assert: base is finite and is neither +0𝔽 nor -0𝔽. |
1998 | 0 | VERIFY(base.is_finite_number() && !base.is_positive_zero() && !base.is_negative_zero()); |
1999 | | |
2000 | | // 9. If exponent is +∞𝔽, then |
2001 | 0 | if (exponent.is_positive_infinity()) { |
2002 | 0 | auto absolute_base = fabs(base.as_double()); |
2003 | | |
2004 | | // a. If abs(ℝ(base)) > 1, return +∞𝔽. |
2005 | 0 | if (absolute_base > 1) |
2006 | 0 | return js_infinity(); |
2007 | | // b. If abs(ℝ(base)) is 1, return NaN. |
2008 | 0 | else if (absolute_base == 1) |
2009 | 0 | return js_nan(); |
2010 | | // c. If abs(ℝ(base)) < 1, return +0𝔽. |
2011 | 0 | else if (absolute_base < 1) |
2012 | 0 | return Value(0); |
2013 | 0 | } |
2014 | | |
2015 | | // 10. If exponent is -∞𝔽, then |
2016 | 0 | if (exponent.is_negative_infinity()) { |
2017 | 0 | auto absolute_base = fabs(base.as_double()); |
2018 | | |
2019 | | // a. If abs(ℝ(base)) > 1, return +0𝔽. |
2020 | 0 | if (absolute_base > 1) |
2021 | 0 | return Value(0); |
2022 | | // b. If abs(ℝ(base)) is 1, return NaN. |
2023 | 0 | else if (absolute_base == 1) |
2024 | 0 | return js_nan(); |
2025 | | // a. If abs(ℝ(base)) > 1, return +0𝔽. |
2026 | 0 | else if (absolute_base < 1) |
2027 | 0 | return js_infinity(); |
2028 | 0 | } |
2029 | | |
2030 | | // 11. Assert: exponent is finite and is neither +0𝔽 nor -0𝔽. |
2031 | 0 | VERIFY(exponent.is_finite_number() && !exponent.is_positive_zero() && !exponent.is_negative_zero()); |
2032 | | |
2033 | | // 12. If base < -0𝔽 and exponent is not an integral Number, return NaN. |
2034 | 0 | if (base.as_double() < 0 && !exponent.is_integral_number()) |
2035 | 0 | return js_nan(); |
2036 | | |
2037 | | // 13. Return an implementation-approximated Number value representing the result of raising ℝ(base) to the ℝ(exponent) power. |
2038 | 0 | return Value(::pow(base.as_double(), exponent.as_double())); |
2039 | 0 | } |
2040 | | |
2041 | | // 13.6 Exponentiation Operator, https://tc39.es/ecma262/#sec-exp-operator |
2042 | | // ExponentiationExpression : UpdateExpression ** ExponentiationExpression |
2043 | | ThrowCompletionOr<Value> exp(VM& vm, Value lhs, Value rhs) |
2044 | 0 | { |
2045 | | // 3. Let lnum be ? ToNumeric(lval). |
2046 | 0 | auto lhs_numeric = TRY(lhs.to_numeric(vm)); |
2047 | | |
2048 | | // 4. Let rnum be ? ToNumeric(rval). |
2049 | 0 | auto rhs_numeric = TRY(rhs.to_numeric(vm)); |
2050 | | |
2051 | | // 7. Let operation be the abstract operation associated with opText and Type(lnum) in the following table: |
2052 | | // [...] |
2053 | | // 8. Return operation(lnum, rnum). |
2054 | 0 | if (both_number(lhs_numeric, rhs_numeric)) { |
2055 | 0 | return exp_double(lhs_numeric, rhs_numeric); |
2056 | 0 | } |
2057 | 0 | if (both_bigint(lhs_numeric, rhs_numeric)) { |
2058 | | // 6.1.6.2.3 BigInt::exponentiate ( base, exponent ), https://tc39.es/ecma262/#sec-numeric-types-bigint-exponentiate |
2059 | 0 | auto base = lhs_numeric.as_bigint().big_integer(); |
2060 | 0 | auto exponent = rhs_numeric.as_bigint().big_integer(); |
2061 | | // 1. If exponent < 0ℤ, throw a RangeError exception. |
2062 | 0 | if (exponent.is_negative()) |
2063 | 0 | return vm.throw_completion<RangeError>(ErrorType::NegativeExponent); |
2064 | | // 2. If base is 0ℤ and exponent is 0ℤ, return 1ℤ. |
2065 | | // 3. Return the BigInt value that represents ℝ(base) raised to the power ℝ(exponent). |
2066 | 0 | return BigInt::create(vm, Crypto::NumberTheory::Power(base, exponent)); |
2067 | 0 | } |
2068 | 0 | return vm.throw_completion<TypeError>(ErrorType::BigIntBadOperatorOtherType, "exponentiation"); |
2069 | 0 | } |
2070 | | |
2071 | | ThrowCompletionOr<Value> in(VM& vm, Value lhs, Value rhs) |
2072 | 0 | { |
2073 | 0 | if (!rhs.is_object()) |
2074 | 0 | return vm.throw_completion<TypeError>(ErrorType::InOperatorWithObject); |
2075 | 0 | auto lhs_property_key = TRY(lhs.to_property_key(vm)); |
2076 | 0 | return Value(TRY(rhs.as_object().has_property(lhs_property_key))); |
2077 | 0 | } |
2078 | | |
2079 | | // 13.10.2 InstanceofOperator ( V, target ), https://tc39.es/ecma262/#sec-instanceofoperator |
2080 | | ThrowCompletionOr<Value> instance_of(VM& vm, Value value, Value target) |
2081 | 0 | { |
2082 | | // 1. If target is not an Object, throw a TypeError exception. |
2083 | 0 | if (!target.is_object()) |
2084 | 0 | return vm.throw_completion<TypeError>(ErrorType::NotAnObject, target.to_string_without_side_effects()); |
2085 | | |
2086 | | // 2. Let instOfHandler be ? GetMethod(target, @@hasInstance). |
2087 | 0 | auto instance_of_handler = TRY(target.get_method(vm, vm.well_known_symbol_has_instance())); |
2088 | | |
2089 | | // 3. If instOfHandler is not undefined, then |
2090 | 0 | if (instance_of_handler) { |
2091 | | // a. Return ToBoolean(? Call(instOfHandler, target, « V »)). |
2092 | 0 | return Value(TRY(call(vm, *instance_of_handler, target, value)).to_boolean()); |
2093 | 0 | } |
2094 | | |
2095 | | // 4. If IsCallable(target) is false, throw a TypeError exception. |
2096 | 0 | if (!target.is_function()) |
2097 | 0 | return vm.throw_completion<TypeError>(ErrorType::NotAFunction, target.to_string_without_side_effects()); |
2098 | | |
2099 | | // 5. Return ? OrdinaryHasInstance(target, V). |
2100 | 0 | return ordinary_has_instance(vm, target, value); |
2101 | 0 | } |
2102 | | |
2103 | | // 7.3.22 OrdinaryHasInstance ( C, O ), https://tc39.es/ecma262/#sec-ordinaryhasinstance |
2104 | | ThrowCompletionOr<Value> ordinary_has_instance(VM& vm, Value lhs, Value rhs) |
2105 | 0 | { |
2106 | | // 1. If IsCallable(C) is false, return false. |
2107 | 0 | if (!rhs.is_function()) |
2108 | 0 | return Value(false); |
2109 | | |
2110 | 0 | auto& rhs_function = rhs.as_function(); |
2111 | | |
2112 | | // 2. If C has a [[BoundTargetFunction]] internal slot, then |
2113 | 0 | if (is<BoundFunction>(rhs_function)) { |
2114 | 0 | auto const& bound_target = static_cast<BoundFunction const&>(rhs_function); |
2115 | | |
2116 | | // a. Let BC be C.[[BoundTargetFunction]]. |
2117 | | // b. Return ? InstanceofOperator(O, BC). |
2118 | 0 | return instance_of(vm, lhs, Value(&bound_target.bound_target_function())); |
2119 | 0 | } |
2120 | | |
2121 | | // 3. If O is not an Object, return false. |
2122 | 0 | if (!lhs.is_object()) |
2123 | 0 | return Value(false); |
2124 | | |
2125 | 0 | auto* lhs_object = &lhs.as_object(); |
2126 | | |
2127 | | // 4. Let P be ? Get(C, "prototype"). |
2128 | 0 | auto rhs_prototype = TRY(rhs_function.get(vm.names.prototype)); |
2129 | | |
2130 | | // 5. If P is not an Object, throw a TypeError exception. |
2131 | 0 | if (!rhs_prototype.is_object()) |
2132 | 0 | return vm.throw_completion<TypeError>(ErrorType::InstanceOfOperatorBadPrototype, rhs.to_string_without_side_effects()); |
2133 | | |
2134 | | // 6. Repeat, |
2135 | 0 | while (true) { |
2136 | | // a. Set O to ? O.[[GetPrototypeOf]](). |
2137 | 0 | lhs_object = TRY(lhs_object->internal_get_prototype_of()); |
2138 | | |
2139 | | // b. If O is null, return false. |
2140 | 0 | if (!lhs_object) |
2141 | 0 | return Value(false); |
2142 | | |
2143 | | // c. If SameValue(P, O) is true, return true. |
2144 | 0 | if (same_value(rhs_prototype, lhs_object)) |
2145 | 0 | return Value(true); |
2146 | 0 | } |
2147 | 0 | } |
2148 | | |
2149 | | // 7.2.10 SameValue ( x, y ), https://tc39.es/ecma262/#sec-samevalue |
2150 | | bool same_value(Value lhs, Value rhs) |
2151 | 0 | { |
2152 | | // 1. If Type(x) is different from Type(y), return false. |
2153 | 0 | if (!same_type_for_equality(lhs, rhs)) |
2154 | 0 | return false; |
2155 | | |
2156 | | // 2. If x is a Number, then |
2157 | 0 | if (lhs.is_number()) { |
2158 | | // a. Return Number::sameValue(x, y). |
2159 | | |
2160 | | // 6.1.6.1.14 Number::sameValue ( x, y ), https://tc39.es/ecma262/#sec-numeric-types-number-sameValue |
2161 | | // 1. If x is NaN and y is NaN, return true. |
2162 | 0 | if (lhs.is_nan() && rhs.is_nan()) |
2163 | 0 | return true; |
2164 | | // 2. If x is +0𝔽 and y is -0𝔽, return false. |
2165 | 0 | if (lhs.is_positive_zero() && rhs.is_negative_zero()) |
2166 | 0 | return false; |
2167 | | // 3. If x is -0𝔽 and y is +0𝔽, return false. |
2168 | 0 | if (lhs.is_negative_zero() && rhs.is_positive_zero()) |
2169 | 0 | return false; |
2170 | | // 4. If x is the same Number value as y, return true. |
2171 | | // 5. Return false. |
2172 | 0 | return lhs.as_double() == rhs.as_double(); |
2173 | 0 | } |
2174 | | |
2175 | | // 3. Return SameValueNonNumber(x, y). |
2176 | 0 | return same_value_non_number(lhs, rhs); |
2177 | 0 | } |
2178 | | |
2179 | | // 7.2.11 SameValueZero ( x, y ), https://tc39.es/ecma262/#sec-samevaluezero |
2180 | | bool same_value_zero(Value lhs, Value rhs) |
2181 | 0 | { |
2182 | | // 1. If Type(x) is different from Type(y), return false. |
2183 | 0 | if (!same_type_for_equality(lhs, rhs)) |
2184 | 0 | return false; |
2185 | | |
2186 | | // 2. If x is a Number, then |
2187 | 0 | if (lhs.is_number()) { |
2188 | | // a. Return Number::sameValueZero(x, y). |
2189 | 0 | if (lhs.is_nan() && rhs.is_nan()) |
2190 | 0 | return true; |
2191 | 0 | return lhs.as_double() == rhs.as_double(); |
2192 | 0 | } |
2193 | | |
2194 | | // 3. Return SameValueNonNumber(x, y). |
2195 | 0 | return same_value_non_number(lhs, rhs); |
2196 | 0 | } |
2197 | | |
2198 | | // 7.2.12 SameValueNonNumber ( x, y ), https://tc39.es/ecma262/#sec-samevaluenonnumeric |
2199 | | bool same_value_non_number(Value lhs, Value rhs) |
2200 | 0 | { |
2201 | | // 1. Assert: Type(x) is the same as Type(y). |
2202 | 0 | VERIFY(same_type_for_equality(lhs, rhs)); |
2203 | 0 | VERIFY(!lhs.is_number()); |
2204 | | |
2205 | | // 2. If x is a BigInt, then |
2206 | 0 | if (lhs.is_bigint()) { |
2207 | | // a. Return BigInt::equal(x, y). |
2208 | | |
2209 | | // 6.1.6.2.13 BigInt::equal ( x, y ), https://tc39.es/ecma262/#sec-numeric-types-bigint-equal |
2210 | | // 1. If ℝ(x) = ℝ(y), return true; otherwise return false. |
2211 | 0 | return lhs.as_bigint().big_integer() == rhs.as_bigint().big_integer(); |
2212 | 0 | } |
2213 | | |
2214 | | // 5. If x is a String, then |
2215 | 0 | if (lhs.is_string()) { |
2216 | | // a. If x and y are exactly the same sequence of code units (same length and same code units at corresponding indices), return true; otherwise, return false. |
2217 | 0 | return lhs.as_string().byte_string() == rhs.as_string().byte_string(); |
2218 | 0 | } |
2219 | | |
2220 | | // 3. If x is undefined, return true. |
2221 | | // 4. If x is null, return true. |
2222 | | // 6. If x is a Boolean, then |
2223 | | // a. If x and y are both true or both false, return true; otherwise, return false. |
2224 | | // 7. If x is a Symbol, then |
2225 | | // a. If x and y are both the same Symbol value, return true; otherwise, return false. |
2226 | | // 8. If x and y are the same Object value, return true. Otherwise, return false. |
2227 | | // NOTE: All the options above will have the exact same bit representation in Value, so we can directly compare the bits. |
2228 | 0 | return lhs.m_value.encoded == rhs.m_value.encoded; |
2229 | 0 | } |
2230 | | |
2231 | | // 7.2.15 IsStrictlyEqual ( x, y ), https://tc39.es/ecma262/#sec-isstrictlyequal |
2232 | | bool is_strictly_equal(Value lhs, Value rhs) |
2233 | 0 | { |
2234 | | // 1. If Type(x) is different from Type(y), return false. |
2235 | 0 | if (!same_type_for_equality(lhs, rhs)) |
2236 | 0 | return false; |
2237 | | |
2238 | | // 2. If x is a Number, then |
2239 | 0 | if (lhs.is_number()) { |
2240 | | // a. Return Number::equal(x, y). |
2241 | | |
2242 | | // 6.1.6.1.13 Number::equal ( x, y ), https://tc39.es/ecma262/#sec-numeric-types-number-equal |
2243 | | // 1. If x is NaN, return false. |
2244 | | // 2. If y is NaN, return false. |
2245 | 0 | if (lhs.is_nan() || rhs.is_nan()) |
2246 | 0 | return false; |
2247 | | // 3. If x is the same Number value as y, return true. |
2248 | | // 4. If x is +0𝔽 and y is -0𝔽, return true. |
2249 | | // 5. If x is -0𝔽 and y is +0𝔽, return true. |
2250 | 0 | if (lhs.as_double() == rhs.as_double()) |
2251 | 0 | return true; |
2252 | | // 6. Return false. |
2253 | 0 | return false; |
2254 | 0 | } |
2255 | | |
2256 | | // 3. Return SameValueNonNumber(x, y). |
2257 | 0 | return same_value_non_number(lhs, rhs); |
2258 | 0 | } |
2259 | | |
2260 | | // 7.2.14 IsLooselyEqual ( x, y ), https://tc39.es/ecma262/#sec-islooselyequal |
2261 | | ThrowCompletionOr<bool> is_loosely_equal(VM& vm, Value lhs, Value rhs) |
2262 | 0 | { |
2263 | | // 1. If Type(x) is the same as Type(y), then |
2264 | 0 | if (same_type_for_equality(lhs, rhs)) { |
2265 | | // a. Return IsStrictlyEqual(x, y). |
2266 | 0 | return is_strictly_equal(lhs, rhs); |
2267 | 0 | } |
2268 | | |
2269 | | // 2. If x is null and y is undefined, return true. |
2270 | | // 3. If x is undefined and y is null, return true. |
2271 | 0 | if (lhs.is_nullish() && rhs.is_nullish()) |
2272 | 0 | return true; |
2273 | | |
2274 | | // 4. NOTE: This step is replaced in section B.3.6.2. |
2275 | | // B.3.6.2 Changes to IsLooselyEqual, https://tc39.es/ecma262/#sec-IsHTMLDDA-internal-slot-aec |
2276 | | // 4. Perform the following steps: |
2277 | | // a. If Type(x) is Object and x has an [[IsHTMLDDA]] internal slot and y is either null or undefined, return true. |
2278 | 0 | if (lhs.is_object() && lhs.as_object().is_htmldda() && rhs.is_nullish()) |
2279 | 0 | return true; |
2280 | | |
2281 | | // b. If x is either null or undefined and Type(y) is Object and y has an [[IsHTMLDDA]] internal slot, return true. |
2282 | 0 | if (lhs.is_nullish() && rhs.is_object() && rhs.as_object().is_htmldda()) |
2283 | 0 | return true; |
2284 | | |
2285 | | // == End of B.3.6.2 == |
2286 | | |
2287 | | // 5. If Type(x) is Number and Type(y) is String, return ! IsLooselyEqual(x, ! ToNumber(y)). |
2288 | 0 | if (lhs.is_number() && rhs.is_string()) |
2289 | 0 | return is_loosely_equal(vm, lhs, MUST(rhs.to_number(vm))); |
2290 | | |
2291 | | // 6. If Type(x) is String and Type(y) is Number, return ! IsLooselyEqual(! ToNumber(x), y). |
2292 | 0 | if (lhs.is_string() && rhs.is_number()) |
2293 | 0 | return is_loosely_equal(vm, MUST(lhs.to_number(vm)), rhs); |
2294 | | |
2295 | | // 7. If Type(x) is BigInt and Type(y) is String, then |
2296 | 0 | if (lhs.is_bigint() && rhs.is_string()) { |
2297 | | // a. Let n be StringToBigInt(y). |
2298 | 0 | auto bigint = string_to_bigint(vm, rhs.as_string().byte_string()); |
2299 | | |
2300 | | // b. If n is undefined, return false. |
2301 | 0 | if (!bigint.has_value()) |
2302 | 0 | return false; |
2303 | | |
2304 | | // c. Return ! IsLooselyEqual(x, n). |
2305 | 0 | return is_loosely_equal(vm, lhs, *bigint); |
2306 | 0 | } |
2307 | | |
2308 | | // 8. If Type(x) is String and Type(y) is BigInt, return ! IsLooselyEqual(y, x). |
2309 | 0 | if (lhs.is_string() && rhs.is_bigint()) |
2310 | 0 | return is_loosely_equal(vm, rhs, lhs); |
2311 | | |
2312 | | // 9. If Type(x) is Boolean, return ! IsLooselyEqual(! ToNumber(x), y). |
2313 | 0 | if (lhs.is_boolean()) |
2314 | 0 | return is_loosely_equal(vm, MUST(lhs.to_number(vm)), rhs); |
2315 | | |
2316 | | // 10. If Type(y) is Boolean, return ! IsLooselyEqual(x, ! ToNumber(y)). |
2317 | 0 | if (rhs.is_boolean()) |
2318 | 0 | return is_loosely_equal(vm, lhs, MUST(rhs.to_number(vm))); |
2319 | | |
2320 | | // 11. If Type(x) is either String, Number, BigInt, or Symbol and Type(y) is Object, return ! IsLooselyEqual(x, ? ToPrimitive(y)). |
2321 | 0 | if ((lhs.is_string() || lhs.is_number() || lhs.is_bigint() || lhs.is_symbol()) && rhs.is_object()) { |
2322 | 0 | auto rhs_primitive = TRY(rhs.to_primitive(vm)); |
2323 | 0 | return is_loosely_equal(vm, lhs, rhs_primitive); |
2324 | 0 | } |
2325 | | |
2326 | | // 12. If Type(x) is Object and Type(y) is either String, Number, BigInt, or Symbol, return ! IsLooselyEqual(? ToPrimitive(x), y). |
2327 | 0 | if (lhs.is_object() && (rhs.is_string() || rhs.is_number() || rhs.is_bigint() || rhs.is_symbol())) { |
2328 | 0 | auto lhs_primitive = TRY(lhs.to_primitive(vm)); |
2329 | 0 | return is_loosely_equal(vm, lhs_primitive, rhs); |
2330 | 0 | } |
2331 | | |
2332 | | // 13. If Type(x) is BigInt and Type(y) is Number, or if Type(x) is Number and Type(y) is BigInt, then |
2333 | 0 | if ((lhs.is_bigint() && rhs.is_number()) || (lhs.is_number() && rhs.is_bigint())) { |
2334 | | // a. If x or y are any of NaN, +∞𝔽, or -∞𝔽, return false. |
2335 | 0 | if (lhs.is_nan() || lhs.is_infinity() || rhs.is_nan() || rhs.is_infinity()) |
2336 | 0 | return false; |
2337 | | |
2338 | | // b. If ℝ(x) = ℝ(y), return true; otherwise return false. |
2339 | 0 | if ((lhs.is_number() && !lhs.is_integral_number()) || (rhs.is_number() && !rhs.is_integral_number())) |
2340 | 0 | return false; |
2341 | | |
2342 | 0 | VERIFY(!lhs.is_nan() && !rhs.is_nan()); |
2343 | | |
2344 | 0 | auto& number_side = lhs.is_number() ? lhs : rhs; |
2345 | 0 | auto& bigint_side = lhs.is_number() ? rhs : lhs; |
2346 | |
|
2347 | 0 | return bigint_side.as_bigint().big_integer().compare_to_double(number_side.as_double()) == Crypto::UnsignedBigInteger::CompareResult::DoubleEqualsBigInt; |
2348 | 0 | } |
2349 | | |
2350 | | // 14. Return false. |
2351 | 0 | return false; |
2352 | 0 | } |
2353 | | |
2354 | | // 7.2.13 IsLessThan ( x, y, LeftFirst ), https://tc39.es/ecma262/#sec-islessthan |
2355 | | ThrowCompletionOr<TriState> is_less_than(VM& vm, Value lhs, Value rhs, bool left_first) |
2356 | 0 | { |
2357 | 0 | Value x_primitive; |
2358 | 0 | Value y_primitive; |
2359 | | |
2360 | | // 1. If the LeftFirst flag is true, then |
2361 | 0 | if (left_first) { |
2362 | | // a. Let px be ? ToPrimitive(x, number). |
2363 | 0 | x_primitive = TRY(lhs.to_primitive(vm, Value::PreferredType::Number)); |
2364 | | |
2365 | | // b. Let py be ? ToPrimitive(y, number). |
2366 | 0 | y_primitive = TRY(rhs.to_primitive(vm, Value::PreferredType::Number)); |
2367 | 0 | } else { |
2368 | | // a. NOTE: The order of evaluation needs to be reversed to preserve left to right evaluation. |
2369 | | |
2370 | | // b. Let py be ? ToPrimitive(y, number). |
2371 | 0 | y_primitive = TRY(lhs.to_primitive(vm, Value::PreferredType::Number)); |
2372 | | |
2373 | | // c. Let px be ? ToPrimitive(x, number). |
2374 | 0 | x_primitive = TRY(rhs.to_primitive(vm, Value::PreferredType::Number)); |
2375 | 0 | } |
2376 | | |
2377 | | // 3. If px is a String and py is a String, then |
2378 | 0 | if (x_primitive.is_string() && y_primitive.is_string()) { |
2379 | 0 | auto x_string = x_primitive.as_string().byte_string(); |
2380 | 0 | auto y_string = y_primitive.as_string().byte_string(); |
2381 | |
|
2382 | 0 | Utf8View x_code_points { x_string }; |
2383 | 0 | Utf8View y_code_points { y_string }; |
2384 | | |
2385 | | // a. Let lx be the length of px. |
2386 | | // b. Let ly be the length of py. |
2387 | | // c. For each integer i such that 0 ≤ i < min(lx, ly), in ascending order, do |
2388 | 0 | for (auto k = x_code_points.begin(), l = y_code_points.begin(); |
2389 | 0 | k != x_code_points.end() && l != y_code_points.end(); |
2390 | 0 | ++k, ++l) { |
2391 | | // i. Let cx be the integer that is the numeric value of the code unit at index i within px. |
2392 | | // ii. Let cy be the integer that is the numeric value of the code unit at index i within py. |
2393 | 0 | if (*k != *l) { |
2394 | | // iii. If cx < cy, return true. |
2395 | 0 | if (*k < *l) { |
2396 | 0 | return TriState::True; |
2397 | 0 | } |
2398 | | // iv. If cx > cy, return false. |
2399 | 0 | else { |
2400 | 0 | return TriState::False; |
2401 | 0 | } |
2402 | 0 | } |
2403 | 0 | } |
2404 | | |
2405 | | // d. If lx < ly, return true. Otherwise, return false. |
2406 | 0 | return x_code_points.length() < y_code_points.length() |
2407 | 0 | ? TriState::True |
2408 | 0 | : TriState::False; |
2409 | 0 | } |
2410 | | |
2411 | | // 4. Else, |
2412 | | // a. If px is a BigInt and py is a String, then |
2413 | 0 | if (x_primitive.is_bigint() && y_primitive.is_string()) { |
2414 | | // i. Let ny be StringToBigInt(py). |
2415 | 0 | auto y_bigint = string_to_bigint(vm, y_primitive.as_string().byte_string()); |
2416 | | |
2417 | | // ii. If ny is undefined, return undefined. |
2418 | 0 | if (!y_bigint.has_value()) |
2419 | 0 | return TriState::Unknown; |
2420 | | |
2421 | | // iii. Return BigInt::lessThan(px, ny). |
2422 | 0 | if (x_primitive.as_bigint().big_integer() < (*y_bigint)->big_integer()) |
2423 | 0 | return TriState::True; |
2424 | 0 | return TriState::False; |
2425 | 0 | } |
2426 | | |
2427 | | // b. If px is a String and py is a BigInt, then |
2428 | 0 | if (x_primitive.is_string() && y_primitive.is_bigint()) { |
2429 | | // i. Let nx be StringToBigInt(px). |
2430 | 0 | auto x_bigint = string_to_bigint(vm, x_primitive.as_string().byte_string()); |
2431 | | |
2432 | | // ii. If nx is undefined, return undefined. |
2433 | 0 | if (!x_bigint.has_value()) |
2434 | 0 | return TriState::Unknown; |
2435 | | |
2436 | | // iii. Return BigInt::lessThan(nx, py). |
2437 | 0 | if ((*x_bigint)->big_integer() < y_primitive.as_bigint().big_integer()) |
2438 | 0 | return TriState::True; |
2439 | 0 | return TriState::False; |
2440 | 0 | } |
2441 | | |
2442 | | // c. NOTE: Because px and py are primitive values, evaluation order is not important. |
2443 | | |
2444 | | // d. Let nx be ? ToNumeric(px). |
2445 | 0 | auto x_numeric = TRY(x_primitive.to_numeric(vm)); |
2446 | | |
2447 | | // e. Let ny be ? ToNumeric(py). |
2448 | 0 | auto y_numeric = TRY(y_primitive.to_numeric(vm)); |
2449 | | |
2450 | | // h. If nx or ny is NaN, return undefined. |
2451 | 0 | if (x_numeric.is_nan() || y_numeric.is_nan()) |
2452 | 0 | return TriState::Unknown; |
2453 | | |
2454 | | // i. If nx is -∞𝔽 or ny is +∞𝔽, return true. |
2455 | 0 | if (x_numeric.is_positive_infinity() || y_numeric.is_negative_infinity()) |
2456 | 0 | return TriState::False; |
2457 | | |
2458 | | // j. If nx is +∞𝔽 or ny is -∞𝔽, return false. |
2459 | 0 | if (x_numeric.is_negative_infinity() || y_numeric.is_positive_infinity()) |
2460 | 0 | return TriState::True; |
2461 | | |
2462 | | // f. If Type(nx) is the same as Type(ny), then |
2463 | | |
2464 | | // i. If nx is a Number, then |
2465 | 0 | if (x_numeric.is_number() && y_numeric.is_number()) { |
2466 | | // 1. Return Number::lessThan(nx, ny). |
2467 | 0 | if (x_numeric.as_double() < y_numeric.as_double()) |
2468 | 0 | return TriState::True; |
2469 | 0 | else |
2470 | 0 | return TriState::False; |
2471 | 0 | } |
2472 | | // ii. Else, |
2473 | 0 | if (x_numeric.is_bigint() && y_numeric.is_bigint()) { |
2474 | | // 1. Assert: nx is a BigInt. |
2475 | | // 2. Return BigInt::lessThan(nx, ny). |
2476 | 0 | if (x_numeric.as_bigint().big_integer() < y_numeric.as_bigint().big_integer()) |
2477 | 0 | return TriState::True; |
2478 | 0 | else |
2479 | 0 | return TriState::False; |
2480 | 0 | } |
2481 | | |
2482 | | // g. Assert: nx is a BigInt and ny is a Number, or nx is a Number and ny is a BigInt. |
2483 | 0 | VERIFY((x_numeric.is_number() && y_numeric.is_bigint()) || (x_numeric.is_bigint() && y_numeric.is_number())); |
2484 | | |
2485 | | // k. If ℝ(nx) < ℝ(ny), return true; otherwise return false. |
2486 | 0 | bool x_lower_than_y; |
2487 | 0 | VERIFY(!x_numeric.is_nan() && !y_numeric.is_nan()); |
2488 | 0 | if (x_numeric.is_number()) { |
2489 | 0 | x_lower_than_y = y_numeric.as_bigint().big_integer().compare_to_double(x_numeric.as_double()) |
2490 | 0 | == Crypto::UnsignedBigInteger::CompareResult::DoubleLessThanBigInt; |
2491 | 0 | } else { |
2492 | 0 | x_lower_than_y = x_numeric.as_bigint().big_integer().compare_to_double(y_numeric.as_double()) |
2493 | 0 | == Crypto::UnsignedBigInteger::CompareResult::DoubleGreaterThanBigInt; |
2494 | 0 | } |
2495 | 0 | if (x_lower_than_y) |
2496 | 0 | return TriState::True; |
2497 | 0 | else |
2498 | 0 | return TriState::False; |
2499 | 0 | } |
2500 | | |
2501 | | // 7.3.21 Invoke ( V, P [ , argumentsList ] ), https://tc39.es/ecma262/#sec-invoke |
2502 | | ThrowCompletionOr<Value> Value::invoke_internal(VM& vm, PropertyKey const& property_key, Optional<MarkedVector<Value>> arguments) |
2503 | 0 | { |
2504 | | // 1. If argumentsList is not present, set argumentsList to a new empty List. |
2505 | | |
2506 | | // 2. Let func be ? GetV(V, P). |
2507 | 0 | auto function = TRY(get(vm, property_key)); |
2508 | | |
2509 | | // 3. Return ? Call(func, V, argumentsList). |
2510 | 0 | ReadonlySpan<Value> argument_list; |
2511 | 0 | if (arguments.has_value()) |
2512 | 0 | argument_list = arguments.value().span(); |
2513 | 0 | return call(vm, function, *this, argument_list); |
2514 | 0 | } |
2515 | | |
2516 | | } |