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/js_number_format.h" 174514f5e3Sopenharmony_ci#include "ecmascript/ecma_context.h" 184514f5e3Sopenharmony_ci#include "ecmascript/js_function.h" 194514f5e3Sopenharmony_ci#include "ecmascript/object_factory-inl.h" 204514f5e3Sopenharmony_ci 214514f5e3Sopenharmony_cinamespace panda::ecmascript { 224514f5e3Sopenharmony_ci 234514f5e3Sopenharmony_ciconst std::vector<StyleOption> JSNumberFormat::STYLE_OPTION = { 244514f5e3Sopenharmony_ci StyleOption::DECIMAL, StyleOption::PERCENT, StyleOption::CURRENCY, StyleOption::UNIT 254514f5e3Sopenharmony_ci}; 264514f5e3Sopenharmony_ciconst std::vector<std::string> JSNumberFormat::STYLE_OPTION_NAME = { 274514f5e3Sopenharmony_ci "decimal", "percent", "currency", "unit" 284514f5e3Sopenharmony_ci}; 294514f5e3Sopenharmony_ci 304514f5e3Sopenharmony_ciconst std::vector<CurrencyDisplayOption> JSNumberFormat::CURRENCY_DISPLAY_OPTION = { 314514f5e3Sopenharmony_ci CurrencyDisplayOption::CODE, CurrencyDisplayOption::SYMBOL, 324514f5e3Sopenharmony_ci CurrencyDisplayOption::NARROWSYMBOL, CurrencyDisplayOption::NAME 334514f5e3Sopenharmony_ci}; 344514f5e3Sopenharmony_ciconst std::vector<std::string> JSNumberFormat::CURRENCY_DISPLAY_OPTION_NAME = { 354514f5e3Sopenharmony_ci "code", "symbol", "narrowSymbol", "name" 364514f5e3Sopenharmony_ci}; 374514f5e3Sopenharmony_ci 384514f5e3Sopenharmony_ciconst std::vector<CurrencySignOption> JSNumberFormat::CURRENCY_SIGN_OPTION = { 394514f5e3Sopenharmony_ci CurrencySignOption::STANDARD, CurrencySignOption::ACCOUNTING 404514f5e3Sopenharmony_ci}; 414514f5e3Sopenharmony_ciconst std::vector<std::string> JSNumberFormat::CURRENCY_SIGN_OPTION_NAME = {"standard", "accounting"}; 424514f5e3Sopenharmony_ci 434514f5e3Sopenharmony_ciconst std::vector<UnitDisplayOption> JSNumberFormat::UNIT_DISPLAY_OPTION = { 444514f5e3Sopenharmony_ci UnitDisplayOption::SHORT, UnitDisplayOption::NARROW, UnitDisplayOption::LONG 454514f5e3Sopenharmony_ci}; 464514f5e3Sopenharmony_ciconst std::vector<std::string> JSNumberFormat::UNIT_DISPLAY_OPTION_NAME = {"short", "narrow", "long"}; 474514f5e3Sopenharmony_ci 484514f5e3Sopenharmony_ciconst std::vector<LocaleMatcherOption> JSNumberFormat::LOCALE_MATCHER_OPTION = { 494514f5e3Sopenharmony_ci LocaleMatcherOption::LOOKUP, LocaleMatcherOption::BEST_FIT 504514f5e3Sopenharmony_ci}; 514514f5e3Sopenharmony_ciconst std::vector<std::string> JSNumberFormat::LOCALE_MATCHER_OPTION_NAME = {"lookup", "best fit"}; 524514f5e3Sopenharmony_ci 534514f5e3Sopenharmony_ciconst std::vector<NotationOption> JSNumberFormat::NOTATION_OPTION = { 544514f5e3Sopenharmony_ci NotationOption::STANDARD, NotationOption::SCIENTIFIC, 554514f5e3Sopenharmony_ci NotationOption::ENGINEERING, NotationOption::COMPACT 564514f5e3Sopenharmony_ci}; 574514f5e3Sopenharmony_ciconst std::vector<std::string> JSNumberFormat::NOTATION_OPTION_NAME = { 584514f5e3Sopenharmony_ci "standard", "scientific", "engineering", "compact" 594514f5e3Sopenharmony_ci}; 604514f5e3Sopenharmony_ci 614514f5e3Sopenharmony_ciconst std::vector<SignDisplayOption> JSNumberFormat::SIGN_DISPLAY_OPTION = { 624514f5e3Sopenharmony_ci SignDisplayOption::AUTO, SignDisplayOption::NEVER, 634514f5e3Sopenharmony_ci SignDisplayOption::ALWAYS, SignDisplayOption::EXCEPTZERO 644514f5e3Sopenharmony_ci}; 654514f5e3Sopenharmony_ciconst std::vector<std::string> JSNumberFormat::SIGN_DISPLAY_OPTION_NAME = { 664514f5e3Sopenharmony_ci "auto", "never", "always", "exceptZero" 674514f5e3Sopenharmony_ci}; 684514f5e3Sopenharmony_ci 694514f5e3Sopenharmony_ciconst std::vector<CompactDisplayOption> JSNumberFormat::COMPACT_DISPLAY_OPTION = { 704514f5e3Sopenharmony_ci CompactDisplayOption::SHORT, CompactDisplayOption::LONG 714514f5e3Sopenharmony_ci}; 724514f5e3Sopenharmony_ciconst std::vector<std::string> JSNumberFormat::COMPACT_DISPLAY_OPTION_NAME = {"short", "long"}; 734514f5e3Sopenharmony_ci 744514f5e3Sopenharmony_ciconst std::set<std::string> SANCTIONED_UNIT({ "acre", "bit", "byte", "celsius", "centimeter", "day", "degree", 754514f5e3Sopenharmony_ci "fahrenheit", "fluid-ounce", "foot", "gallon", "gigabit", "gigabyte", 764514f5e3Sopenharmony_ci "gram", "hectare", "hour", "inch", "kilobit", "kilobyte", "kilogram", 774514f5e3Sopenharmony_ci "kilometer", "liter", "megabit", "megabyte", "meter", "mile", 784514f5e3Sopenharmony_ci "mile-scandinavian", "millimeter", "milliliter", "millisecond", 794514f5e3Sopenharmony_ci "minute", "month", "ounce", "percent", "petabyte", "pound", "second", 804514f5e3Sopenharmony_ci "stone", "terabit", "terabyte", "week", "yard", "year" }); 814514f5e3Sopenharmony_ci 824514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> OptionToEcmaString(JSThread *thread, StyleOption style) 834514f5e3Sopenharmony_ci{ 844514f5e3Sopenharmony_ci JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined()); 854514f5e3Sopenharmony_ci auto globalConst = thread->GlobalConstants(); 864514f5e3Sopenharmony_ci switch (style) { 874514f5e3Sopenharmony_ci case StyleOption::DECIMAL: 884514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledDecimalString().GetTaggedValue()); 894514f5e3Sopenharmony_ci break; 904514f5e3Sopenharmony_ci case StyleOption::CURRENCY: 914514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledCurrencyString().GetTaggedValue()); 924514f5e3Sopenharmony_ci break; 934514f5e3Sopenharmony_ci case StyleOption::PERCENT: 944514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledPercentString().GetTaggedValue()); 954514f5e3Sopenharmony_ci break; 964514f5e3Sopenharmony_ci case StyleOption::UNIT: 974514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledUnitString().GetTaggedValue()); 984514f5e3Sopenharmony_ci break; 994514f5e3Sopenharmony_ci default: 1004514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 1014514f5e3Sopenharmony_ci UNREACHABLE(); 1024514f5e3Sopenharmony_ci } 1034514f5e3Sopenharmony_ci return result; 1044514f5e3Sopenharmony_ci} 1054514f5e3Sopenharmony_ci 1064514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> OptionToEcmaString(JSThread *thread, CurrencyDisplayOption currencyDisplay) 1074514f5e3Sopenharmony_ci{ 1084514f5e3Sopenharmony_ci JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined()); 1094514f5e3Sopenharmony_ci auto globalConst = thread->GlobalConstants(); 1104514f5e3Sopenharmony_ci switch (currencyDisplay) { 1114514f5e3Sopenharmony_ci case CurrencyDisplayOption::CODE: 1124514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledCodeString().GetTaggedValue()); 1134514f5e3Sopenharmony_ci break; 1144514f5e3Sopenharmony_ci case CurrencyDisplayOption::SYMBOL: 1154514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledSymbolString().GetTaggedValue()); 1164514f5e3Sopenharmony_ci break; 1174514f5e3Sopenharmony_ci case CurrencyDisplayOption::NARROWSYMBOL: 1184514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledNarrowSymbolString().GetTaggedValue()); 1194514f5e3Sopenharmony_ci break; 1204514f5e3Sopenharmony_ci case CurrencyDisplayOption::NAME: 1214514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledNameString().GetTaggedValue()); 1224514f5e3Sopenharmony_ci break; 1234514f5e3Sopenharmony_ci default: 1244514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 1254514f5e3Sopenharmony_ci UNREACHABLE(); 1264514f5e3Sopenharmony_ci } 1274514f5e3Sopenharmony_ci return result; 1284514f5e3Sopenharmony_ci} 1294514f5e3Sopenharmony_ci 1304514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> OptionToEcmaString(JSThread *thread, CurrencySignOption currencySign) 1314514f5e3Sopenharmony_ci{ 1324514f5e3Sopenharmony_ci auto globalConst = thread->GlobalConstants(); 1334514f5e3Sopenharmony_ci JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined()); 1344514f5e3Sopenharmony_ci switch (currencySign) { 1354514f5e3Sopenharmony_ci case CurrencySignOption::STANDARD: 1364514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledStandardString().GetTaggedValue()); 1374514f5e3Sopenharmony_ci break; 1384514f5e3Sopenharmony_ci case CurrencySignOption::ACCOUNTING: 1394514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledAccountingString().GetTaggedValue()); 1404514f5e3Sopenharmony_ci break; 1414514f5e3Sopenharmony_ci default: 1424514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 1434514f5e3Sopenharmony_ci UNREACHABLE(); 1444514f5e3Sopenharmony_ci } 1454514f5e3Sopenharmony_ci return result; 1464514f5e3Sopenharmony_ci} 1474514f5e3Sopenharmony_ci 1484514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> OptionToEcmaString(JSThread *thread, UnitDisplayOption unitDisplay) 1494514f5e3Sopenharmony_ci{ 1504514f5e3Sopenharmony_ci JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined()); 1514514f5e3Sopenharmony_ci auto globalConst = thread->GlobalConstants(); 1524514f5e3Sopenharmony_ci switch (unitDisplay) { 1534514f5e3Sopenharmony_ci case UnitDisplayOption::SHORT: 1544514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledShortString().GetTaggedValue()); 1554514f5e3Sopenharmony_ci break; 1564514f5e3Sopenharmony_ci case UnitDisplayOption::NARROW: 1574514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledNarrowString().GetTaggedValue()); 1584514f5e3Sopenharmony_ci break; 1594514f5e3Sopenharmony_ci case UnitDisplayOption::LONG: 1604514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledLongString().GetTaggedValue()); 1614514f5e3Sopenharmony_ci break; 1624514f5e3Sopenharmony_ci default: 1634514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 1644514f5e3Sopenharmony_ci UNREACHABLE(); 1654514f5e3Sopenharmony_ci } 1664514f5e3Sopenharmony_ci return result; 1674514f5e3Sopenharmony_ci} 1684514f5e3Sopenharmony_ci 1694514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> OptionToEcmaString(JSThread *thread, NotationOption notation) 1704514f5e3Sopenharmony_ci{ 1714514f5e3Sopenharmony_ci JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined()); 1724514f5e3Sopenharmony_ci auto globalConst = thread->GlobalConstants(); 1734514f5e3Sopenharmony_ci switch (notation) { 1744514f5e3Sopenharmony_ci case NotationOption::STANDARD: 1754514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledStandardString().GetTaggedValue()); 1764514f5e3Sopenharmony_ci break; 1774514f5e3Sopenharmony_ci case NotationOption::SCIENTIFIC: 1784514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledScientificString().GetTaggedValue()); 1794514f5e3Sopenharmony_ci break; 1804514f5e3Sopenharmony_ci case NotationOption::ENGINEERING: 1814514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledEngineeringString().GetTaggedValue()); 1824514f5e3Sopenharmony_ci break; 1834514f5e3Sopenharmony_ci case NotationOption::COMPACT: 1844514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledCompactString().GetTaggedValue()); 1854514f5e3Sopenharmony_ci break; 1864514f5e3Sopenharmony_ci default: 1874514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 1884514f5e3Sopenharmony_ci UNREACHABLE(); 1894514f5e3Sopenharmony_ci } 1904514f5e3Sopenharmony_ci return result; 1914514f5e3Sopenharmony_ci} 1924514f5e3Sopenharmony_ci 1934514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> OptionToEcmaString(JSThread *thread, CompactDisplayOption compactDisplay) 1944514f5e3Sopenharmony_ci{ 1954514f5e3Sopenharmony_ci JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined()); 1964514f5e3Sopenharmony_ci auto globalConst = thread->GlobalConstants(); 1974514f5e3Sopenharmony_ci switch (compactDisplay) { 1984514f5e3Sopenharmony_ci case CompactDisplayOption::SHORT: 1994514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledShortString().GetTaggedValue()); 2004514f5e3Sopenharmony_ci break; 2014514f5e3Sopenharmony_ci case CompactDisplayOption::LONG: 2024514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledLongString().GetTaggedValue()); 2034514f5e3Sopenharmony_ci break; 2044514f5e3Sopenharmony_ci default: 2054514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 2064514f5e3Sopenharmony_ci UNREACHABLE(); 2074514f5e3Sopenharmony_ci } 2084514f5e3Sopenharmony_ci return result; 2094514f5e3Sopenharmony_ci} 2104514f5e3Sopenharmony_ci 2114514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> OptionToEcmaString(JSThread *thread, SignDisplayOption signDisplay) 2124514f5e3Sopenharmony_ci{ 2134514f5e3Sopenharmony_ci JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined()); 2144514f5e3Sopenharmony_ci auto globalConst = thread->GlobalConstants(); 2154514f5e3Sopenharmony_ci switch (signDisplay) { 2164514f5e3Sopenharmony_ci case SignDisplayOption::AUTO: 2174514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledAutoString().GetTaggedValue()); 2184514f5e3Sopenharmony_ci break; 2194514f5e3Sopenharmony_ci case SignDisplayOption::ALWAYS: 2204514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledAlwaysString().GetTaggedValue()); 2214514f5e3Sopenharmony_ci break; 2224514f5e3Sopenharmony_ci case SignDisplayOption::NEVER: 2234514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledNeverString().GetTaggedValue()); 2244514f5e3Sopenharmony_ci break; 2254514f5e3Sopenharmony_ci case SignDisplayOption::EXCEPTZERO: 2264514f5e3Sopenharmony_ci result.Update(globalConst->GetHandledExceptZeroString().GetTaggedValue()); 2274514f5e3Sopenharmony_ci break; 2284514f5e3Sopenharmony_ci default: 2294514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 2304514f5e3Sopenharmony_ci UNREACHABLE(); 2314514f5e3Sopenharmony_ci } 2324514f5e3Sopenharmony_ci return result; 2334514f5e3Sopenharmony_ci} 2344514f5e3Sopenharmony_ci 2354514f5e3Sopenharmony_ciicu::MeasureUnit ToMeasureUnit(const std::string &sanctionedUnit) 2364514f5e3Sopenharmony_ci{ 2374514f5e3Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 2384514f5e3Sopenharmony_ci // Get All ICU measure unit 2394514f5e3Sopenharmony_ci int32_t total = icu::MeasureUnit::getAvailable(nullptr, 0, status); 2404514f5e3Sopenharmony_ci status = U_ZERO_ERROR; 2414514f5e3Sopenharmony_ci std::vector<icu::MeasureUnit> units(total); 2424514f5e3Sopenharmony_ci icu::MeasureUnit::getAvailable(units.data(), total, status); 2434514f5e3Sopenharmony_ci ASSERT(U_SUCCESS(status)); 2444514f5e3Sopenharmony_ci 2454514f5e3Sopenharmony_ci // Find measure unit according to sanctioned unit 2464514f5e3Sopenharmony_ci // then return measure unit 2474514f5e3Sopenharmony_ci for (auto &unit : units) { 2484514f5e3Sopenharmony_ci if (std::strcmp(sanctionedUnit.c_str(), unit.getSubtype()) == 0) { 2494514f5e3Sopenharmony_ci return unit; 2504514f5e3Sopenharmony_ci } 2514514f5e3Sopenharmony_ci } 2524514f5e3Sopenharmony_ci return icu::MeasureUnit(); 2534514f5e3Sopenharmony_ci} 2544514f5e3Sopenharmony_ci 2554514f5e3Sopenharmony_ci// ecma402 #sec-issanctionedsimpleunitidentifier 2564514f5e3Sopenharmony_cibool IsSanctionedSimpleUnitIdentifier(const std::string &unit) 2574514f5e3Sopenharmony_ci{ 2584514f5e3Sopenharmony_ci // 1. If unitIdentifier is listed in sanctioned unit set, return true. 2594514f5e3Sopenharmony_ci auto it = SANCTIONED_UNIT.find(unit); 2604514f5e3Sopenharmony_ci if (it != SANCTIONED_UNIT.end()) { 2614514f5e3Sopenharmony_ci return true; 2624514f5e3Sopenharmony_ci } 2634514f5e3Sopenharmony_ci 2644514f5e3Sopenharmony_ci // 2. Else, Return false. 2654514f5e3Sopenharmony_ci return false; 2664514f5e3Sopenharmony_ci} 2674514f5e3Sopenharmony_ci 2684514f5e3Sopenharmony_ci// 6.5.1 IsWellFormedUnitIdentifier ( unitIdentifier ) 2694514f5e3Sopenharmony_cibool IsWellFormedUnitIdentifier(const std::string &unit, icu::MeasureUnit &icuUnit, icu::MeasureUnit &icuPerUnit) 2704514f5e3Sopenharmony_ci{ 2714514f5e3Sopenharmony_ci // 1. If the result of IsSanctionedSimpleUnitIdentifier(unitIdentifier) is true, then 2724514f5e3Sopenharmony_ci // a. Return true. 2734514f5e3Sopenharmony_ci icu::MeasureUnit result = icu::MeasureUnit(); 2744514f5e3Sopenharmony_ci icu::MeasureUnit emptyUnit = icu::MeasureUnit(); 2754514f5e3Sopenharmony_ci auto pos = unit.find("-per-"); 2764514f5e3Sopenharmony_ci if (IsSanctionedSimpleUnitIdentifier(unit) && pos == std::string::npos) { 2774514f5e3Sopenharmony_ci result = ToMeasureUnit(unit); 2784514f5e3Sopenharmony_ci icuUnit = result; 2794514f5e3Sopenharmony_ci icuPerUnit = emptyUnit; 2804514f5e3Sopenharmony_ci return true; 2814514f5e3Sopenharmony_ci } 2824514f5e3Sopenharmony_ci 2834514f5e3Sopenharmony_ci // 2. If the substring "-per-" does not occur exactly once in unitIdentifier, 2844514f5e3Sopenharmony_ci // a. then false 2854514f5e3Sopenharmony_ci size_t afterPos = pos + JSNumberFormat::PERUNIT_STRING; 2864514f5e3Sopenharmony_ci if (pos == std::string::npos || unit.find("-per-", afterPos) != std::string::npos) { 2874514f5e3Sopenharmony_ci return false; 2884514f5e3Sopenharmony_ci } 2894514f5e3Sopenharmony_ci 2904514f5e3Sopenharmony_ci // 3. Let numerator be the substring of unitIdentifier from the beginning to just before "-per-". 2914514f5e3Sopenharmony_ci std::string numerator = unit.substr(0, pos); 2924514f5e3Sopenharmony_ci // 4. If the result of IsSanctionedUnitIdentifier(numerator) is false, then 2934514f5e3Sopenharmony_ci // a. return false 2944514f5e3Sopenharmony_ci if (IsSanctionedSimpleUnitIdentifier(numerator)) { 2954514f5e3Sopenharmony_ci result = ToMeasureUnit(numerator); 2964514f5e3Sopenharmony_ci } else { 2974514f5e3Sopenharmony_ci return false; 2984514f5e3Sopenharmony_ci } 2994514f5e3Sopenharmony_ci 3004514f5e3Sopenharmony_ci // 5. Let denominator be the substring of unitIdentifier from just after "-per-" to the end. 3014514f5e3Sopenharmony_ci std::string denominator = unit.substr(pos + JSNumberFormat::PERUNIT_STRING); 3024514f5e3Sopenharmony_ci 3034514f5e3Sopenharmony_ci // 6. If the result of IsSanctionedUnitIdentifier(denominator) is false, then 3044514f5e3Sopenharmony_ci // a. Return false 3054514f5e3Sopenharmony_ci icu::MeasureUnit perResult = icu::MeasureUnit(); 3064514f5e3Sopenharmony_ci if (IsSanctionedSimpleUnitIdentifier(denominator)) { 3074514f5e3Sopenharmony_ci perResult = ToMeasureUnit(denominator); 3084514f5e3Sopenharmony_ci } else { 3094514f5e3Sopenharmony_ci return false; 3104514f5e3Sopenharmony_ci } 3114514f5e3Sopenharmony_ci 3124514f5e3Sopenharmony_ci // 7. Return true. 3134514f5e3Sopenharmony_ci icuUnit = result; 3144514f5e3Sopenharmony_ci icuPerUnit = perResult; 3154514f5e3Sopenharmony_ci return true; 3164514f5e3Sopenharmony_ci} 3174514f5e3Sopenharmony_ci 3184514f5e3Sopenharmony_ci// 12.1.13 SetNumberFormatUnitOptions ( intlObj, options ) 3194514f5e3Sopenharmony_ciFractionDigitsOption SetNumberFormatUnitOptions(JSThread *thread, 3204514f5e3Sopenharmony_ci const JSHandle<JSNumberFormat> &numberFormat, 3214514f5e3Sopenharmony_ci const JSHandle<JSObject> &optionsObject, 3224514f5e3Sopenharmony_ci icu::number::LocalizedNumberFormatter *icuNumberFormatter) 3234514f5e3Sopenharmony_ci{ 3244514f5e3Sopenharmony_ci auto globalConst = thread->GlobalConstants(); 3254514f5e3Sopenharmony_ci FractionDigitsOption fractionDigitsOption; 3264514f5e3Sopenharmony_ci // 3. Let style be ? GetOption(options, "style", "string", « "decimal", "percent", "currency", "unit" », "decimal"). 3274514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> property = globalConst->GetHandledStyleString(); 3284514f5e3Sopenharmony_ci auto style = JSLocale::GetOptionOfString<StyleOption>( 3294514f5e3Sopenharmony_ci thread, optionsObject, property, 3304514f5e3Sopenharmony_ci JSNumberFormat::STYLE_OPTION, JSNumberFormat::STYLE_OPTION_NAME, 3314514f5e3Sopenharmony_ci StyleOption::DECIMAL); 3324514f5e3Sopenharmony_ci RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, fractionDigitsOption); 3334514f5e3Sopenharmony_ci 3344514f5e3Sopenharmony_ci // 4. Set intlObj.[[Style]] to style. 3354514f5e3Sopenharmony_ci numberFormat->SetStyle(style); 3364514f5e3Sopenharmony_ci 3374514f5e3Sopenharmony_ci // 5. Let currency be ? GetOption(options, "currency", "string", undefined, undefined). 3384514f5e3Sopenharmony_ci property = globalConst->GetHandledCurrencyString(); 3394514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> undefinedValue(thread, JSTaggedValue::Undefined()); 3404514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> currency = 3414514f5e3Sopenharmony_ci JSLocale::GetOption(thread, optionsObject, property, OptionType::STRING, undefinedValue, undefinedValue); 3424514f5e3Sopenharmony_ci RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, fractionDigitsOption); 3434514f5e3Sopenharmony_ci 3444514f5e3Sopenharmony_ci // 6. If currency is not undefined, then 3454514f5e3Sopenharmony_ci // a. If the result of IsWellFormedCurrencyCode(currency) is false, throw a RangeError exception. 3464514f5e3Sopenharmony_ci if (!currency->IsUndefined()) { 3474514f5e3Sopenharmony_ci JSHandle<EcmaString> currencyStr = JSHandle<EcmaString>::Cast(currency); 3484514f5e3Sopenharmony_ci if (EcmaStringAccessor(currencyStr).IsUtf16()) { 3494514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "not a utf-8", fractionDigitsOption); 3504514f5e3Sopenharmony_ci } 3514514f5e3Sopenharmony_ci std::string currencyCStr = intl::LocaleHelper::ConvertToStdString(currencyStr); 3524514f5e3Sopenharmony_ci if (!JSLocale::IsWellFormedCurrencyCode(currencyCStr)) { 3534514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "not a wellformed code", fractionDigitsOption); 3544514f5e3Sopenharmony_ci } 3554514f5e3Sopenharmony_ci } else { 3564514f5e3Sopenharmony_ci // 7. If style is "currency" and currency is undefined, throw a TypeError exception. 3574514f5e3Sopenharmony_ci if (style == StyleOption::CURRENCY) { 3584514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, "style is currency but currency is undefined", fractionDigitsOption); 3594514f5e3Sopenharmony_ci } 3604514f5e3Sopenharmony_ci } 3614514f5e3Sopenharmony_ci 3624514f5e3Sopenharmony_ci // 8. Let currencyDisplay be ? GetOption(options, "currencyDisplay", "string", 3634514f5e3Sopenharmony_ci // « "code", "symbol", "narrowSymbol", "name" », "symbol"). 3644514f5e3Sopenharmony_ci property = globalConst->GetHandledCurrencyDisplayString(); 3654514f5e3Sopenharmony_ci auto currencyDisplay = JSLocale::GetOptionOfString<CurrencyDisplayOption>( 3664514f5e3Sopenharmony_ci thread, optionsObject, property, 3674514f5e3Sopenharmony_ci JSNumberFormat::CURRENCY_DISPLAY_OPTION, JSNumberFormat::CURRENCY_DISPLAY_OPTION_NAME, 3684514f5e3Sopenharmony_ci CurrencyDisplayOption::SYMBOL); 3694514f5e3Sopenharmony_ci RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, fractionDigitsOption); 3704514f5e3Sopenharmony_ci numberFormat->SetCurrencyDisplay(currencyDisplay); 3714514f5e3Sopenharmony_ci 3724514f5e3Sopenharmony_ci // 9. Let currencySign be ? GetOption(options, "currencySign", "string", « "standard", "accounting" », "standard"). 3734514f5e3Sopenharmony_ci property = globalConst->GetHandledCurrencySignString(); 3744514f5e3Sopenharmony_ci auto currencySign = JSLocale::GetOptionOfString<CurrencySignOption>( 3754514f5e3Sopenharmony_ci thread, optionsObject, property, 3764514f5e3Sopenharmony_ci JSNumberFormat::CURRENCY_SIGN_OPTION, JSNumberFormat::CURRENCY_SIGN_OPTION_NAME, 3774514f5e3Sopenharmony_ci CurrencySignOption::STANDARD); 3784514f5e3Sopenharmony_ci RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, fractionDigitsOption); 3794514f5e3Sopenharmony_ci numberFormat->SetCurrencySign(currencySign); 3804514f5e3Sopenharmony_ci 3814514f5e3Sopenharmony_ci // 10. Let unit be ? GetOption(options, "unit", "string", undefined, undefined). 3824514f5e3Sopenharmony_ci property = globalConst->GetHandledUnitString(); 3834514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> unit = 3844514f5e3Sopenharmony_ci JSLocale::GetOption(thread, optionsObject, property, OptionType::STRING, undefinedValue, undefinedValue); 3854514f5e3Sopenharmony_ci RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, fractionDigitsOption); 3864514f5e3Sopenharmony_ci numberFormat->SetUnit(thread, unit); 3874514f5e3Sopenharmony_ci 3884514f5e3Sopenharmony_ci // 11. If unit is not undefined, then 3894514f5e3Sopenharmony_ci // If the result of IsWellFormedUnitIdentifier(unit) is false, throw a RangeError exception. 3904514f5e3Sopenharmony_ci icu::MeasureUnit icuUnit; 3914514f5e3Sopenharmony_ci icu::MeasureUnit icuPerUnit; 3924514f5e3Sopenharmony_ci if (!unit->IsUndefined()) { 3934514f5e3Sopenharmony_ci JSHandle<EcmaString> unitStr = JSHandle<EcmaString>::Cast(unit); 3944514f5e3Sopenharmony_ci if (EcmaStringAccessor(unitStr).IsUtf16()) { 3954514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "Unit input is illegal", fractionDigitsOption); 3964514f5e3Sopenharmony_ci } 3974514f5e3Sopenharmony_ci std::string str = intl::LocaleHelper::ConvertToStdString(unitStr); 3984514f5e3Sopenharmony_ci if (!IsWellFormedUnitIdentifier(str, icuUnit, icuPerUnit)) { 3994514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "Unit input is illegal", fractionDigitsOption); 4004514f5e3Sopenharmony_ci } 4014514f5e3Sopenharmony_ci } else { 4024514f5e3Sopenharmony_ci // 15.12. if style is "unit" and unit is undefined, throw a TypeError exception. 4034514f5e3Sopenharmony_ci if (style == StyleOption::UNIT) { 4044514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, "style is unit but unit is undefined", fractionDigitsOption); 4054514f5e3Sopenharmony_ci } 4064514f5e3Sopenharmony_ci } 4074514f5e3Sopenharmony_ci 4084514f5e3Sopenharmony_ci // 13. Let unitDisplay be ? GetOption(options, "unitDisplay", "string", « "short", "narrow", "long" », "short"). 4094514f5e3Sopenharmony_ci property = globalConst->GetHandledUnitDisplayString(); 4104514f5e3Sopenharmony_ci auto unitDisplay = JSLocale::GetOptionOfString<UnitDisplayOption>( 4114514f5e3Sopenharmony_ci thread, optionsObject, property, 4124514f5e3Sopenharmony_ci JSNumberFormat::UNIT_DISPLAY_OPTION, JSNumberFormat::UNIT_DISPLAY_OPTION_NAME, 4134514f5e3Sopenharmony_ci UnitDisplayOption::SHORT); 4144514f5e3Sopenharmony_ci RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, fractionDigitsOption); 4154514f5e3Sopenharmony_ci numberFormat->SetUnitDisplay(unitDisplay); 4164514f5e3Sopenharmony_ci 4174514f5e3Sopenharmony_ci // 14. If style is "currency", then 4184514f5e3Sopenharmony_ci // a. Let currency be the result of converting currency to upper case as specified in 6.1. 4194514f5e3Sopenharmony_ci // b. Set intlObj.[[Currency]] to currency. 4204514f5e3Sopenharmony_ci // c. Set intlObj.[[CurrencyDisplay]] to currencyDisplay. 4214514f5e3Sopenharmony_ci // d. Set intlObj.[[CurrencySign]] to currencySign. 4224514f5e3Sopenharmony_ci icu::UnicodeString currencyUStr; 4234514f5e3Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 4244514f5e3Sopenharmony_ci if (style == StyleOption::CURRENCY) { 4254514f5e3Sopenharmony_ci JSHandle<EcmaString> currencyStr = JSHandle<EcmaString>::Cast(currency); 4264514f5e3Sopenharmony_ci std::string currencyCStr = intl::LocaleHelper::ConvertToStdString(currencyStr); 4274514f5e3Sopenharmony_ci std::transform(currencyCStr.begin(), currencyCStr.end(), currencyCStr.begin(), toupper); 4284514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 4294514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> currencyValue = JSHandle<JSTaggedValue>::Cast(factory->NewFromStdString(currencyCStr)); 4304514f5e3Sopenharmony_ci numberFormat->SetCurrency(thread, currencyValue); 4314514f5e3Sopenharmony_ci currencyUStr = currencyCStr.c_str(); 4324514f5e3Sopenharmony_ci if (!currencyUStr.isEmpty()) { // NOLINT(readability-implicit-bool-conversion) 4334514f5e3Sopenharmony_ci *icuNumberFormatter = icuNumberFormatter->unit(icu::CurrencyUnit(currencyUStr.getBuffer(), status)); 4344514f5e3Sopenharmony_ci ASSERT(U_SUCCESS(status)); 4354514f5e3Sopenharmony_ci UNumberUnitWidth uNumberUnitWidth; 4364514f5e3Sopenharmony_ci // Trans currencyDisplayOption to ICU format number display option 4374514f5e3Sopenharmony_ci switch (currencyDisplay) { 4384514f5e3Sopenharmony_ci case CurrencyDisplayOption::CODE: 4394514f5e3Sopenharmony_ci uNumberUnitWidth = UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE; 4404514f5e3Sopenharmony_ci break; 4414514f5e3Sopenharmony_ci case CurrencyDisplayOption::SYMBOL: 4424514f5e3Sopenharmony_ci uNumberUnitWidth = UNumberUnitWidth::UNUM_UNIT_WIDTH_SHORT; 4434514f5e3Sopenharmony_ci break; 4444514f5e3Sopenharmony_ci case CurrencyDisplayOption::NARROWSYMBOL: 4454514f5e3Sopenharmony_ci uNumberUnitWidth = UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW; 4464514f5e3Sopenharmony_ci break; 4474514f5e3Sopenharmony_ci case CurrencyDisplayOption::NAME: 4484514f5e3Sopenharmony_ci uNumberUnitWidth = UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME; 4494514f5e3Sopenharmony_ci break; 4504514f5e3Sopenharmony_ci default: 4514514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 4524514f5e3Sopenharmony_ci UNREACHABLE(); 4534514f5e3Sopenharmony_ci } 4544514f5e3Sopenharmony_ci *icuNumberFormatter = icuNumberFormatter->unitWidth(uNumberUnitWidth); 4554514f5e3Sopenharmony_ci } 4564514f5e3Sopenharmony_ci } 4574514f5e3Sopenharmony_ci 4584514f5e3Sopenharmony_ci // 15. If style is "unit", then 4594514f5e3Sopenharmony_ci // if unit is not undefiend set unit to LocalizedNumberFormatter 4604514f5e3Sopenharmony_ci // then if perunit is not undefiend set perunit to LocalizedNumberFormatter 4614514f5e3Sopenharmony_ci if (style == StyleOption::UNIT) { 4624514f5e3Sopenharmony_ci icu::MeasureUnit emptyUnit = icu::MeasureUnit(); 4634514f5e3Sopenharmony_ci if (icuUnit != emptyUnit) { // NOLINT(readability-implicit-bool-conversion) 4644514f5e3Sopenharmony_ci *icuNumberFormatter = icuNumberFormatter->unit(icuUnit); 4654514f5e3Sopenharmony_ci } 4664514f5e3Sopenharmony_ci if (icuPerUnit != emptyUnit) { // NOLINT(readability-implicit-bool-conversion) 4674514f5e3Sopenharmony_ci *icuNumberFormatter = icuNumberFormatter->perUnit(icuPerUnit); 4684514f5e3Sopenharmony_ci } 4694514f5e3Sopenharmony_ci } 4704514f5e3Sopenharmony_ci 4714514f5e3Sopenharmony_ci // 17. If style is "currency", then 4724514f5e3Sopenharmony_ci // a. Let cDigits be CurrencyDigits(currency). 4734514f5e3Sopenharmony_ci // b. Let mnfdDefault be cDigits. 4744514f5e3Sopenharmony_ci // c. Let mxfdDefault be cDigits. 4754514f5e3Sopenharmony_ci if (style == StyleOption::CURRENCY) { 4764514f5e3Sopenharmony_ci int32_t cDigits = JSNumberFormat::CurrencyDigits(currencyUStr); 4774514f5e3Sopenharmony_ci fractionDigitsOption.mnfdDefault = cDigits; 4784514f5e3Sopenharmony_ci fractionDigitsOption.mxfdDefault = cDigits; 4794514f5e3Sopenharmony_ci } else { 4804514f5e3Sopenharmony_ci // 18. Else, 4814514f5e3Sopenharmony_ci // a. Let mnfdDefault be 0. 4824514f5e3Sopenharmony_ci // b. If style is "percent", then 4834514f5e3Sopenharmony_ci // i. Let mxfdDefault be 0. 4844514f5e3Sopenharmony_ci // c. else, 4854514f5e3Sopenharmony_ci // i. Let mxfdDefault be 3. 4864514f5e3Sopenharmony_ci fractionDigitsOption.mnfdDefault = 0; 4874514f5e3Sopenharmony_ci if (style == StyleOption::PERCENT) { 4884514f5e3Sopenharmony_ci fractionDigitsOption.mxfdDefault = 0; 4894514f5e3Sopenharmony_ci } else { 4904514f5e3Sopenharmony_ci fractionDigitsOption.mxfdDefault = 3; // Max decimal precision is 3 4914514f5e3Sopenharmony_ci } 4924514f5e3Sopenharmony_ci } 4934514f5e3Sopenharmony_ci return fractionDigitsOption; 4944514f5e3Sopenharmony_ci} 4954514f5e3Sopenharmony_ci 4964514f5e3Sopenharmony_ci// 12.1.2 InitializeNumberFormat ( numberFormat, locales, options ) 4974514f5e3Sopenharmony_ci// NOLINTNEXTLINE(readability-function-size) 4984514f5e3Sopenharmony_civoid JSNumberFormat::InitializeNumberFormat(JSThread *thread, const JSHandle<JSNumberFormat> &numberFormat, 4994514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &locales, 5004514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &options, 5014514f5e3Sopenharmony_ci bool forIcuCache) 5024514f5e3Sopenharmony_ci{ 5034514f5e3Sopenharmony_ci EcmaVM *ecmaVm = thread->GetEcmaVM(); 5044514f5e3Sopenharmony_ci ObjectFactory *factory = ecmaVm->GetFactory(); 5054514f5e3Sopenharmony_ci // 1. Let requestedLocales be ? CanonicalizeLocaleList(locales). 5064514f5e3Sopenharmony_ci JSHandle<TaggedArray> requestedLocales = intl::LocaleHelper::CanonicalizeLocaleList(thread, locales); 5074514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 5084514f5e3Sopenharmony_ci // 2. If options is undefined, then 5094514f5e3Sopenharmony_ci // a. Let options be ObjectCreate(null). 5104514f5e3Sopenharmony_ci // 3. Else, 5114514f5e3Sopenharmony_ci // a. Let options be ? ToObject(options). 5124514f5e3Sopenharmony_ci JSHandle<JSObject> optionsObject; 5134514f5e3Sopenharmony_ci if (options->IsUndefined()) { 5144514f5e3Sopenharmony_ci optionsObject = factory->CreateNullJSObject(); 5154514f5e3Sopenharmony_ci } else { 5164514f5e3Sopenharmony_ci optionsObject = JSTaggedValue::ToObject(thread, options); 5174514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 5184514f5e3Sopenharmony_ci } 5194514f5e3Sopenharmony_ci 5204514f5e3Sopenharmony_ci auto globalConst = thread->GlobalConstants(); 5214514f5e3Sopenharmony_ci // 5. Let matcher be ? GetOption(options, "localeMatcher", "string", « "lookup", "best fit" », "best fit"). 5224514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> property = globalConst->GetHandledLocaleMatcherString(); 5234514f5e3Sopenharmony_ci auto matcher = JSLocale::GetOptionOfString<LocaleMatcherOption>( 5244514f5e3Sopenharmony_ci thread, optionsObject, property, 5254514f5e3Sopenharmony_ci JSNumberFormat::LOCALE_MATCHER_OPTION, JSNumberFormat::LOCALE_MATCHER_OPTION_NAME, 5264514f5e3Sopenharmony_ci LocaleMatcherOption::BEST_FIT); 5274514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 5284514f5e3Sopenharmony_ci 5294514f5e3Sopenharmony_ci // 7. Let numberingSystem be ? GetOption(options, "numberingSystem", "string", undefined, undefined). 5304514f5e3Sopenharmony_ci property = globalConst->GetHandledNumberingSystemString(); 5314514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> undefinedValue(thread, JSTaggedValue::Undefined()); 5324514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> numberingSystemTaggedValue = 5334514f5e3Sopenharmony_ci JSLocale::GetOption(thread, optionsObject, property, OptionType::STRING, undefinedValue, undefinedValue); 5344514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 5354514f5e3Sopenharmony_ci numberFormat->SetNumberingSystem(thread, numberingSystemTaggedValue); 5364514f5e3Sopenharmony_ci 5374514f5e3Sopenharmony_ci // 8. If numberingSystem is not undefined, then 5384514f5e3Sopenharmony_ci // a. If numberingSystem does not match the Unicode Locale Identifier type nonterminal, 5394514f5e3Sopenharmony_ci // throw a RangeError exception. `(3*8alphanum) *("-" (3*8alphanum))` 5404514f5e3Sopenharmony_ci std::string numberingSystemStr; 5414514f5e3Sopenharmony_ci if (!numberingSystemTaggedValue->IsUndefined()) { 5424514f5e3Sopenharmony_ci JSHandle<EcmaString> numberingSystemEcmaString = JSHandle<EcmaString>::Cast(numberingSystemTaggedValue); 5434514f5e3Sopenharmony_ci if (EcmaStringAccessor(numberingSystemEcmaString).IsUtf16()) { 5444514f5e3Sopenharmony_ci THROW_ERROR(thread, ErrorType::RANGE_ERROR, "invalid numberingSystem"); 5454514f5e3Sopenharmony_ci } 5464514f5e3Sopenharmony_ci numberingSystemStr = intl::LocaleHelper::ConvertToStdString(numberingSystemEcmaString); 5474514f5e3Sopenharmony_ci if (!JSLocale::IsNormativeNumberingSystem(numberingSystemStr)) { 5484514f5e3Sopenharmony_ci THROW_ERROR(thread, ErrorType::RANGE_ERROR, "invalid numberingSystem"); 5494514f5e3Sopenharmony_ci } 5504514f5e3Sopenharmony_ci } 5514514f5e3Sopenharmony_ci 5524514f5e3Sopenharmony_ci if (!numberingSystemStr.empty()) { 5534514f5e3Sopenharmony_ci // If numberingSystem is invalid, Let numberingSystem be undefined. 5544514f5e3Sopenharmony_ci if (!JSLocale::IsWellNumberingSystem(numberingSystemStr)) { 5554514f5e3Sopenharmony_ci numberFormat->SetNumberingSystem(thread, undefinedValue); 5564514f5e3Sopenharmony_ci } 5574514f5e3Sopenharmony_ci } 5584514f5e3Sopenharmony_ci 5594514f5e3Sopenharmony_ci // 10. Let localeData be %NumberFormat%.[[LocaleData]]. 5604514f5e3Sopenharmony_ci JSHandle<TaggedArray> availableLocales; 5614514f5e3Sopenharmony_ci if (requestedLocales->GetLength() == 0) { 5624514f5e3Sopenharmony_ci availableLocales = factory->EmptyArray(); 5634514f5e3Sopenharmony_ci } else { 5644514f5e3Sopenharmony_ci availableLocales = GetAvailableLocales(thread); 5654514f5e3Sopenharmony_ci } 5664514f5e3Sopenharmony_ci 5674514f5e3Sopenharmony_ci // 11. Let r be ResolveLocale( %NumberFormat%.[[AvailableLocales]], requestedLocales, opt, 5684514f5e3Sopenharmony_ci // %NumberFormat%.[[RelevantExtensionKeys]], localeData). 5694514f5e3Sopenharmony_ci std::set<std::string> relevantExtensionKeys{"nu"}; 5704514f5e3Sopenharmony_ci ResolvedLocale r = 5714514f5e3Sopenharmony_ci JSLocale::ResolveLocale(thread, availableLocales, requestedLocales, matcher, relevantExtensionKeys); 5724514f5e3Sopenharmony_ci 5734514f5e3Sopenharmony_ci // 12. Set numberFormat.[[Locale]] to r.[[locale]]. 5744514f5e3Sopenharmony_ci icu::Locale icuLocale = r.localeData; 5754514f5e3Sopenharmony_ci JSHandle<EcmaString> localeStr = intl::LocaleHelper::ToLanguageTag(thread, icuLocale); 5764514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 5774514f5e3Sopenharmony_ci numberFormat->SetLocale(thread, localeStr.GetTaggedValue()); 5784514f5e3Sopenharmony_ci 5794514f5e3Sopenharmony_ci // Set numberingSystemStr to UnicodeKeyWord "nu" 5804514f5e3Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 5814514f5e3Sopenharmony_ci if (!numberingSystemStr.empty()) { 5824514f5e3Sopenharmony_ci if (JSLocale::IsWellNumberingSystem(numberingSystemStr)) { 5834514f5e3Sopenharmony_ci icuLocale.setUnicodeKeywordValue("nu", numberingSystemStr, status); 5844514f5e3Sopenharmony_ci ASSERT(U_SUCCESS(status)); 5854514f5e3Sopenharmony_ci } 5864514f5e3Sopenharmony_ci } 5874514f5e3Sopenharmony_ci 5884514f5e3Sopenharmony_ci icu::number::LocalizedNumberFormatter icuNumberFormatter = 5894514f5e3Sopenharmony_ci icu::number::NumberFormatter::withLocale(icuLocale).roundingMode(UNUM_ROUND_HALFUP); 5904514f5e3Sopenharmony_ci 5914514f5e3Sopenharmony_ci int32_t mnfdDefault = 0; 5924514f5e3Sopenharmony_ci int32_t mxfdDefault = 0; 5934514f5e3Sopenharmony_ci FractionDigitsOption fractionOptions = 5944514f5e3Sopenharmony_ci SetNumberFormatUnitOptions(thread, numberFormat, optionsObject, &icuNumberFormatter); 5954514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 5964514f5e3Sopenharmony_ci mnfdDefault = fractionOptions.mnfdDefault; 5974514f5e3Sopenharmony_ci mxfdDefault = fractionOptions.mxfdDefault; 5984514f5e3Sopenharmony_ci UnitDisplayOption unitDisplay = numberFormat->GetUnitDisplay(); 5994514f5e3Sopenharmony_ci 6004514f5e3Sopenharmony_ci // Trans unitDisplay option to ICU display option 6014514f5e3Sopenharmony_ci UNumberUnitWidth uNumberUnitWidth; 6024514f5e3Sopenharmony_ci switch (unitDisplay) { 6034514f5e3Sopenharmony_ci case UnitDisplayOption::SHORT: 6044514f5e3Sopenharmony_ci uNumberUnitWidth = UNumberUnitWidth::UNUM_UNIT_WIDTH_SHORT; 6054514f5e3Sopenharmony_ci break; 6064514f5e3Sopenharmony_ci case UnitDisplayOption::NARROW: 6074514f5e3Sopenharmony_ci uNumberUnitWidth = UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW; 6084514f5e3Sopenharmony_ci break; 6094514f5e3Sopenharmony_ci case UnitDisplayOption::LONG: 6104514f5e3Sopenharmony_ci // UNUM_UNIT_WIDTH_FULL_NAME Print the full name of the unit, without any abbreviations. 6114514f5e3Sopenharmony_ci uNumberUnitWidth = UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME; 6124514f5e3Sopenharmony_ci break; 6134514f5e3Sopenharmony_ci default: 6144514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 6154514f5e3Sopenharmony_ci UNREACHABLE(); 6164514f5e3Sopenharmony_ci } 6174514f5e3Sopenharmony_ci icuNumberFormatter = icuNumberFormatter.unitWidth(uNumberUnitWidth); 6184514f5e3Sopenharmony_ci 6194514f5e3Sopenharmony_ci // 16. Let style be numberFormat.[[Style]]. 6204514f5e3Sopenharmony_ci StyleOption style = numberFormat->GetStyle(); 6214514f5e3Sopenharmony_ci if (style == StyleOption::PERCENT) { 6224514f5e3Sopenharmony_ci icuNumberFormatter = icuNumberFormatter.unit(icu::MeasureUnit::getPercent()). 6234514f5e3Sopenharmony_ci scale(icu::number::Scale::powerOfTen(2)); // means 10^2 6244514f5e3Sopenharmony_ci } 6254514f5e3Sopenharmony_ci 6264514f5e3Sopenharmony_ci // 19. Let notation be ? GetOption( 6274514f5e3Sopenharmony_ci // options, "notation", "string", « "standard", "scientific", "engineering", "compact" », "standard"). 6284514f5e3Sopenharmony_ci property = globalConst->GetHandledNotationString(); 6294514f5e3Sopenharmony_ci auto notation = JSLocale::GetOptionOfString<NotationOption>( 6304514f5e3Sopenharmony_ci thread, optionsObject, property, 6314514f5e3Sopenharmony_ci JSNumberFormat::NOTATION_OPTION, JSNumberFormat::NOTATION_OPTION_NAME, 6324514f5e3Sopenharmony_ci NotationOption::STANDARD); 6334514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 6344514f5e3Sopenharmony_ci numberFormat->SetNotation(notation); 6354514f5e3Sopenharmony_ci 6364514f5e3Sopenharmony_ci // 21. Perform ? SetNumberFormatDigitOptions(numberFormat, options, mnfdDefault, mxfdDefault, notation). 6374514f5e3Sopenharmony_ci JSLocale::SetNumberFormatDigitOptions(thread, numberFormat, JSHandle<JSTaggedValue>::Cast(optionsObject), 6384514f5e3Sopenharmony_ci mnfdDefault, mxfdDefault, notation); 6394514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 6404514f5e3Sopenharmony_ci icuNumberFormatter = SetICUFormatterDigitOptions(icuNumberFormatter, numberFormat); 6414514f5e3Sopenharmony_ci 6424514f5e3Sopenharmony_ci // 22. Let compactDisplay be ? GetOptionOfString(options, "compactDisplay", "string", « "short", "long" », "short"). 6434514f5e3Sopenharmony_ci property = globalConst->GetHandledCompactDisplayString(); 6444514f5e3Sopenharmony_ci auto compactDisplay = JSLocale::GetOptionOfString<CompactDisplayOption>( 6454514f5e3Sopenharmony_ci thread, optionsObject, property, 6464514f5e3Sopenharmony_ci JSNumberFormat::COMPACT_DISPLAY_OPTION, JSNumberFormat::COMPACT_DISPLAY_OPTION_NAME, 6474514f5e3Sopenharmony_ci CompactDisplayOption::SHORT); 6484514f5e3Sopenharmony_ci numberFormat->SetCompactDisplay(compactDisplay); 6494514f5e3Sopenharmony_ci 6504514f5e3Sopenharmony_ci // Trans NotationOption to ICU Noation and set to icuNumberFormatter 6514514f5e3Sopenharmony_ci if (notation == NotationOption::COMPACT) { 6524514f5e3Sopenharmony_ci switch (compactDisplay) { 6534514f5e3Sopenharmony_ci case CompactDisplayOption::SHORT: 6544514f5e3Sopenharmony_ci icuNumberFormatter = icuNumberFormatter.notation(icu::number::Notation::compactShort()); 6554514f5e3Sopenharmony_ci break; 6564514f5e3Sopenharmony_ci case CompactDisplayOption::LONG: 6574514f5e3Sopenharmony_ci icuNumberFormatter = icuNumberFormatter.notation(icu::number::Notation::compactLong()); 6584514f5e3Sopenharmony_ci break; 6594514f5e3Sopenharmony_ci default: 6604514f5e3Sopenharmony_ci break; 6614514f5e3Sopenharmony_ci } 6624514f5e3Sopenharmony_ci } 6634514f5e3Sopenharmony_ci switch (notation) { 6644514f5e3Sopenharmony_ci case NotationOption::STANDARD: 6654514f5e3Sopenharmony_ci icuNumberFormatter = icuNumberFormatter.notation(icu::number::Notation::simple()); 6664514f5e3Sopenharmony_ci break; 6674514f5e3Sopenharmony_ci case NotationOption::SCIENTIFIC: 6684514f5e3Sopenharmony_ci icuNumberFormatter = icuNumberFormatter.notation(icu::number::Notation::scientific()); 6694514f5e3Sopenharmony_ci break; 6704514f5e3Sopenharmony_ci case NotationOption::ENGINEERING: 6714514f5e3Sopenharmony_ci icuNumberFormatter = icuNumberFormatter.notation(icu::number::Notation::engineering()); 6724514f5e3Sopenharmony_ci break; 6734514f5e3Sopenharmony_ci default: 6744514f5e3Sopenharmony_ci break; 6754514f5e3Sopenharmony_ci } 6764514f5e3Sopenharmony_ci 6774514f5e3Sopenharmony_ci // 24. Let useGrouping be ? GetOption(options, "useGrouping", "boolean", undefined, true). 6784514f5e3Sopenharmony_ci property = globalConst->GetHandledUserGroupingString(); 6794514f5e3Sopenharmony_ci bool useGrouping = false; 6804514f5e3Sopenharmony_ci [[maybe_unused]] bool find = JSLocale::GetOptionOfBool(thread, optionsObject, property, true, &useGrouping); 6814514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 6824514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> useGroupingValue(thread, JSTaggedValue(useGrouping)); 6834514f5e3Sopenharmony_ci numberFormat->SetUseGrouping(thread, useGroupingValue); 6844514f5e3Sopenharmony_ci 6854514f5e3Sopenharmony_ci // 25. Set numberFormat.[[UseGrouping]] to useGrouping. 6864514f5e3Sopenharmony_ci if (!useGrouping) { 6874514f5e3Sopenharmony_ci icuNumberFormatter = icuNumberFormatter.grouping(UNumberGroupingStrategy::UNUM_GROUPING_OFF); 6884514f5e3Sopenharmony_ci } 6894514f5e3Sopenharmony_ci 6904514f5e3Sopenharmony_ci // 26. Let signDisplay be ? 6914514f5e3Sopenharmony_ci // GetOption(options, "signDisplay", "string", « "auto", "never", "always", "exceptZero" », "auto"). 6924514f5e3Sopenharmony_ci property = globalConst->GetHandledSignDisplayString(); 6934514f5e3Sopenharmony_ci auto signDisplay = JSLocale::GetOptionOfString<SignDisplayOption>( 6944514f5e3Sopenharmony_ci thread, optionsObject, property, 6954514f5e3Sopenharmony_ci JSNumberFormat::SIGN_DISPLAY_OPTION, JSNumberFormat::SIGN_DISPLAY_OPTION_NAME, 6964514f5e3Sopenharmony_ci SignDisplayOption::AUTO); 6974514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 6984514f5e3Sopenharmony_ci numberFormat->SetSignDisplay(signDisplay); 6994514f5e3Sopenharmony_ci 7004514f5e3Sopenharmony_ci // 27. Set numberFormat.[[SignDisplay]] to signDisplay. 7014514f5e3Sopenharmony_ci // The default sign in ICU is UNUM_SIGN_AUTO which is mapped from 7024514f5e3Sopenharmony_ci // SignDisplay::AUTO and CurrencySign::STANDARD so we can skip setting 7034514f5e3Sopenharmony_ci // under that values for optimization. 7044514f5e3Sopenharmony_ci CurrencySignOption currencySign = numberFormat->GetCurrencySign(); 7054514f5e3Sopenharmony_ci 7064514f5e3Sopenharmony_ci // Trans SignDisPlayOption to ICU UNumberSignDisplay and set to icuNumberFormatter 7074514f5e3Sopenharmony_ci switch (signDisplay) { 7084514f5e3Sopenharmony_ci case SignDisplayOption::AUTO: 7094514f5e3Sopenharmony_ci // if CurrencySign is ACCOUNTING, Use the locale-dependent accounting format on negative numbers 7104514f5e3Sopenharmony_ci if (currencySign == CurrencySignOption::ACCOUNTING) { 7114514f5e3Sopenharmony_ci icuNumberFormatter = icuNumberFormatter.sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING); 7124514f5e3Sopenharmony_ci } else { 7134514f5e3Sopenharmony_ci icuNumberFormatter = icuNumberFormatter.sign(UNumberSignDisplay::UNUM_SIGN_AUTO); 7144514f5e3Sopenharmony_ci } 7154514f5e3Sopenharmony_ci break; 7164514f5e3Sopenharmony_ci case SignDisplayOption::NEVER: 7174514f5e3Sopenharmony_ci icuNumberFormatter = icuNumberFormatter.sign(UNumberSignDisplay::UNUM_SIGN_NEVER); 7184514f5e3Sopenharmony_ci break; 7194514f5e3Sopenharmony_ci case SignDisplayOption::ALWAYS: 7204514f5e3Sopenharmony_ci // if CurrencySign is ACCOUNTING, Use the locale-dependent accounting format on negative numbers 7214514f5e3Sopenharmony_ci if (currencySign == CurrencySignOption::ACCOUNTING) { 7224514f5e3Sopenharmony_ci icuNumberFormatter = icuNumberFormatter.sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_ALWAYS); 7234514f5e3Sopenharmony_ci } else { 7244514f5e3Sopenharmony_ci icuNumberFormatter = icuNumberFormatter.sign(UNumberSignDisplay::UNUM_SIGN_ALWAYS); 7254514f5e3Sopenharmony_ci } 7264514f5e3Sopenharmony_ci break; 7274514f5e3Sopenharmony_ci case SignDisplayOption::EXCEPTZERO: 7284514f5e3Sopenharmony_ci // if CurrencySign is ACCOUNTING, Use the locale-dependent accounting format on negative numbers 7294514f5e3Sopenharmony_ci if (currencySign == CurrencySignOption::ACCOUNTING) { 7304514f5e3Sopenharmony_ci icuNumberFormatter = icuNumberFormatter.sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO); 7314514f5e3Sopenharmony_ci } else { 7324514f5e3Sopenharmony_ci icuNumberFormatter = icuNumberFormatter.sign(UNumberSignDisplay::UNUM_SIGN_EXCEPT_ZERO); 7334514f5e3Sopenharmony_ci } 7344514f5e3Sopenharmony_ci break; 7354514f5e3Sopenharmony_ci default: 7364514f5e3Sopenharmony_ci break; 7374514f5e3Sopenharmony_ci } 7384514f5e3Sopenharmony_ci 7394514f5e3Sopenharmony_ci if (forIcuCache) { 7404514f5e3Sopenharmony_ci std::string cacheEntry = 7414514f5e3Sopenharmony_ci locales->IsUndefined() ? "" : EcmaStringAccessor(locales.GetTaggedValue()).ToStdString(); 7424514f5e3Sopenharmony_ci auto formatterPointer = new icu::number::LocalizedNumberFormatter(icuNumberFormatter); 7434514f5e3Sopenharmony_ci thread->GetCurrentEcmaContext()->SetIcuFormatterToCache(IcuFormatterType::NUMBER_FORMATTER, cacheEntry, 7444514f5e3Sopenharmony_ci formatterPointer, JSNumberFormat::FreeIcuNumberformat); 7454514f5e3Sopenharmony_ci } else { 7464514f5e3Sopenharmony_ci // Set numberFormat.[[IcuNumberForma]] to handleNumberFormatter 7474514f5e3Sopenharmony_ci factory->NewJSIntlIcuData(numberFormat, icuNumberFormatter, JSNumberFormat::FreeIcuNumberformat); 7484514f5e3Sopenharmony_ci } 7494514f5e3Sopenharmony_ci // Set numberFormat.[[BoundFormat]] to undefinedValue 7504514f5e3Sopenharmony_ci numberFormat->SetBoundFormat(thread, undefinedValue); 7514514f5e3Sopenharmony_ci} 7524514f5e3Sopenharmony_ci 7534514f5e3Sopenharmony_ci// 12.1.3 CurrencyDigits ( currency ) 7544514f5e3Sopenharmony_ciint32_t JSNumberFormat::CurrencyDigits(const icu::UnicodeString ¤cy) 7554514f5e3Sopenharmony_ci{ 7564514f5e3Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 7574514f5e3Sopenharmony_ci // If the ISO 4217 currency and funds code list contains currency as an alphabetic code, 7584514f5e3Sopenharmony_ci // return the minor unit value corresponding to the currency from the list; otherwise, return 2. 7594514f5e3Sopenharmony_ci int32_t fractionDigits = 7604514f5e3Sopenharmony_ci ucurr_getDefaultFractionDigits(reinterpret_cast<const UChar *>(currency.getBuffer()), &status); 7614514f5e3Sopenharmony_ci if (U_SUCCESS(status)) { 7624514f5e3Sopenharmony_ci return fractionDigits; 7634514f5e3Sopenharmony_ci } 7644514f5e3Sopenharmony_ci return JSNumberFormat::DEFAULT_FRACTION_DIGITS; 7654514f5e3Sopenharmony_ci} 7664514f5e3Sopenharmony_ci 7674514f5e3Sopenharmony_ciicu::number::LocalizedNumberFormatter *JSNumberFormat::GetCachedIcuNumberFormatter(JSThread *thread, 7684514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &locales) 7694514f5e3Sopenharmony_ci{ 7704514f5e3Sopenharmony_ci std::string cacheEntry = locales->IsUndefined() ? "" : EcmaStringAccessor(locales.GetTaggedValue()).ToStdString(); 7714514f5e3Sopenharmony_ci void *cachedNumberFormatter = thread->GetCurrentEcmaContext()->GetIcuFormatterFromCache( 7724514f5e3Sopenharmony_ci IcuFormatterType::NUMBER_FORMATTER, cacheEntry); 7734514f5e3Sopenharmony_ci if (cachedNumberFormatter) { 7744514f5e3Sopenharmony_ci return reinterpret_cast<icu::number::LocalizedNumberFormatter*>(cachedNumberFormatter); 7754514f5e3Sopenharmony_ci } 7764514f5e3Sopenharmony_ci return nullptr; 7774514f5e3Sopenharmony_ci} 7784514f5e3Sopenharmony_ci 7794514f5e3Sopenharmony_ci// 12.1.8 FormatNumeric( numberFormat, x ) 7804514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> JSNumberFormat::FormatNumeric(JSThread *thread, const JSHandle<JSNumberFormat> &numberFormat, 7814514f5e3Sopenharmony_ci JSTaggedValue x) 7824514f5e3Sopenharmony_ci{ 7834514f5e3Sopenharmony_ci icu::number::LocalizedNumberFormatter *icuNumberFormat = numberFormat->GetIcuCallTarget(); 7844514f5e3Sopenharmony_ci ASSERT(icuNumberFormat != nullptr); 7854514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> res = FormatNumeric(thread, icuNumberFormat, x); 7864514f5e3Sopenharmony_ci return res; 7874514f5e3Sopenharmony_ci} 7884514f5e3Sopenharmony_ci 7894514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> JSNumberFormat::FormatNumeric(JSThread *thread, 7904514f5e3Sopenharmony_ci const icu::number::LocalizedNumberFormatter *icuNumberFormat, 7914514f5e3Sopenharmony_ci JSTaggedValue x) 7924514f5e3Sopenharmony_ci{ 7934514f5e3Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 7944514f5e3Sopenharmony_ci icu::number::FormattedNumber formattedNumber; 7954514f5e3Sopenharmony_ci if (x.IsBigInt()) { 7964514f5e3Sopenharmony_ci JSHandle<BigInt> bigint(thread, x); 7974514f5e3Sopenharmony_ci JSHandle<EcmaString> bigintStr = BigInt::ToString(thread, bigint); 7984514f5e3Sopenharmony_ci std::string stdString = EcmaStringAccessor(bigintStr).ToStdString(); 7994514f5e3Sopenharmony_ci formattedNumber = icuNumberFormat->formatDecimal(icu::StringPiece(stdString), status); 8004514f5e3Sopenharmony_ci } else { 8014514f5e3Sopenharmony_ci double number = x.GetNumber(); 8024514f5e3Sopenharmony_ci formattedNumber = icuNumberFormat->formatDouble(number, status); 8034514f5e3Sopenharmony_ci } 8044514f5e3Sopenharmony_ci if (U_FAILURE(status)) { 8054514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> errorResult(thread, JSTaggedValue::Exception()); 8064514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "icu formatter format failed", errorResult); 8074514f5e3Sopenharmony_ci } 8084514f5e3Sopenharmony_ci icu::UnicodeString result = formattedNumber.toString(status); 8094514f5e3Sopenharmony_ci if (U_FAILURE(status)) { 8104514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> errorResult(thread, JSTaggedValue::Exception()); 8114514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "formatted number toString failed", errorResult); 8124514f5e3Sopenharmony_ci } 8134514f5e3Sopenharmony_ci JSHandle<EcmaString> stringValue = intl::LocaleHelper::UStringToString(thread, result); 8144514f5e3Sopenharmony_ci return JSHandle<JSTaggedValue>::Cast(stringValue); 8154514f5e3Sopenharmony_ci} 8164514f5e3Sopenharmony_ci 8174514f5e3Sopenharmony_civoid GroupToParts(JSThread *thread, const icu::number::FormattedNumber &formatted, const JSHandle<JSArray> &receiver, 8184514f5e3Sopenharmony_ci const JSHandle<JSNumberFormat> &numberFormat, JSTaggedValue x) 8194514f5e3Sopenharmony_ci{ 8204514f5e3Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 8214514f5e3Sopenharmony_ci icu::UnicodeString formattedText = formatted.toString(status); 8224514f5e3Sopenharmony_ci if (U_FAILURE(status)) { // NOLINT(readability-implicit-bool-conversion) 8234514f5e3Sopenharmony_ci THROW_TYPE_ERROR(thread, "formattedNumber toString failed"); 8244514f5e3Sopenharmony_ci } 8254514f5e3Sopenharmony_ci ASSERT(x.IsNumber() || x.IsBigInt()); 8264514f5e3Sopenharmony_ci 8274514f5e3Sopenharmony_ci StyleOption styleOption = numberFormat->GetStyle(); 8284514f5e3Sopenharmony_ci 8294514f5e3Sopenharmony_ci icu::ConstrainedFieldPosition cfpo; 8304514f5e3Sopenharmony_ci // Set constrainCategory to UFIELD_CATEGORY_NUMBER which is specified for UNumberFormatFields 8314514f5e3Sopenharmony_ci cfpo.constrainCategory(UFIELD_CATEGORY_NUMBER); 8324514f5e3Sopenharmony_ci auto globalConst = thread->GlobalConstants(); 8334514f5e3Sopenharmony_ci JSMutableHandle<JSTaggedValue> typeString(thread, JSTaggedValue::Undefined()); 8344514f5e3Sopenharmony_ci int index = 0; 8354514f5e3Sopenharmony_ci int previousLimit = 0; 8364514f5e3Sopenharmony_ci /** 8374514f5e3Sopenharmony_ci * From ICU header file document @unumberformatter.h 8384514f5e3Sopenharmony_ci * Sets a constraint on the field category. 8394514f5e3Sopenharmony_ci * 8404514f5e3Sopenharmony_ci * When this instance of ConstrainedFieldPosition is passed to FormattedValue#nextPosition, 8414514f5e3Sopenharmony_ci * positions are skipped unless they have the given category. 8424514f5e3Sopenharmony_ci * 8434514f5e3Sopenharmony_ci * Any previously set constraints are cleared. 8444514f5e3Sopenharmony_ci * 8454514f5e3Sopenharmony_ci * For example, to loop over only the number-related fields: 8464514f5e3Sopenharmony_ci * 8474514f5e3Sopenharmony_ci * ConstrainedFieldPosition cfpo; 8484514f5e3Sopenharmony_ci * cfpo.constrainCategory(UFIELDCATEGORY_NUMBER_FORMAT); 8494514f5e3Sopenharmony_ci * while (fmtval.nextPosition(cfpo, status)) { 8504514f5e3Sopenharmony_ci * // handle the number-related field position 8514514f5e3Sopenharmony_ci * } 8524514f5e3Sopenharmony_ci */ 8534514f5e3Sopenharmony_ci bool lastFieldGroup = false; 8544514f5e3Sopenharmony_ci int groupLeapLength = 0; 8554514f5e3Sopenharmony_ci while (formatted.nextPosition(cfpo, status)) { 8564514f5e3Sopenharmony_ci int32_t fieldId = cfpo.getField(); 8574514f5e3Sopenharmony_ci int32_t start = cfpo.getStart(); 8584514f5e3Sopenharmony_ci int32_t limit = cfpo.getLimit(); 8594514f5e3Sopenharmony_ci typeString.Update(globalConst->GetLiteralString()); 8604514f5e3Sopenharmony_ci // If start greater than previousLimit, means a literal type exists before number fields 8614514f5e3Sopenharmony_ci // so add a literal type with value of formattedText.sub(0, start) 8624514f5e3Sopenharmony_ci // Special case when fieldId is UNUM_GROUPING_SEPARATOR_FIELD 8634514f5e3Sopenharmony_ci if (static_cast<UNumberFormatFields>(fieldId) == UNUM_GROUPING_SEPARATOR_FIELD) { 8644514f5e3Sopenharmony_ci JSHandle<EcmaString> substring = 8654514f5e3Sopenharmony_ci intl::LocaleHelper::UStringToString(thread, formattedText, previousLimit, start); 8664514f5e3Sopenharmony_ci typeString.Update(globalConst->GetIntegerString()); 8674514f5e3Sopenharmony_ci JSLocale::PutElement(thread, index, receiver, typeString, JSHandle<JSTaggedValue>::Cast(substring)); 8684514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 8694514f5e3Sopenharmony_ci index++; 8704514f5e3Sopenharmony_ci { 8714514f5e3Sopenharmony_ci typeString.Update(JSLocale::GetNumberFieldType(thread, x, fieldId).GetTaggedValue()); 8724514f5e3Sopenharmony_ci substring = intl::LocaleHelper::UStringToString(thread, formattedText, start, limit); 8734514f5e3Sopenharmony_ci JSLocale::PutElement(thread, index, receiver, typeString, JSHandle<JSTaggedValue>::Cast(substring)); 8744514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 8754514f5e3Sopenharmony_ci index++; 8764514f5e3Sopenharmony_ci } 8774514f5e3Sopenharmony_ci lastFieldGroup = true; 8784514f5e3Sopenharmony_ci groupLeapLength = start - previousLimit + 1; 8794514f5e3Sopenharmony_ci previousLimit = limit; 8804514f5e3Sopenharmony_ci continue; 8814514f5e3Sopenharmony_ci } else if (start > previousLimit) { 8824514f5e3Sopenharmony_ci JSHandle<EcmaString> substring = 8834514f5e3Sopenharmony_ci intl::LocaleHelper::UStringToString(thread, formattedText, previousLimit, start); 8844514f5e3Sopenharmony_ci JSLocale::PutElement(thread, index, receiver, typeString, JSHandle<JSTaggedValue>::Cast(substring)); 8854514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 8864514f5e3Sopenharmony_ci index++; 8874514f5e3Sopenharmony_ci } 8884514f5e3Sopenharmony_ci if (lastFieldGroup) { 8894514f5e3Sopenharmony_ci start = start + groupLeapLength; 8904514f5e3Sopenharmony_ci lastFieldGroup = false; 8914514f5e3Sopenharmony_ci } 8924514f5e3Sopenharmony_ci // Special case in ICU when style is unit and unit is percent 8934514f5e3Sopenharmony_ci if (styleOption == StyleOption::UNIT && static_cast<UNumberFormatFields>(fieldId) == UNUM_PERCENT_FIELD) { 8944514f5e3Sopenharmony_ci typeString.Update(globalConst->GetUnitString()); 8954514f5e3Sopenharmony_ci } else { 8964514f5e3Sopenharmony_ci typeString.Update(JSLocale::GetNumberFieldType(thread, x, fieldId).GetTaggedValue()); 8974514f5e3Sopenharmony_ci } 8984514f5e3Sopenharmony_ci JSHandle<EcmaString> substring = intl::LocaleHelper::UStringToString(thread, formattedText, start, limit); 8994514f5e3Sopenharmony_ci JSLocale::PutElement(thread, index, receiver, typeString, JSHandle<JSTaggedValue>::Cast(substring)); 9004514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 9014514f5e3Sopenharmony_ci index++; 9024514f5e3Sopenharmony_ci previousLimit = limit; 9034514f5e3Sopenharmony_ci } 9044514f5e3Sopenharmony_ci // If iterated length is smaller than formattedText.length, means a literal type exists after number fields 9054514f5e3Sopenharmony_ci // so add a literal type with value of formattedText.sub(previousLimit, formattedText.length) 9064514f5e3Sopenharmony_ci if (formattedText.length() > previousLimit) { 9074514f5e3Sopenharmony_ci typeString.Update(globalConst->GetLiteralString()); 9084514f5e3Sopenharmony_ci JSHandle<EcmaString> substring = 9094514f5e3Sopenharmony_ci intl::LocaleHelper::UStringToString(thread, formattedText, previousLimit, formattedText.length()); 9104514f5e3Sopenharmony_ci JSLocale::PutElement(thread, index, receiver, typeString, JSHandle<JSTaggedValue>::Cast(substring)); 9114514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 9124514f5e3Sopenharmony_ci } 9134514f5e3Sopenharmony_ci} 9144514f5e3Sopenharmony_ci 9154514f5e3Sopenharmony_ci// 12.1.9 FormatNumericToParts( numberFormat, x ) 9164514f5e3Sopenharmony_ciJSHandle<JSArray> JSNumberFormat::FormatNumericToParts(JSThread *thread, const JSHandle<JSNumberFormat> &numberFormat, 9174514f5e3Sopenharmony_ci JSTaggedValue x) 9184514f5e3Sopenharmony_ci{ 9194514f5e3Sopenharmony_ci ASSERT(x.IsNumber() || x.IsBigInt()); 9204514f5e3Sopenharmony_ci icu::number::LocalizedNumberFormatter *icuNumberFormatter = numberFormat->GetIcuCallTarget(); 9214514f5e3Sopenharmony_ci ASSERT(icuNumberFormatter != nullptr); 9224514f5e3Sopenharmony_ci 9234514f5e3Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 9244514f5e3Sopenharmony_ci icu::number::FormattedNumber formattedNumber; 9254514f5e3Sopenharmony_ci if (x.IsBigInt()) { 9264514f5e3Sopenharmony_ci JSHandle<BigInt> bigint(thread, x); 9274514f5e3Sopenharmony_ci JSHandle<EcmaString> bigintStr = BigInt::ToString(thread, bigint); 9284514f5e3Sopenharmony_ci std::string stdString = EcmaStringAccessor(bigintStr).ToStdString(); 9294514f5e3Sopenharmony_ci formattedNumber = icuNumberFormatter->formatDecimal(icu::StringPiece(stdString), status); 9304514f5e3Sopenharmony_ci } else { 9314514f5e3Sopenharmony_ci double number = x.GetNumber(); 9324514f5e3Sopenharmony_ci formattedNumber = icuNumberFormatter->formatDouble(number, status); 9334514f5e3Sopenharmony_ci } 9344514f5e3Sopenharmony_ci if (U_FAILURE(status)) { 9354514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 9364514f5e3Sopenharmony_ci JSHandle<JSArray> emptyArray = factory->NewJSArray(); 9374514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "icu formatter format failed", emptyArray); 9384514f5e3Sopenharmony_ci } 9394514f5e3Sopenharmony_ci 9404514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> arr = JSArray::ArrayCreate(thread, JSTaggedNumber(0)); 9414514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSArray, thread); 9424514f5e3Sopenharmony_ci JSHandle<JSArray> result = JSHandle<JSArray>::Cast(arr); 9434514f5e3Sopenharmony_ci GroupToParts(thread, formattedNumber, result, numberFormat, x); 9444514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSArray, thread); 9454514f5e3Sopenharmony_ci return result; 9464514f5e3Sopenharmony_ci} 9474514f5e3Sopenharmony_ci 9484514f5e3Sopenharmony_ci// 12.1.12 UnwrapNumberFormat( nf ) 9494514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> JSNumberFormat::UnwrapNumberFormat(JSThread *thread, const JSHandle<JSTaggedValue> &nf) 9504514f5e3Sopenharmony_ci{ 9514514f5e3Sopenharmony_ci // 1. Assert: Type(nf) is Object. 9524514f5e3Sopenharmony_ci ASSERT(nf->IsJSObject()); 9534514f5e3Sopenharmony_ci 9544514f5e3Sopenharmony_ci // 2. If nf does not have an [[InitializedNumberFormat]] internal slot and ? 9554514f5e3Sopenharmony_ci // InstanceofOperator(nf, %NumberFormat%) is true, then Let nf be ? Get(nf, %Intl%.[[FallbackSymbol]]). 9564514f5e3Sopenharmony_ci JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv(); 9574514f5e3Sopenharmony_ci bool hasInstance = JSFunction::OrdinaryHasInstance(thread, env->GetNumberFormatFunction(), nf); 9584514f5e3Sopenharmony_ci RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined())); 9594514f5e3Sopenharmony_ci 9604514f5e3Sopenharmony_ci bool isJSNumberFormat = nf->IsJSNumberFormat(); 9614514f5e3Sopenharmony_ci // If nf does not have an [[InitializedNumberFormat]] internal slot and ? 9624514f5e3Sopenharmony_ci // InstanceofOperator(nf, %NumberFormat%) is true, then 9634514f5e3Sopenharmony_ci // a. Let nf be ? Get(nf, %Intl%.[[FallbackSymbol]]). 9644514f5e3Sopenharmony_ci if (!isJSNumberFormat && hasInstance) { 9654514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> key(thread, JSHandle<JSIntl>::Cast(env->GetIntlFunction())->GetFallbackSymbol()); 9664514f5e3Sopenharmony_ci OperationResult operationResult = JSTaggedValue::GetProperty(thread, nf, key); 9674514f5e3Sopenharmony_ci RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined())); 9684514f5e3Sopenharmony_ci return operationResult.GetValue(); 9694514f5e3Sopenharmony_ci } 9704514f5e3Sopenharmony_ci // 3. Perform ? RequireInternalSlot(nf, [[InitializedNumberFormat]]). 9714514f5e3Sopenharmony_ci if (!isJSNumberFormat) { 9724514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, "this is not object", 9734514f5e3Sopenharmony_ci JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception())); 9744514f5e3Sopenharmony_ci } 9754514f5e3Sopenharmony_ci return nf; 9764514f5e3Sopenharmony_ci} 9774514f5e3Sopenharmony_ci 9784514f5e3Sopenharmony_ciJSHandle<TaggedArray> JSNumberFormat::GetAvailableLocales(JSThread *thread) 9794514f5e3Sopenharmony_ci{ 9804514f5e3Sopenharmony_ci JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv(); 9814514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> numberFormatLocales = env->GetNumberFormatLocales(); 9824514f5e3Sopenharmony_ci if (!numberFormatLocales->IsUndefined()) { 9834514f5e3Sopenharmony_ci return JSHandle<TaggedArray>::Cast(numberFormatLocales); 9844514f5e3Sopenharmony_ci } 9854514f5e3Sopenharmony_ci const char *key = "NumberElements"; 9864514f5e3Sopenharmony_ci const char *path = nullptr; 9874514f5e3Sopenharmony_ci std::vector<std::string> availableStringLocales = intl::LocaleHelper::GetAvailableLocales(thread, key, path); 9884514f5e3Sopenharmony_ci JSHandle<TaggedArray> availableLocales = JSLocale::ConstructLocaleList(thread, availableStringLocales); 9894514f5e3Sopenharmony_ci env->SetNumberFormatLocales(thread, availableLocales); 9904514f5e3Sopenharmony_ci return availableLocales; 9914514f5e3Sopenharmony_ci} 9924514f5e3Sopenharmony_ci 9934514f5e3Sopenharmony_civoid JSNumberFormat::ResolvedOptions(JSThread *thread, const JSHandle<JSNumberFormat> &numberFormat, 9944514f5e3Sopenharmony_ci const JSHandle<JSObject> &options) 9954514f5e3Sopenharmony_ci{ 9964514f5e3Sopenharmony_ci // Table 5: Resolved Options of NumberFormat Instances 9974514f5e3Sopenharmony_ci // Internal Slot Property 9984514f5e3Sopenharmony_ci // [[Locale]] "locale" 9994514f5e3Sopenharmony_ci // [[NumberingSystem]] "numberingSystem" 10004514f5e3Sopenharmony_ci // [[Style]] "style" 10014514f5e3Sopenharmony_ci // [[Currency]] "currency" 10024514f5e3Sopenharmony_ci // [[CurrencyDisplay]] "currencyDisplay" 10034514f5e3Sopenharmony_ci // [[CurrencySign]] "currencySign" 10044514f5e3Sopenharmony_ci // [[Unit]] "unit" 10054514f5e3Sopenharmony_ci // [[UnitDisplay]] "unitDisplay" 10064514f5e3Sopenharmony_ci // [[MinimumIntegerDigits]] "minimumIntegerDigits" 10074514f5e3Sopenharmony_ci // [[MinimumFractionDigits]] "minimumFractionDigits" 10084514f5e3Sopenharmony_ci // [[MaximumFractionDigits]] "maximumFractionDigits" 10094514f5e3Sopenharmony_ci // [[MinimumSignificantDigits]] "minimumSignificantDigits" 10104514f5e3Sopenharmony_ci // [[MaximumSignificantDigits]] "maximumSignificantDigits" 10114514f5e3Sopenharmony_ci // [[UseGrouping]] "useGrouping" 10124514f5e3Sopenharmony_ci // [[Notation]] "notation" 10134514f5e3Sopenharmony_ci // [[CompactDisplay]] "compactDisplay" 10144514f5e3Sopenharmony_ci // [SignDisplay]] "signDisplay" 10154514f5e3Sopenharmony_ci // [[Locale]] 10164514f5e3Sopenharmony_ci auto globalConst = thread->GlobalConstants(); 10174514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> property = globalConst->GetHandledLocaleString(); 10184514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> locale(thread, numberFormat->GetLocale()); 10194514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, locale); 10204514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 10214514f5e3Sopenharmony_ci 10224514f5e3Sopenharmony_ci // [[NumberingSystem]] 10234514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> numberingSystem(thread, numberFormat->GetNumberingSystem()); 10244514f5e3Sopenharmony_ci if (numberingSystem->IsUndefined()) { 10254514f5e3Sopenharmony_ci numberingSystem = globalConst->GetHandledLatnString(); 10264514f5e3Sopenharmony_ci } 10274514f5e3Sopenharmony_ci property = globalConst->GetHandledNumberingSystemString(); 10284514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, numberingSystem); 10294514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 10304514f5e3Sopenharmony_ci 10314514f5e3Sopenharmony_ci // [[Style]] 10324514f5e3Sopenharmony_ci StyleOption style = numberFormat->GetStyle(); 10334514f5e3Sopenharmony_ci property = globalConst->GetHandledStyleString(); 10344514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> styleString = OptionToEcmaString(thread, style); 10354514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, styleString); 10364514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 10374514f5e3Sopenharmony_ci 10384514f5e3Sopenharmony_ci // [[currency]] 10394514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> currency(thread, JSTaggedValue::Undefined()); 10404514f5e3Sopenharmony_ci // If style is not currency the currency should be undefined 10414514f5e3Sopenharmony_ci if (style == StyleOption::CURRENCY) { 10424514f5e3Sopenharmony_ci currency = JSHandle<JSTaggedValue>(thread, numberFormat->GetCurrency()); 10434514f5e3Sopenharmony_ci } 10444514f5e3Sopenharmony_ci if (!currency->IsUndefined()) { // NOLINT(readability-implicit-bool-conversion) 10454514f5e3Sopenharmony_ci property = globalConst->GetHandledCurrencyString(); 10464514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, currency); 10474514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 10484514f5e3Sopenharmony_ci 10494514f5e3Sopenharmony_ci // [[CurrencyDisplay]] 10504514f5e3Sopenharmony_ci property = globalConst->GetHandledCurrencyDisplayString(); 10514514f5e3Sopenharmony_ci CurrencyDisplayOption currencyDisplay = numberFormat->GetCurrencyDisplay(); 10524514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> currencyDisplayString = OptionToEcmaString(thread, currencyDisplay); 10534514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, currencyDisplayString); 10544514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 10554514f5e3Sopenharmony_ci 10564514f5e3Sopenharmony_ci // [[CurrencySign]] 10574514f5e3Sopenharmony_ci property = globalConst->GetHandledCurrencySignString(); 10584514f5e3Sopenharmony_ci CurrencySignOption currencySign = numberFormat->GetCurrencySign(); 10594514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> currencySignString = OptionToEcmaString(thread, currencySign); 10604514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, currencySignString); 10614514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 10624514f5e3Sopenharmony_ci } 10634514f5e3Sopenharmony_ci 10644514f5e3Sopenharmony_ci if (style == StyleOption::UNIT) { 10654514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> unit(thread, numberFormat->GetUnit()); 10664514f5e3Sopenharmony_ci if (!unit->IsUndefined()) { 10674514f5e3Sopenharmony_ci // [[Unit]] 10684514f5e3Sopenharmony_ci property = globalConst->GetHandledUnitString(); 10694514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, unit); 10704514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 10714514f5e3Sopenharmony_ci } 10724514f5e3Sopenharmony_ci // [[UnitDisplay]] 10734514f5e3Sopenharmony_ci property = globalConst->GetHandledUnitDisplayString(); 10744514f5e3Sopenharmony_ci UnitDisplayOption unitDisplay = numberFormat->GetUnitDisplay(); 10754514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> unitDisplayString = OptionToEcmaString(thread, unitDisplay); 10764514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, unitDisplayString); 10774514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 10784514f5e3Sopenharmony_ci } 10794514f5e3Sopenharmony_ci // [[MinimumIntegerDigits]] 10804514f5e3Sopenharmony_ci property = globalConst->GetHandledMinimumIntegerDigitsString(); 10814514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> minimumIntegerDigits(thread, numberFormat->GetMinimumIntegerDigits()); 10824514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, minimumIntegerDigits); 10834514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 10844514f5e3Sopenharmony_ci 10854514f5e3Sopenharmony_ci RoundingType roundingType = numberFormat->GetRoundingType(); 10864514f5e3Sopenharmony_ci if (roundingType == RoundingType::SIGNIFICANTDIGITS) { 10874514f5e3Sopenharmony_ci // [[MinimumSignificantDigits]] 10884514f5e3Sopenharmony_ci property = globalConst->GetHandledMinimumSignificantDigitsString(); 10894514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> minimumSignificantDigits(thread, numberFormat->GetMinimumSignificantDigits()); 10904514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, minimumSignificantDigits); 10914514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 10924514f5e3Sopenharmony_ci // [[MaximumSignificantDigits]] 10934514f5e3Sopenharmony_ci property = globalConst->GetHandledMaximumSignificantDigitsString(); 10944514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> maximumSignificantDigits(thread, numberFormat->GetMaximumSignificantDigits()); 10954514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, maximumSignificantDigits); 10964514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 10974514f5e3Sopenharmony_ci } else { 10984514f5e3Sopenharmony_ci // [[MinimumFractionDigits]] 10994514f5e3Sopenharmony_ci property = globalConst->GetHandledMinimumFractionDigitsString(); 11004514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> minimumFractionDigits(thread, numberFormat->GetMinimumFractionDigits()); 11014514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, minimumFractionDigits); 11024514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 11034514f5e3Sopenharmony_ci // [[MaximumFractionDigits]] 11044514f5e3Sopenharmony_ci property = globalConst->GetHandledMaximumFractionDigitsString(); 11054514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> maximumFractionDigits(thread, numberFormat->GetMaximumFractionDigits()); 11064514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, maximumFractionDigits); 11074514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 11084514f5e3Sopenharmony_ci 11094514f5e3Sopenharmony_ci // in v3, should contain BOTH significant and fraction digits 11104514f5e3Sopenharmony_ci if (roundingType == RoundingType::COMPACTROUNDING) { 11114514f5e3Sopenharmony_ci // [[MinimumSignificantDigits]] 11124514f5e3Sopenharmony_ci property = globalConst->GetHandledMinimumSignificantDigitsString(); 11134514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> minimumSignificantDigits(thread, numberFormat->GetMinimumSignificantDigits()); 11144514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, minimumSignificantDigits); 11154514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 11164514f5e3Sopenharmony_ci // [[MaximumSignificantDigits]] 11174514f5e3Sopenharmony_ci property = globalConst->GetHandledMaximumSignificantDigitsString(); 11184514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> maximumSignificantDigits(thread, numberFormat->GetMaximumSignificantDigits()); 11194514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, maximumSignificantDigits); 11204514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 11214514f5e3Sopenharmony_ci } 11224514f5e3Sopenharmony_ci } 11234514f5e3Sopenharmony_ci 11244514f5e3Sopenharmony_ci // [[UseGrouping]] 11254514f5e3Sopenharmony_ci property = globalConst->GetHandledUserGroupingString(); 11264514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, 11274514f5e3Sopenharmony_ci JSHandle<JSTaggedValue>(thread, numberFormat->GetUseGrouping())); 11284514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 11294514f5e3Sopenharmony_ci 11304514f5e3Sopenharmony_ci // [[Notation]] 11314514f5e3Sopenharmony_ci property = globalConst->GetHandledNotationString(); 11324514f5e3Sopenharmony_ci NotationOption notation = numberFormat->GetNotation(); 11334514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> notationString = OptionToEcmaString(thread, notation); 11344514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, notationString); 11354514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 11364514f5e3Sopenharmony_ci 11374514f5e3Sopenharmony_ci // Only output compactDisplay when notation is compact. 11384514f5e3Sopenharmony_ci if (notation == NotationOption::COMPACT) { 11394514f5e3Sopenharmony_ci // [[CompactDisplay]] 11404514f5e3Sopenharmony_ci property = globalConst->GetHandledCompactDisplayString(); 11414514f5e3Sopenharmony_ci CompactDisplayOption compactDisplay = numberFormat->GetCompactDisplay(); 11424514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> compactDisplayString = OptionToEcmaString(thread, compactDisplay); 11434514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, compactDisplayString); 11444514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 11454514f5e3Sopenharmony_ci } 11464514f5e3Sopenharmony_ci 11474514f5e3Sopenharmony_ci // [[SignDisplay]] 11484514f5e3Sopenharmony_ci property = globalConst->GetHandledSignDisplayString(); 11494514f5e3Sopenharmony_ci SignDisplayOption signDisplay = numberFormat->GetSignDisplay(); 11504514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> signDisplayString = OptionToEcmaString(thread, signDisplay); 11514514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, signDisplayString); 11524514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 11534514f5e3Sopenharmony_ci} 11544514f5e3Sopenharmony_ci} // namespace panda::ecmascript