1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-28 19:05:08 +00:00

LibJS: Add Value::to_{index,length,integer_or_infinity} abstract operations

We should pay more attention to using the well-defined abstract
operations from the spec rather than making up our own, often slightly
different rules. This is another step in that direction.
This commit is contained in:
Linus Groh 2020-12-02 13:23:51 +00:00 committed by Andreas Kling
parent 6de4f1fcb3
commit eaa85969c4
3 changed files with 66 additions and 1 deletions

View file

@ -53,6 +53,9 @@
namespace JS {
// Used in various abstract operations to make it obvious when a non-optional return value must be discarded.
static const double INVALID { 0 };
static const Crypto::SignedBigInteger BIGINT_ZERO { 0 };
static bool is_valid_bigint_value(String string)
@ -362,11 +365,12 @@ i32 Value::to_i32(GlobalObject& global_object) const
size_t Value::to_size_t(GlobalObject& global_object) const
{
// FIXME: Replace uses of this function with to_length/to_index for correct behaviour and remove this eventually.
if (is_empty())
return 0;
auto number = to_number(global_object);
if (global_object.vm().exception())
return 0;
return INVALID;
if (number.is_nan())
return 0;
if (number.as_double() <= 0)
@ -374,6 +378,63 @@ size_t Value::to_size_t(GlobalObject& global_object) const
return number.as_size_t();
}
size_t Value::to_length(GlobalObject& global_object) const
{
// 7.1.20 ToLength, https://tc39.es/ecma262/#sec-tolength
auto& vm = global_object.vm();
auto len = to_integer_or_infinity(global_object);
if (vm.exception())
return INVALID;
if (len <= 0)
return 0;
return min(len, MAX_ARRAY_LIKE_INDEX);
}
size_t Value::to_index(GlobalObject& global_object) const
{
// 7.1.22 ToIndex, https://tc39.es/ecma262/#sec-toindex
auto& vm = global_object.vm();
if (is_undefined())
return 0;
auto integer_index = to_integer_or_infinity(global_object);
if (vm.exception())
return INVALID;
if (integer_index < 0) {
vm.throw_exception<RangeError>(global_object, ErrorType::InvalidIndex);
return INVALID;
}
auto index = Value(integer_index).to_length(global_object);
ASSERT(!vm.exception());
if (integer_index != index) {
vm.throw_exception<RangeError>(global_object, ErrorType::InvalidIndex);
return INVALID;
}
return index;
}
double Value::to_integer_or_infinity(GlobalObject& global_object) const
{
// 7.1.5 ToIntegerOrInfinity, https://tc39.es/ecma262/#sec-tointegerorinfinity
auto& vm = global_object.vm();
auto number = to_number(global_object);
if (vm.exception())
return INVALID;
if (number.is_nan() || number.as_double() == 0)
return 0;
if (number.is_infinity())
return number.as_double();
auto integer = floor(abs(number.as_double()));
if (number.as_double() < 0)
integer = -integer;
return integer;
}
Value greater_than(GlobalObject& global_object, Value lhs, Value rhs)
{
TriState relation = abstract_relation(global_object, false, lhs, rhs);