ladybird/Userland/Libraries/LibJS/Runtime/BigIntConstructor.cpp
Linus Groh 6e19ab2bbc AK+Everywhere: Rename String to DeprecatedString
We have a new, improved string type coming up in AK (OOM aware, no null
state), and while it's going to use UTF-8, the name UTF8String is a
mouthful - so let's free up the String name by renaming the existing
class.
Making the old one have an annoying name will hopefully also help with
quick adoption :^)
2022-12-06 08:54:33 +01:00

105 lines
3.8 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2020-2022, Linus Groh <linusg@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/DeprecatedString.h>
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/BigInt.h>
#include <LibJS/Runtime/BigIntConstructor.h>
#include <LibJS/Runtime/BigIntObject.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/VM.h>
namespace JS {
static const Crypto::SignedBigInteger BIGINT_ONE { 1 };
BigIntConstructor::BigIntConstructor(Realm& realm)
: NativeFunction(realm.vm().names.BigInt.as_string(), *realm.intrinsics().function_prototype())
{
}
void BigIntConstructor::initialize(Realm& realm)
{
auto& vm = this->vm();
NativeFunction::initialize(realm);
// 21.2.2.3 BigInt.prototype, https://tc39.es/ecma262/#sec-bigint.prototype
define_direct_property(vm.names.prototype, realm.intrinsics().bigint_prototype(), 0);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function(realm, vm.names.asIntN, as_int_n, 2, attr);
define_native_function(realm, vm.names.asUintN, as_uint_n, 2, attr);
define_direct_property(vm.names.length, Value(1), Attribute::Configurable);
}
// 21.2.1.1 BigInt ( value ), https://tc39.es/ecma262/#sec-bigint-constructor-number-value
ThrowCompletionOr<Value> BigIntConstructor::call()
{
auto& vm = this->vm();
auto value = vm.argument(0);
// 2. Let prim be ? ToPrimitive(value, number).
auto primitive = TRY(value.to_primitive(vm, Value::PreferredType::Number));
// 3. If Type(prim) is Number, return ? NumberToBigInt(prim).
if (primitive.is_number())
return TRY(number_to_bigint(vm, primitive));
// 4. Otherwise, return ? ToBigInt(prim).
return TRY(primitive.to_bigint(vm));
}
// 21.2.1.1 BigInt ( value ), https://tc39.es/ecma262/#sec-bigint-constructor-number-value
ThrowCompletionOr<Object*> BigIntConstructor::construct(FunctionObject&)
{
return vm().throw_completion<TypeError>(ErrorType::NotAConstructor, "BigInt");
}
// 21.2.2.1 BigInt.asIntN ( bits, bigint ), https://tc39.es/ecma262/#sec-bigint.asintn
JS_DEFINE_NATIVE_FUNCTION(BigIntConstructor::as_int_n)
{
// 1. Set bits to ? ToIndex(bits).
auto bits = TRY(vm.argument(0).to_index(vm));
// 2. Set bigint to ? ToBigInt(bigint).
auto* bigint = TRY(vm.argument(1).to_bigint(vm));
// 3. Let mod be (bigint) modulo 2^bits.
// FIXME: For large values of `bits`, this can likely be improved with a SignedBigInteger API to
// drop the most significant bits.
auto bits_shift_left = BIGINT_ONE.shift_left(bits);
auto mod = modulo(bigint->big_integer(), bits_shift_left);
// 4. If mod ≥ 2^(bits-1), return (mod - 2^bits); otherwise, return (mod).
// NOTE: Some of the below conditionals are non-standard, but are to protect SignedBigInteger from
// allocating an absurd amount of memory if `bits - 1` overflows to NumericLimits<size_t>::max.
if ((bits == 0) && (mod >= BIGINT_ONE))
return js_bigint(vm, mod.minus(bits_shift_left));
if ((bits > 0) && (mod >= BIGINT_ONE.shift_left(bits - 1)))
return js_bigint(vm, mod.minus(bits_shift_left));
return js_bigint(vm, mod);
}
// 21.2.2.2 BigInt.asUintN ( bits, bigint ), https://tc39.es/ecma262/#sec-bigint.asuintn
JS_DEFINE_NATIVE_FUNCTION(BigIntConstructor::as_uint_n)
{
// 1. Set bits to ? ToIndex(bits).
auto bits = TRY(vm.argument(0).to_index(vm));
// 2. Set bigint to ? ToBigInt(bigint).
auto* bigint = TRY(vm.argument(1).to_bigint(vm));
// 3. Return the BigInt value that represents (bigint) modulo 2bits.
// FIXME: For large values of `bits`, this can likely be improved with a SignedBigInteger API to
// drop the most significant bits.
return js_bigint(vm, modulo(bigint->big_integer(), BIGINT_ONE.shift_left(bits)));
}
}