From 7ff144d533514420a60395e7dc9b41397846d90a Mon Sep 17 00:00:00 2001 From: Luke Date: Thu, 17 Jun 2021 00:13:26 +0100 Subject: LibJS: Add a bunch of numeric conversions to Value Namely: - BigInt64 - BigUint64 - i16 - u16 - i8 - u8 - Clamped u8 These will be used in ArrayBuffer::numeric_to_raw_bytes later. --- Userland/Libraries/LibJS/Runtime/Value.cpp | 113 +++++++++++++++++++++++++++++ Userland/Libraries/LibJS/Runtime/Value.h | 7 ++ 2 files changed, 120 insertions(+) (limited to 'Userland/Libraries') diff --git a/Userland/Libraries/LibJS/Runtime/Value.cpp b/Userland/Libraries/LibJS/Runtime/Value.cpp index bff74edc29..ab045e17a9 100644 --- a/Userland/Libraries/LibJS/Runtime/Value.cpp +++ b/Userland/Libraries/LibJS/Runtime/Value.cpp @@ -548,6 +548,24 @@ BigInt* Value::to_bigint(GlobalObject& global_object) const } } +// 7.1.15 ToBigInt64 ( argument ), https://tc39.es/ecma262/multipage/abstract-operations.html#sec-tobigint64 +i64 Value::to_bigint_int64(GlobalObject& global_object) const +{ + auto* bigint = to_bigint(global_object); + if (global_object.vm().exception()) + return INVALID; + return static_cast(bigint->big_integer().to_u64()); +} + +// 7.1.16 ToBigUint64 ( argument ), https://tc39.es/ecma262/multipage/abstract-operations.html#sec-tobiguint64 +u64 Value::to_bigint_uint64(GlobalObject& global_object) const +{ + auto* bigint = to_bigint(global_object); + if (global_object.vm().exception()) + return INVALID; + return bigint->big_integer().to_u64(); +} + // FIXME: These two conversions are wrong for JS, and seem likely to be footguns i32 Value::as_i32() const { @@ -615,6 +633,101 @@ u32 Value::to_u32(GlobalObject& global_object) const return static_cast(int32bit); } +// 7.1.8 ToInt16 ( argument ), https://tc39.es/ecma262/#sec-toint16 +i16 Value::to_i16(GlobalObject& global_object) const +{ + auto number = to_number(global_object); + if (global_object.vm().exception()) + return INVALID; + double value = number.as_double(); + if (!isfinite(value) || value == 0) + return 0; + auto abs = fabs(value); + auto int_val = floor(abs); + if (signbit(value)) + int_val = -int_val; + auto remainder = fmod(int_val, 65536.0); + auto int16bit = remainder >= 0.0 ? remainder : remainder + 65536.0; // The notation “x modulo y” computes a value k of the same sign as y + if (int16bit >= 32768.0) + int16bit -= 65536.0; + return static_cast(int16bit); +} + +// 7.1.9 ToUint16 ( argument ), https://tc39.es/ecma262/#sec-touint16 +u16 Value::to_u16(GlobalObject& global_object) const +{ + auto number = to_number(global_object); + if (global_object.vm().exception()) + return INVALID; + double value = number.as_double(); + if (!isfinite(value) || value == 0) + return 0; + auto int_val = floor(fabs(value)); + if (signbit(value)) + int_val = -int_val; + auto int16bit = fmod(int_val, NumericLimits::max() + 1.0); + return static_cast(int16bit); +} + +// 7.1.10 ToInt8 ( argument ), https://tc39.es/ecma262/#sec-toint8 +i8 Value::to_i8(GlobalObject& global_object) const +{ + auto number = to_number(global_object); + if (global_object.vm().exception()) + return INVALID; + double value = number.as_double(); + if (!isfinite(value) || value == 0) + return 0; + auto abs = fabs(value); + auto int_val = floor(abs); + if (signbit(value)) + int_val = -int_val; + auto remainder = fmod(int_val, 256.0); + auto int8bit = remainder >= 0.0 ? remainder : remainder + 256.0; // The notation “x modulo y” computes a value k of the same sign as y + if (int8bit >= 128.0) + int8bit -= 256.0; + return static_cast(int8bit); +} + +// 7.1.11 ToUint8 ( argument ), https://tc39.es/ecma262/#sec-touint8 +u8 Value::to_u8(GlobalObject& global_object) const +{ + auto number = to_number(global_object); + if (global_object.vm().exception()) + return INVALID; + double value = number.as_double(); + if (!isfinite(value) || value == 0) + return 0; + auto int_val = floor(fabs(value)); + if (signbit(value)) + int_val = -int_val; + auto int8bit = fmod(int_val, NumericLimits::max() + 1.0); + return static_cast(int8bit); +} + +// 7.1.12 ToUint8Clamp ( argument ), https://tc39.es/ecma262/#sec-touint8clamp +u8 Value::to_u8_clamp(GlobalObject& global_object) const +{ + auto number = to_number(global_object); + if (global_object.vm().exception()) + return INVALID; + if (number.is_nan()) + return 0; + double value = number.as_double(); + if (value <= 0.0) + return 0; + if (value >= 255.0) + return 255; + auto int_val = floor(value); + if (int_val + 0.5 < value) + return static_cast(int_val + 1.0); + if (value < int_val + 0.5) + return static_cast(int_val); + if (fmod(int_val, 2.0) == 1.0) + return static_cast(int_val + 1.0); + return static_cast(int_val); +} + // 7.1.20 ToLength ( argument ), https://tc39.es/ecma262/#sec-tolength size_t Value::to_length(GlobalObject& global_object) const { diff --git a/Userland/Libraries/LibJS/Runtime/Value.h b/Userland/Libraries/LibJS/Runtime/Value.h index 2e861feb99..09eca1530b 100644 --- a/Userland/Libraries/LibJS/Runtime/Value.h +++ b/Userland/Libraries/LibJS/Runtime/Value.h @@ -265,6 +265,8 @@ public: Value to_numeric(GlobalObject&) const; Value to_number(GlobalObject&) const; BigInt* to_bigint(GlobalObject&) const; + i64 to_bigint_int64(GlobalObject&) const; + u64 to_bigint_uint64(GlobalObject&) const; double to_double(GlobalObject&) const; StringOrSymbol to_property_key(GlobalObject&) const; i32 to_i32(GlobalObject& global_object) const @@ -274,6 +276,11 @@ public: return to_i32_slow_case(global_object); } u32 to_u32(GlobalObject&) const; + i16 to_i16(GlobalObject&) const; + u16 to_u16(GlobalObject&) const; + i8 to_i8(GlobalObject&) const; + u8 to_u8(GlobalObject&) const; + u8 to_u8_clamp(GlobalObject&) const; size_t to_length(GlobalObject&) const; size_t to_index(GlobalObject&) const; double to_integer_or_infinity(GlobalObject&) const; -- cgit v1.2.3