14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2021-2024 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_number_format.h" 174514f5e3Sopenharmony_ci 184514f5e3Sopenharmony_ci#include "ecmascript/js_function.h" 194514f5e3Sopenharmony_ci#include "ecmascript/js_number_format.h" 204514f5e3Sopenharmony_ci 214514f5e3Sopenharmony_cinamespace panda::ecmascript::builtins { 224514f5e3Sopenharmony_ci// 13.2.1 Intl.NumberFormat ( [ locales [ , options ] ] ) 234514f5e3Sopenharmony_ciJSTaggedValue BuiltinsNumberFormat::NumberFormatConstructor(EcmaRuntimeCallInfo *argv) 244514f5e3Sopenharmony_ci{ 254514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 264514f5e3Sopenharmony_ci BUILTINS_API_TRACE(thread, NumberFormat, Constructor); 274514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope scope(thread); 284514f5e3Sopenharmony_ci EcmaVM *ecmaVm = thread->GetEcmaVM(); 294514f5e3Sopenharmony_ci JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv(); 304514f5e3Sopenharmony_ci ObjectFactory *factory = ecmaVm->GetFactory(); 314514f5e3Sopenharmony_ci 324514f5e3Sopenharmony_ci // 1. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget. 334514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> constructor = GetConstructor(argv); 344514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv); 354514f5e3Sopenharmony_ci if (newTarget->IsUndefined()) { 364514f5e3Sopenharmony_ci newTarget = constructor; 374514f5e3Sopenharmony_ci } 384514f5e3Sopenharmony_ci 394514f5e3Sopenharmony_ci // Let numberFormat be ? OrdinaryCreateFromConstructor(newTarget, "%NumberFormatPrototype%", 404514f5e3Sopenharmony_ci // « [[InitializedNumberFormat]], [[Locale]], [[DataLocale]], [[NumberingSystem]], [[Style]], [[Unit]], 414514f5e3Sopenharmony_ci // [[UnitDisplay]], [[Currency]], [[CurrencyDisplay]], [[CurrencySign]], [[MinimumIntegerDigits]], 424514f5e3Sopenharmony_ci // [[MinimumFractionDigits]], [[MaximumFractionDigits]], [[MinimumSignificantDigits]], [[MaximumSignificantDigits]], 434514f5e3Sopenharmony_ci // [[RoundingType]], [[Notation]], [[CompactDisplay]], [[UseGrouping]], [[SignDisplay]], [[BoundFormat]] »). 444514f5e3Sopenharmony_ci JSHandle<JSObject> newObject = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget); 454514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 464514f5e3Sopenharmony_ci JSHandle<JSNumberFormat> numberFormat = JSHandle<JSNumberFormat>::Cast(newObject); 474514f5e3Sopenharmony_ci 484514f5e3Sopenharmony_ci // 3. Perform ? InitializeNumberFormat(numberFormat, locales, options). 494514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0); 504514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> options = GetCallArg(argv, 1); 514514f5e3Sopenharmony_ci JSNumberFormat::InitializeNumberFormat(thread, numberFormat, locales, options); 524514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 534514f5e3Sopenharmony_ci 544514f5e3Sopenharmony_ci // 4. Let this be the this value. 554514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisValue = GetThis(argv); 564514f5e3Sopenharmony_ci 574514f5e3Sopenharmony_ci // 5. If NewTarget is undefined and Type(this) is Object and ? InstanceofOperator(this, %NumberFormat%) is true, 584514f5e3Sopenharmony_ci // then 594514f5e3Sopenharmony_ci // a. Perform ? DefinePropertyOrThrow(this, %Intl%.[[FallbackSymbol]], PropertyDescriptor{ 604514f5e3Sopenharmony_ci // [[Value]]: numberFormat, [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }). 614514f5e3Sopenharmony_ci // b. Return this. 624514f5e3Sopenharmony_ci if (GetNewTarget(argv)->IsUndefined() && thisValue->IsJSObject()) { 634514f5e3Sopenharmony_ci bool isInstanceOf = JSFunction::OrdinaryHasInstance(thread, env->GetNumberFormatFunction(), thisValue); 644514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 654514f5e3Sopenharmony_ci if (isInstanceOf) { 664514f5e3Sopenharmony_ci PropertyDescriptor descriptor(thread, JSHandle<JSTaggedValue>::Cast(numberFormat), false, false, false); 674514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> key(thread, JSHandle<JSIntl>::Cast(env->GetIntlFunction())->GetFallbackSymbol()); 684514f5e3Sopenharmony_ci JSTaggedValue::DefinePropertyOrThrow(thread, thisValue, key, descriptor); 694514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 704514f5e3Sopenharmony_ci return thisValue.GetTaggedValue(); 714514f5e3Sopenharmony_ci } 724514f5e3Sopenharmony_ci } 734514f5e3Sopenharmony_ci 744514f5e3Sopenharmony_ci // 6. Return numberFormat. 754514f5e3Sopenharmony_ci return numberFormat.GetTaggedValue(); 764514f5e3Sopenharmony_ci} 774514f5e3Sopenharmony_ci 784514f5e3Sopenharmony_ci// 13.3.2 Intl.NumberFormat.supportedLocalesOf ( locales [ , options ] ) 794514f5e3Sopenharmony_ciJSTaggedValue BuiltinsNumberFormat::SupportedLocalesOf(EcmaRuntimeCallInfo *argv) 804514f5e3Sopenharmony_ci{ 814514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 824514f5e3Sopenharmony_ci BUILTINS_API_TRACE(thread, NumberFormat, SupportedLocalesOf); 834514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope scope(thread); 844514f5e3Sopenharmony_ci // 1. Let availableLocales be %NumberFormat%.[[AvailableLocales]]. 854514f5e3Sopenharmony_ci JSHandle<TaggedArray> availableLocales = JSNumberFormat::GetAvailableLocales(thread); 864514f5e3Sopenharmony_ci 874514f5e3Sopenharmony_ci // 2. Let requestedLocales be ? CanonicalizeLocaleList(locales). 884514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0); 894514f5e3Sopenharmony_ci JSHandle<TaggedArray> requestedLocales = intl::LocaleHelper::CanonicalizeLocaleList(thread, locales); 904514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 914514f5e3Sopenharmony_ci 924514f5e3Sopenharmony_ci // 3. Return ? SupportedLocales(availableLocales, requestedLocales, options). 934514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> options = GetCallArg(argv, 1); 944514f5e3Sopenharmony_ci JSHandle<JSArray> result = JSLocale::SupportedLocales(thread, availableLocales, requestedLocales, options); 954514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 964514f5e3Sopenharmony_ci return result.GetTaggedValue(); 974514f5e3Sopenharmony_ci} 984514f5e3Sopenharmony_ci 994514f5e3Sopenharmony_ci// 13.4.3 get Intl.NumberFormat.prototype.format 1004514f5e3Sopenharmony_ciJSTaggedValue BuiltinsNumberFormat::Format(EcmaRuntimeCallInfo *argv) 1014514f5e3Sopenharmony_ci{ 1024514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 1034514f5e3Sopenharmony_ci BUILTINS_API_TRACE(thread, NumberFormat, Format); 1044514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope scope(thread); 1054514f5e3Sopenharmony_ci 1064514f5e3Sopenharmony_ci // 1. Let nf be this value. 1074514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisValue = GetThis(argv); 1084514f5e3Sopenharmony_ci // 2. If Type(nf) is not Object, throw a TypeError exception. 1094514f5e3Sopenharmony_ci if (!thisValue->IsJSObject()) { 1104514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, "nf is not object", JSTaggedValue::Exception()); 1114514f5e3Sopenharmony_ci } 1124514f5e3Sopenharmony_ci // 3. Let nf be ? UnwrapNumberFormat(nf). 1134514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> nf = JSNumberFormat::UnwrapNumberFormat(thread, thisValue); 1144514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1154514f5e3Sopenharmony_ci if (nf->IsUndefined()) { 1164514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, "nf is not object", JSTaggedValue::Exception()); 1174514f5e3Sopenharmony_ci } 1184514f5e3Sopenharmony_ci 1194514f5e3Sopenharmony_ci JSHandle<JSNumberFormat> typpedNf = JSHandle<JSNumberFormat>::Cast(nf); 1204514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> boundFunc(thread, typpedNf->GetBoundFormat()); 1214514f5e3Sopenharmony_ci // 4. If nf.[[BoundFormat]] is undefined, then 1224514f5e3Sopenharmony_ci // a. Let F be a new built-in function object as defined in Number Format Functions (12.1.4). 1234514f5e3Sopenharmony_ci // b. Set F.[[NumberFormat]] to nf. 1244514f5e3Sopenharmony_ci // c. Set nf.[[BoundFormat]] to F. 1254514f5e3Sopenharmony_ci if (boundFunc->IsUndefined()) { 1264514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 1274514f5e3Sopenharmony_ci JSHandle<JSIntlBoundFunction> intlBoundFunc = factory->NewJSIntlBoundFunction( 1284514f5e3Sopenharmony_ci MethodIndex::BUILTINS_NUMBER_FORMAT_NUMBER_FORMAT_INTERNAL_FORMAT_NUMBER); 1294514f5e3Sopenharmony_ci intlBoundFunc->SetNumberFormat(thread, typpedNf); 1304514f5e3Sopenharmony_ci typpedNf->SetBoundFormat(thread, intlBoundFunc); 1314514f5e3Sopenharmony_ci } 1324514f5e3Sopenharmony_ci return typpedNf->GetBoundFormat(); 1334514f5e3Sopenharmony_ci} 1344514f5e3Sopenharmony_ci 1354514f5e3Sopenharmony_ci// 13.4.4 Intl.NumberFormat.prototype.formatToParts ( date ) 1364514f5e3Sopenharmony_ciJSTaggedValue BuiltinsNumberFormat::FormatToParts(EcmaRuntimeCallInfo *argv) 1374514f5e3Sopenharmony_ci{ 1384514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 1394514f5e3Sopenharmony_ci BUILTINS_API_TRACE(thread, NumberFormat, FormatToParts); 1404514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope scope(thread); 1414514f5e3Sopenharmony_ci // 1. Let nf be the this value. 1424514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> nf = GetThis(argv); 1434514f5e3Sopenharmony_ci // 2. Perform ? RequireInternalSlot(nf, [[InitializedNumberFormat]]). 1444514f5e3Sopenharmony_ci if (!nf->IsJSNumberFormat()) { 1454514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, "Is not JSNumberFormat", JSTaggedValue::Exception()); 1464514f5e3Sopenharmony_ci } 1474514f5e3Sopenharmony_ci // 3. Let x be ? ToNumeric(value). 1484514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> value = GetCallArg(argv, 0); 1494514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> x = JSTaggedValue::ToNumeric(thread, value); 1504514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1514514f5e3Sopenharmony_ci JSHandle<JSArray> result = 1524514f5e3Sopenharmony_ci JSNumberFormat::FormatNumericToParts(thread, JSHandle<JSNumberFormat>::Cast(nf), x.GetTaggedValue()); 1534514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1544514f5e3Sopenharmony_ci return result.GetTaggedValue(); 1554514f5e3Sopenharmony_ci} 1564514f5e3Sopenharmony_ci// 13.4.5 Intl.NumberFormat.prototype.resolvedOptions () 1574514f5e3Sopenharmony_ciJSTaggedValue BuiltinsNumberFormat::ResolvedOptions(EcmaRuntimeCallInfo *argv) 1584514f5e3Sopenharmony_ci{ 1594514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 1604514f5e3Sopenharmony_ci BUILTINS_API_TRACE(thread, NumberFormat, ResolvedOptions); 1614514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope scope(thread); 1624514f5e3Sopenharmony_ci // 1. Let nf be this value. 1634514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisValue = GetThis(argv); 1644514f5e3Sopenharmony_ci // 2. If Type(nf) is not Object, throw a TypeError exception. 1654514f5e3Sopenharmony_ci if (!thisValue->IsJSObject()) { 1664514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, "this is not object", JSTaggedValue::Exception()); 1674514f5e3Sopenharmony_ci } 1684514f5e3Sopenharmony_ci // 3. Let nf be ? UnwrapNumberFormat(nf). 1694514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> nf = JSNumberFormat::UnwrapNumberFormat(thread, thisValue); 1704514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1714514f5e3Sopenharmony_ci // Perform ? RequireInternalSlot(nf, [[InitializedNumberFormat]]). 1724514f5e3Sopenharmony_ci if (!nf->IsJSNumberFormat()) { 1734514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, "nf is not JSNumberFormat", JSTaggedValue::Exception()); 1744514f5e3Sopenharmony_ci } 1754514f5e3Sopenharmony_ci // 4. Let options be ! ObjectCreate(%ObjectPrototype%). 1764514f5e3Sopenharmony_ci auto ecmaVm = thread->GetEcmaVM(); 1774514f5e3Sopenharmony_ci JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv(); 1784514f5e3Sopenharmony_ci ObjectFactory *factory = ecmaVm->GetFactory(); 1794514f5e3Sopenharmony_ci JSHandle<JSFunction> ctor(env->GetObjectFunction()); 1804514f5e3Sopenharmony_ci JSHandle<JSObject> options(factory->NewJSObjectByConstructor(ctor)); 1814514f5e3Sopenharmony_ci 1824514f5e3Sopenharmony_ci // 5. For each row of Table 5, except the header row, in table order, do 1834514f5e3Sopenharmony_ci // Let p be the Property value of the current row. 1844514f5e3Sopenharmony_ci // Let v be the value of nf's internal slot whose name is the Internal Slot value of the current row. 1854514f5e3Sopenharmony_ci // If v is not undefined, then 1864514f5e3Sopenharmony_ci // Perform ! CreateDataPropertyOrThrow(options, p, v). 1874514f5e3Sopenharmony_ci JSNumberFormat::ResolvedOptions(thread, JSHandle<JSNumberFormat>::Cast(nf), options); 1884514f5e3Sopenharmony_ci return options.GetTaggedValue(); 1894514f5e3Sopenharmony_ci} 1904514f5e3Sopenharmony_ci 1914514f5e3Sopenharmony_ciJSTaggedValue BuiltinsNumberFormat::NumberFormatInternalFormatNumber(EcmaRuntimeCallInfo *argv) 1924514f5e3Sopenharmony_ci{ 1934514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 1944514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope scope(thread); 1954514f5e3Sopenharmony_ci JSHandle<JSIntlBoundFunction> intlBoundFunc = JSHandle<JSIntlBoundFunction>::Cast(GetConstructor(argv)); 1964514f5e3Sopenharmony_ci 1974514f5e3Sopenharmony_ci // 1. Let nf be F.[[NumberFormat]]. 1984514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> nf(thread, intlBoundFunc->GetNumberFormat()); 1994514f5e3Sopenharmony_ci // 2. Assert: Type(nf) is Object and nf has an [[InitializedNumberFormat]] internal slot. 2004514f5e3Sopenharmony_ci ASSERT(nf->IsJSObject() && nf->IsJSNumberFormat()); 2014514f5e3Sopenharmony_ci // 3. If value is not provided, let value be undefined. 2024514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> value = GetCallArg(argv, 0); 2034514f5e3Sopenharmony_ci // 4 Let x be ? ToNumeric(value). 2044514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> x = JSTaggedValue::ToNumeric(thread, value); 2054514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2064514f5e3Sopenharmony_ci // 5 Return ? FormatNumeric(nf, x). 2074514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> result = 2084514f5e3Sopenharmony_ci JSNumberFormat::FormatNumeric(thread, JSHandle<JSNumberFormat>::Cast(nf), x.GetTaggedValue()); 2094514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2104514f5e3Sopenharmony_ci return result.GetTaggedValue(); 2114514f5e3Sopenharmony_ci} 2124514f5e3Sopenharmony_ci} // namespace panda::ecmascript::builtins