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