summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibJS/Runtime/NumberConstructor.cpp
blob: 8665680c05e6e18cd23f6bd2f51b91131f07ac2c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
 * 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 const double EPSILON_VALUE { __builtin_exp2(-52) };
constexpr const double MAX_SAFE_INTEGER_VALUE { __builtin_exp2(53) - 1 };
constexpr const double MIN_SAFE_INTEGER_VALUE { -(__builtin_exp2(53) - 1) };
#endif

namespace JS {

NumberConstructor::NumberConstructor(GlobalObject& global_object)
    : NativeFunction(vm().names.Number.as_string(), *global_object.function_prototype())
{
}

void NumberConstructor::initialize(GlobalObject& global_object)
{
    auto& vm = this->vm();
    NativeFunction::initialize(global_object);

    // 21.1.2.15 Number.prototype, https://tc39.es/ecma262/#sec-number.prototype
    define_direct_property(vm.names.prototype, 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);
    define_direct_property(vm.names.parseInt, global_object.get(vm.names.parseInt), attr);
    define_direct_property(vm.names.parseFloat, global_object.get(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);
}

NumberConstructor::~NumberConstructor()
{
}

// Most of 21.1.1.1 Number ( value ) factored into a separate function for sharing between call() and construct().
static Value get_value_from_constructor_argument(GlobalObject& global_object)
{
    auto& vm = global_object.vm();

    Value number;
    if (vm.argument_count() > 0) {
        auto primitive = vm.argument(0).to_numeric(global_object);
        if (vm.exception())
            return {};
        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
Value NumberConstructor::call()
{
    auto& vm = this->vm();
    auto& global_object = this->global_object();

    auto number = get_value_from_constructor_argument(global_object);
    if (vm.exception())
        return {};
    return number;
}

// 21.1.1.1 Number ( value ), https://tc39.es/ecma262/#sec-number-constructor-number-value
Value NumberConstructor::construct(FunctionObject& new_target)
{
    auto& vm = this->vm();
    auto& global_object = this->global_object();

    auto number = get_value_from_constructor_argument(global_object);
    if (vm.exception())
        return {};
    return TRY_OR_DISCARD(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);
}

}