
This is a continuation of the previous commit. Calling initialize() is the first thing that's done after allocating a cell on the JS heap - and in the common case of allocating an object, that's where properties are assigned and intrinsics occasionally accessed. Since those are supposed to live on the realm eventually, this is another step into that direction.
124 lines
5 KiB
C++
124 lines
5 KiB
C++
/*
|
|
* Copyright (c) 2020-2021, Linus Groh <linusg@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <AK/Math.h>
|
|
#include <LibJS/Runtime/AbstractOperations.h>
|
|
#include <LibJS/Runtime/Error.h>
|
|
#include <LibJS/Runtime/GlobalObject.h>
|
|
#include <LibJS/Runtime/NumberConstructor.h>
|
|
#include <LibJS/Runtime/NumberObject.h>
|
|
|
|
#ifdef __clang__
|
|
# define EPSILON_VALUE AK::exp2(-52.)
|
|
# define MAX_SAFE_INTEGER_VALUE AK::exp2(53.) - 1
|
|
# define MIN_SAFE_INTEGER_VALUE -(AK::exp2(53.) - 1)
|
|
#else
|
|
constexpr double const EPSILON_VALUE { __builtin_exp2(-52) };
|
|
constexpr double const MAX_SAFE_INTEGER_VALUE { __builtin_exp2(53) - 1 };
|
|
constexpr double const MIN_SAFE_INTEGER_VALUE { -(__builtin_exp2(53) - 1) };
|
|
#endif
|
|
|
|
namespace JS {
|
|
|
|
NumberConstructor::NumberConstructor(Realm& realm)
|
|
: NativeFunction(vm().names.Number.as_string(), *realm.global_object().function_prototype())
|
|
{
|
|
}
|
|
|
|
void NumberConstructor::initialize(Realm& realm)
|
|
{
|
|
auto& vm = this->vm();
|
|
NativeFunction::initialize(realm);
|
|
|
|
// 21.1.2.15 Number.prototype, https://tc39.es/ecma262/#sec-number.prototype
|
|
define_direct_property(vm.names.prototype, realm.global_object().number_prototype(), 0);
|
|
|
|
u8 attr = Attribute::Writable | Attribute::Configurable;
|
|
define_native_function(vm.names.isFinite, is_finite, 1, attr);
|
|
define_native_function(vm.names.isInteger, is_integer, 1, attr);
|
|
define_native_function(vm.names.isNaN, is_nan, 1, attr);
|
|
define_native_function(vm.names.isSafeInteger, is_safe_integer, 1, attr);
|
|
// FIXME: Store these as intrinsics (`parse_int_function()`) instead of getting them from the global object
|
|
define_direct_property(vm.names.parseInt, realm.global_object().get_without_side_effects(vm.names.parseInt), attr);
|
|
define_direct_property(vm.names.parseFloat, realm.global_object().get_without_side_effects(vm.names.parseFloat), attr);
|
|
define_direct_property(vm.names.EPSILON, Value(EPSILON_VALUE), 0);
|
|
define_direct_property(vm.names.MAX_VALUE, Value(NumericLimits<double>::max()), 0);
|
|
define_direct_property(vm.names.MIN_VALUE, Value(NumericLimits<double>::min()), 0);
|
|
define_direct_property(vm.names.MAX_SAFE_INTEGER, Value(MAX_SAFE_INTEGER_VALUE), 0);
|
|
define_direct_property(vm.names.MIN_SAFE_INTEGER, Value(MIN_SAFE_INTEGER_VALUE), 0);
|
|
define_direct_property(vm.names.NEGATIVE_INFINITY, js_negative_infinity(), 0);
|
|
define_direct_property(vm.names.POSITIVE_INFINITY, js_infinity(), 0);
|
|
define_direct_property(vm.names.NaN, js_nan(), 0);
|
|
|
|
define_direct_property(vm.names.length, Value(1), Attribute::Configurable);
|
|
}
|
|
|
|
// Most of 21.1.1.1 Number ( value ) factored into a separate function for sharing between call() and construct().
|
|
static ThrowCompletionOr<Value> get_value_from_constructor_argument(GlobalObject& global_object)
|
|
{
|
|
auto& vm = global_object.vm();
|
|
|
|
Value number;
|
|
if (vm.argument_count() > 0) {
|
|
auto primitive = TRY(vm.argument(0).to_numeric(global_object));
|
|
if (primitive.is_bigint()) {
|
|
// FIXME: How should huge values be handled here?
|
|
auto& big_integer = primitive.as_bigint().big_integer();
|
|
number = Value(static_cast<double>(big_integer.unsigned_value().to_u64()) * (big_integer.is_negative() ? -1.0 : 1.0));
|
|
} else {
|
|
number = primitive;
|
|
}
|
|
} else {
|
|
number = Value(0);
|
|
}
|
|
return number;
|
|
}
|
|
|
|
// 21.1.1.1 Number ( value ), https://tc39.es/ecma262/#sec-number-constructor-number-value
|
|
ThrowCompletionOr<Value> NumberConstructor::call()
|
|
{
|
|
return get_value_from_constructor_argument(global_object());
|
|
}
|
|
|
|
// 21.1.1.1 Number ( value ), https://tc39.es/ecma262/#sec-number-constructor-number-value
|
|
ThrowCompletionOr<Object*> NumberConstructor::construct(FunctionObject& new_target)
|
|
{
|
|
auto& global_object = this->global_object();
|
|
|
|
auto number = TRY(get_value_from_constructor_argument(global_object));
|
|
return TRY(ordinary_create_from_constructor<NumberObject>(global_object, new_target, &GlobalObject::number_prototype, number.as_double()));
|
|
}
|
|
|
|
// 21.1.2.2 Number.isFinite ( number ), https://tc39.es/ecma262/#sec-number.isfinite
|
|
JS_DEFINE_NATIVE_FUNCTION(NumberConstructor::is_finite)
|
|
{
|
|
return Value(vm.argument(0).is_finite_number());
|
|
}
|
|
|
|
// 21.1.2.3 Number.isInteger ( number ), https://tc39.es/ecma262/#sec-number.isinteger
|
|
JS_DEFINE_NATIVE_FUNCTION(NumberConstructor::is_integer)
|
|
{
|
|
return Value(vm.argument(0).is_integral_number());
|
|
}
|
|
|
|
// 21.1.2.4 Number.isNaN ( number ), https://tc39.es/ecma262/#sec-number.isnan
|
|
JS_DEFINE_NATIVE_FUNCTION(NumberConstructor::is_nan)
|
|
{
|
|
return Value(vm.argument(0).is_nan());
|
|
}
|
|
|
|
// 21.1.2.5 Number.isSafeInteger ( number ), https://tc39.es/ecma262/#sec-number.issafeinteger
|
|
JS_DEFINE_NATIVE_FUNCTION(NumberConstructor::is_safe_integer)
|
|
{
|
|
if (!vm.argument(0).is_number())
|
|
return Value(false);
|
|
if (!vm.argument(0).is_integral_number())
|
|
return Value(false);
|
|
auto value = vm.argument(0).as_double();
|
|
return Value(value >= MIN_SAFE_INTEGER_VALUE && value <= MAX_SAFE_INTEGER_VALUE);
|
|
}
|
|
|
|
}
|