14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License.
54514f5e3Sopenharmony_ci * You may obtain a copy of the License at
64514f5e3Sopenharmony_ci *
74514f5e3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84514f5e3Sopenharmony_ci *
94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and
134514f5e3Sopenharmony_ci * limitations under the License.
144514f5e3Sopenharmony_ci */
154514f5e3Sopenharmony_ci
164514f5e3Sopenharmony_ci#include "ecmascript/builtins/builtins_bigint.h"
174514f5e3Sopenharmony_ci
184514f5e3Sopenharmony_ci#include "ecmascript/js_primitive_ref.h"
194514f5e3Sopenharmony_ci#ifdef ARK_SUPPORT_INTL
204514f5e3Sopenharmony_ci#include "ecmascript/js_number_format.h"
214514f5e3Sopenharmony_ci#else
224514f5e3Sopenharmony_ci#ifndef ARK_NOT_SUPPORT_INTL_GLOBAL
234514f5e3Sopenharmony_ci#include "ecmascript/intl/global_intl_helper.h"
244514f5e3Sopenharmony_ci#endif
254514f5e3Sopenharmony_ci#endif
264514f5e3Sopenharmony_ci
274514f5e3Sopenharmony_cinamespace panda::ecmascript::builtins {
284514f5e3Sopenharmony_ciJSTaggedValue BuiltinsBigInt::BigIntConstructor(EcmaRuntimeCallInfo *argv)
294514f5e3Sopenharmony_ci{
304514f5e3Sopenharmony_ci    ASSERT(argv);
314514f5e3Sopenharmony_ci    JSThread *thread = argv->GetThread();
324514f5e3Sopenharmony_ci    BUILTINS_API_TRACE(thread, BigInt, Constructor);
334514f5e3Sopenharmony_ci    [[maybe_unused]] EcmaHandleScope handleScope(thread);
344514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
354514f5e3Sopenharmony_ci    // 1. If NewTarget is not undefined, throw a TypeError exception.
364514f5e3Sopenharmony_ci    if (!newTarget->IsUndefined()) {
374514f5e3Sopenharmony_ci        THROW_TYPE_ERROR_AND_RETURN(thread, "BigInt is not a constructor", JSTaggedValue::Exception());
384514f5e3Sopenharmony_ci    }
394514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
404514f5e3Sopenharmony_ci    return BigIntConstructorInternal(thread, value);
414514f5e3Sopenharmony_ci}
424514f5e3Sopenharmony_ci
434514f5e3Sopenharmony_ciJSTaggedValue BuiltinsBigInt::BigIntConstructorInternal(JSThread *thread, JSHandle<JSTaggedValue> value)
444514f5e3Sopenharmony_ci{
454514f5e3Sopenharmony_ci    BUILTINS_API_TRACE(thread, BigInt, Constructor);
464514f5e3Sopenharmony_ci    [[maybe_unused]] EcmaHandleScope handleScope(thread);
474514f5e3Sopenharmony_ci    // 2. Let prim be ? ToPrimitive(value).
484514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> Primitive(thread, JSTaggedValue::ToPrimitive(thread, value));
494514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
504514f5e3Sopenharmony_ci    // 3. If Type(prim) is Number, return ? NumberToBigInt(prim).
514514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
524514f5e3Sopenharmony_ci    if (Primitive->IsNumber()) {
534514f5e3Sopenharmony_ci        return BigInt::NumberToBigInt(thread, Primitive);
544514f5e3Sopenharmony_ci    }
554514f5e3Sopenharmony_ci    // 4. Otherwise, return ? ToBigInt(value).
564514f5e3Sopenharmony_ci    return JSTaggedValue::ToBigInt(thread, value);
574514f5e3Sopenharmony_ci}
584514f5e3Sopenharmony_ci
594514f5e3Sopenharmony_ciJSTaggedValue BuiltinsBigInt::AsUintN(EcmaRuntimeCallInfo *argv)
604514f5e3Sopenharmony_ci{
614514f5e3Sopenharmony_ci    ASSERT(argv);
624514f5e3Sopenharmony_ci    JSThread *thread = argv->GetThread();
634514f5e3Sopenharmony_ci    BUILTINS_API_TRACE(thread, BigInt, AsUintN);
644514f5e3Sopenharmony_ci    [[maybe_unused]] EcmaHandleScope handleScope(thread);
654514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> bits = GetCallArg(argv, 0);
664514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> bigint = GetCallArg(argv, 1);
674514f5e3Sopenharmony_ci    // 1. Let bits be ? ToIndex(bits).
684514f5e3Sopenharmony_ci    JSTaggedNumber index = JSTaggedValue::ToIndex(thread, bits);
694514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
704514f5e3Sopenharmony_ci    // 2. Let bigint be ? ToBigInt(bigint).
714514f5e3Sopenharmony_ci    JSTaggedValue jsBigint = JSTaggedValue::ToBigInt(thread, bigint);
724514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
734514f5e3Sopenharmony_ci    JSHandle<BigInt> jsBigintVal(thread, jsBigint);
744514f5e3Sopenharmony_ci    // 3. Return a BigInt representing bigint modulo 2bits.
754514f5e3Sopenharmony_ci    return BigInt::AsUintN(thread, index, jsBigintVal);
764514f5e3Sopenharmony_ci}
774514f5e3Sopenharmony_ci
784514f5e3Sopenharmony_ciJSTaggedValue BuiltinsBigInt::AsIntN(EcmaRuntimeCallInfo *argv)
794514f5e3Sopenharmony_ci{
804514f5e3Sopenharmony_ci    ASSERT(argv);
814514f5e3Sopenharmony_ci    JSThread *thread = argv->GetThread();
824514f5e3Sopenharmony_ci    BUILTINS_API_TRACE(thread, BigInt, AsIntN);
834514f5e3Sopenharmony_ci    [[maybe_unused]] EcmaHandleScope handleScope(thread);
844514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> bits = GetCallArg(argv, 0);
854514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> bigint = GetCallArg(argv, 1);
864514f5e3Sopenharmony_ci    // 1. Let bits be ? ToIndex(bits).
874514f5e3Sopenharmony_ci    JSTaggedNumber index = JSTaggedValue::ToIndex(thread, bits);
884514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
894514f5e3Sopenharmony_ci    // 2. Let bigint be ? ToBigInt(bigint).
904514f5e3Sopenharmony_ci    JSTaggedValue jsBigint = JSTaggedValue::ToBigInt(thread, bigint);
914514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
924514f5e3Sopenharmony_ci    JSHandle<BigInt> jsBigintVal(thread, jsBigint);
934514f5e3Sopenharmony_ci    // 3. Let mod be ℝ(bigint) modulo 2bits.
944514f5e3Sopenharmony_ci    // 4. If mod ≥ 2bits - 1, return ℤ(mod - 2bits); otherwise, return ℤ(mod).
954514f5e3Sopenharmony_ci    return BigInt::AsintN(thread, index, jsBigintVal);
964514f5e3Sopenharmony_ci}
974514f5e3Sopenharmony_ci
984514f5e3Sopenharmony_ciJSTaggedValue BuiltinsBigInt::ToLocaleString(EcmaRuntimeCallInfo *argv)
994514f5e3Sopenharmony_ci{
1004514f5e3Sopenharmony_ci    ASSERT(argv);
1014514f5e3Sopenharmony_ci    JSThread *thread = argv->GetThread();
1024514f5e3Sopenharmony_ci    BUILTINS_API_TRACE(thread, BigInt, ToLocaleString);
1034514f5e3Sopenharmony_ci    [[maybe_unused]] EcmaHandleScope handleScope(thread);
1044514f5e3Sopenharmony_ci    // 1. Let x be ? ThisBigIntValue(this value).
1054514f5e3Sopenharmony_ci    JSTaggedValue value = ThisBigIntValue(argv);
1064514f5e3Sopenharmony_ci    [[maybe_unused]] JSHandle<JSTaggedValue> x(thread, value);
1074514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1084514f5e3Sopenharmony_ci
1094514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0);
1104514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> options = GetCallArg(argv, 1);
1114514f5e3Sopenharmony_ci    [[maybe_unused]] bool cacheable = (locales->IsUndefined() || locales->IsString()) && options->IsUndefined();
1124514f5e3Sopenharmony_ci#ifdef ARK_SUPPORT_INTL
1134514f5e3Sopenharmony_ci    if (cacheable) {
1144514f5e3Sopenharmony_ci        auto numberFormatter = JSNumberFormat::GetCachedIcuNumberFormatter(thread, locales);
1154514f5e3Sopenharmony_ci        if (numberFormatter != nullptr) {
1164514f5e3Sopenharmony_ci            JSHandle<JSTaggedValue> result = JSNumberFormat::FormatNumeric(thread, numberFormatter, x.GetTaggedValue());
1174514f5e3Sopenharmony_ci            RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1184514f5e3Sopenharmony_ci            return result.GetTaggedValue();
1194514f5e3Sopenharmony_ci        }
1204514f5e3Sopenharmony_ci    }
1214514f5e3Sopenharmony_ci    // 2. Let numberFormat be ? Construct(%NumberFormat%, « locales, options »).
1224514f5e3Sopenharmony_ci    EcmaVM *ecmaVm = thread->GetEcmaVM();
1234514f5e3Sopenharmony_ci    JSHandle<JSFunction> ctor(ecmaVm->GetGlobalEnv()->GetNumberFormatFunction());
1244514f5e3Sopenharmony_ci    ObjectFactory *factory = ecmaVm->GetFactory();
1254514f5e3Sopenharmony_ci    JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(ctor);
1264514f5e3Sopenharmony_ci    JSHandle<JSNumberFormat> numberFormat = JSHandle<JSNumberFormat>::Cast(obj);
1274514f5e3Sopenharmony_ci    JSNumberFormat::InitializeNumberFormat(thread, numberFormat, locales, options, cacheable);
1284514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1294514f5e3Sopenharmony_ci    if (cacheable) {
1304514f5e3Sopenharmony_ci        auto numberFormatter = JSNumberFormat::GetCachedIcuNumberFormatter(thread, locales);
1314514f5e3Sopenharmony_ci        ASSERT(numberFormatter != nullptr);
1324514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> result = JSNumberFormat::FormatNumeric(thread, numberFormatter, x.GetTaggedValue());
1334514f5e3Sopenharmony_ci        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1344514f5e3Sopenharmony_ci        return result.GetTaggedValue();
1354514f5e3Sopenharmony_ci    }
1364514f5e3Sopenharmony_ci
1374514f5e3Sopenharmony_ci    // Return ? FormatNumeric(numberFormat, x).
1384514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> result = JSNumberFormat::FormatNumeric(thread, numberFormat, x.GetTaggedValue());
1394514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1404514f5e3Sopenharmony_ci    return result.GetTaggedValue();
1414514f5e3Sopenharmony_ci#else
1424514f5e3Sopenharmony_ci#ifdef ARK_NOT_SUPPORT_INTL_GLOBAL
1434514f5e3Sopenharmony_ci    ARK_SUPPORT_INTL_RETURN_JSVALUE(thread, "LocaleCompare");
1444514f5e3Sopenharmony_ci#else
1454514f5e3Sopenharmony_ci    intl::GlobalIntlHelper gh(thread, intl::GlobalFormatterType::NumberFormatter);
1464514f5e3Sopenharmony_ci    auto numberFormatter = gh.GetGlobalObject<intl::GlobalNumberFormat>(thread,
1474514f5e3Sopenharmony_ci        locales, options, intl::GlobalFormatterType::NumberFormatter, cacheable);
1484514f5e3Sopenharmony_ci    if (numberFormatter == nullptr) {
1494514f5e3Sopenharmony_ci        LOG_ECMA(ERROR) << "BuiltinsBigInt:numberFormatter is nullptr";
1504514f5e3Sopenharmony_ci    }
1514514f5e3Sopenharmony_ci    ASSERT(numberFormatter != nullptr);
1524514f5e3Sopenharmony_ci    std::string result = numberFormatter->Format(x->GetDouble());
1534514f5e3Sopenharmony_ci    EcmaVM *ecmaVm = thread->GetEcmaVM();
1544514f5e3Sopenharmony_ci    ObjectFactory *factory = ecmaVm->GetFactory();
1554514f5e3Sopenharmony_ci    JSHandle returnValue = factory->NewFromStdString(result);
1564514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1574514f5e3Sopenharmony_ci    return returnValue.GetTaggedValue();
1584514f5e3Sopenharmony_ci#endif
1594514f5e3Sopenharmony_ci#endif
1604514f5e3Sopenharmony_ci}
1614514f5e3Sopenharmony_ci
1624514f5e3Sopenharmony_ciJSTaggedValue BuiltinsBigInt::ToString(EcmaRuntimeCallInfo *argv)
1634514f5e3Sopenharmony_ci{
1644514f5e3Sopenharmony_ci    ASSERT(argv);
1654514f5e3Sopenharmony_ci    JSThread *thread = argv->GetThread();
1664514f5e3Sopenharmony_ci    BUILTINS_API_TRACE(thread, BigInt, ToString);
1674514f5e3Sopenharmony_ci    [[maybe_unused]] EcmaHandleScope handleScope(thread);
1684514f5e3Sopenharmony_ci
1694514f5e3Sopenharmony_ci    // 1. Let x be ? thisBigIntValue(this value).
1704514f5e3Sopenharmony_ci    JSTaggedValue value = ThisBigIntValue(argv);
1714514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1724514f5e3Sopenharmony_ci    JSHandle<BigInt> thisBigint(thread, value);
1734514f5e3Sopenharmony_ci    // 2. If radix is not present, let radixNumber be 10
1744514f5e3Sopenharmony_ci    double radix = base::DECIMAL;
1754514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> radixValue = GetCallArg(argv, 0);
1764514f5e3Sopenharmony_ci    // 3. Else, let radixNumber be ? ToIntegerOrInfinity(radix).
1774514f5e3Sopenharmony_ci    if (!radixValue->IsUndefined()) {
1784514f5e3Sopenharmony_ci        JSTaggedNumber radixNumber = JSTaggedValue::ToInteger(thread, radixValue);
1794514f5e3Sopenharmony_ci        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1804514f5e3Sopenharmony_ci        radix = radixNumber.GetNumber();
1814514f5e3Sopenharmony_ci    }
1824514f5e3Sopenharmony_ci    // 4. If radixNumber < 2 or radixNumber > 36, throw a RangeError exception.
1834514f5e3Sopenharmony_ci    if (radix < base::MIN_RADIX || radix > base::MAX_RADIX) {
1844514f5e3Sopenharmony_ci        THROW_RANGE_ERROR_AND_RETURN(thread, "toString() radix argument must be between 2 and 36",
1854514f5e3Sopenharmony_ci                                     JSTaggedValue::Exception());
1864514f5e3Sopenharmony_ci    }
1874514f5e3Sopenharmony_ci    // 5. If radixNumber = 10, return ToString(x).
1884514f5e3Sopenharmony_ci    if (radix == base::DECIMAL) {
1894514f5e3Sopenharmony_ci        return BigInt::ToString(thread, thisBigint).GetTaggedValue();
1904514f5e3Sopenharmony_ci    }
1914514f5e3Sopenharmony_ci    // 6. Return the String representation of this BigInt value using the radix specified by radixNumber
1924514f5e3Sopenharmony_ci    return BigInt::ToString(thread, thisBigint, static_cast<int>(radix)).GetTaggedValue();
1934514f5e3Sopenharmony_ci}
1944514f5e3Sopenharmony_ci
1954514f5e3Sopenharmony_ciJSTaggedValue BuiltinsBigInt::ValueOf(EcmaRuntimeCallInfo *argv)
1964514f5e3Sopenharmony_ci{
1974514f5e3Sopenharmony_ci    ASSERT(argv);
1984514f5e3Sopenharmony_ci    JSThread *thread = argv->GetThread();
1994514f5e3Sopenharmony_ci    BUILTINS_API_TRACE(thread, BigInt, ValueOf);
2004514f5e3Sopenharmony_ci    [[maybe_unused]] EcmaHandleScope handleScope(thread);
2014514f5e3Sopenharmony_ci    // 1. Let x be ? thisBigIntValue(this value).
2024514f5e3Sopenharmony_ci    return ThisBigIntValue(argv);
2034514f5e3Sopenharmony_ci}
2044514f5e3Sopenharmony_ci
2054514f5e3Sopenharmony_ciJSTaggedValue BuiltinsBigInt::ThisBigIntValue(EcmaRuntimeCallInfo *argv)
2064514f5e3Sopenharmony_ci{
2074514f5e3Sopenharmony_ci    ASSERT(argv);
2084514f5e3Sopenharmony_ci    JSThread *thread = argv->GetThread();
2094514f5e3Sopenharmony_ci    BUILTINS_API_TRACE(thread, BigInt, ThisBigIntValue);
2104514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> value = GetThis(argv);
2114514f5e3Sopenharmony_ci    // 1. If Type(value) is BigInt, return value.
2124514f5e3Sopenharmony_ci    if (value->IsBigInt()) {
2134514f5e3Sopenharmony_ci        return value.GetTaggedValue();
2144514f5e3Sopenharmony_ci    }
2154514f5e3Sopenharmony_ci    // 2. If Type(value) is Object and value has a [[BigIntData]] internal slot, then
2164514f5e3Sopenharmony_ci    if (value->IsJSPrimitiveRef()) {
2174514f5e3Sopenharmony_ci        JSTaggedValue primitive = JSPrimitiveRef::Cast(value->GetTaggedObject())->GetValue();
2184514f5e3Sopenharmony_ci        // a. Assert: Type(value.[[BigIntData]]) is BigInt.
2194514f5e3Sopenharmony_ci        if (primitive.IsBigInt()) {
2204514f5e3Sopenharmony_ci            // b. Return value.[[BigIntData]].
2214514f5e3Sopenharmony_ci            return primitive;
2224514f5e3Sopenharmony_ci        }
2234514f5e3Sopenharmony_ci    }
2244514f5e3Sopenharmony_ci    // 3. Throw a TypeError exception.
2254514f5e3Sopenharmony_ci    THROW_TYPE_ERROR_AND_RETURN(thread, "not BigInt type", JSTaggedValue::Exception());
2264514f5e3Sopenharmony_ci}
2274514f5e3Sopenharmony_ci}  // namespace panda::ecmascript::builtins