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:
parent
6de4f1fcb3
commit
eaa85969c4
3 changed files with 66 additions and 1 deletions
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue