14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#include "ecmascript/js_plural_rules.h" 174514f5e3Sopenharmony_ci 184514f5e3Sopenharmony_ci#include "ecmascript/object_factory-inl.h" 194514f5e3Sopenharmony_ci#include "ecmascript/js_number_format.h" 204514f5e3Sopenharmony_ci#include "ecmascript/checkpoint/thread_state_transition.h" 214514f5e3Sopenharmony_ci 224514f5e3Sopenharmony_cinamespace panda::ecmascript { 234514f5e3Sopenharmony_ciconstexpr int32_t STRING_SEPARATOR_LENGTH = 4; 244514f5e3Sopenharmony_ci 254514f5e3Sopenharmony_ciicu::number::LocalizedNumberFormatter *JSPluralRules::GetIcuNumberFormatter() const 264514f5e3Sopenharmony_ci{ 274514f5e3Sopenharmony_ci ASSERT(GetIcuNF().IsJSNativePointer()); 284514f5e3Sopenharmony_ci auto result = JSNativePointer::Cast(GetIcuNF().GetTaggedObject())->GetExternalPointer(); 294514f5e3Sopenharmony_ci return reinterpret_cast<icu::number::LocalizedNumberFormatter *>(result); 304514f5e3Sopenharmony_ci} 314514f5e3Sopenharmony_ci 324514f5e3Sopenharmony_civoid JSPluralRules::FreeIcuNumberFormatter([[maybe_unused]] void *env, void *pointer, void* hint) 334514f5e3Sopenharmony_ci{ 344514f5e3Sopenharmony_ci if (pointer == nullptr) { 354514f5e3Sopenharmony_ci return; 364514f5e3Sopenharmony_ci } 374514f5e3Sopenharmony_ci auto icuNumberFormatter = reinterpret_cast<icu::number::LocalizedNumberFormatter *>(pointer); 384514f5e3Sopenharmony_ci icuNumberFormatter->~LocalizedNumberFormatter(); 394514f5e3Sopenharmony_ci if (hint != nullptr) { 404514f5e3Sopenharmony_ci reinterpret_cast<EcmaVM *>(hint)->GetNativeAreaAllocator()->FreeBuffer(pointer); 414514f5e3Sopenharmony_ci } 424514f5e3Sopenharmony_ci} 434514f5e3Sopenharmony_ci 444514f5e3Sopenharmony_civoid JSPluralRules::SetIcuNumberFormatter(JSThread *thread, const JSHandle<JSPluralRules> &pluralRules, 454514f5e3Sopenharmony_ci const icu::number::LocalizedNumberFormatter &icuNF, const NativePointerCallback &callback) 464514f5e3Sopenharmony_ci{ 474514f5e3Sopenharmony_ci EcmaVM *ecmaVm = thread->GetEcmaVM(); 484514f5e3Sopenharmony_ci ObjectFactory *factory = ecmaVm->GetFactory(); 494514f5e3Sopenharmony_ci 504514f5e3Sopenharmony_ci icu::number::LocalizedNumberFormatter *icuPointer = 514514f5e3Sopenharmony_ci ecmaVm->GetNativeAreaAllocator()->New<icu::number::LocalizedNumberFormatter>(icuNF); 524514f5e3Sopenharmony_ci ASSERT(icuPointer != nullptr); 534514f5e3Sopenharmony_ci JSTaggedValue data = pluralRules->GetIcuNF(); 544514f5e3Sopenharmony_ci if (data.IsHeapObject() && data.IsJSNativePointer()) { 554514f5e3Sopenharmony_ci JSNativePointer *native = JSNativePointer::Cast(data.GetTaggedObject()); 564514f5e3Sopenharmony_ci native->ResetExternalPointer(thread, icuPointer); 574514f5e3Sopenharmony_ci return; 584514f5e3Sopenharmony_ci } 594514f5e3Sopenharmony_ci JSHandle<JSNativePointer> pointer = factory->NewJSNativePointer(icuPointer, callback, ecmaVm); 604514f5e3Sopenharmony_ci pluralRules->SetIcuNF(thread, pointer.GetTaggedValue()); 614514f5e3Sopenharmony_ci} 624514f5e3Sopenharmony_ci 634514f5e3Sopenharmony_ciicu::PluralRules *JSPluralRules::GetIcuPluralRules() const 644514f5e3Sopenharmony_ci{ 654514f5e3Sopenharmony_ci ASSERT(GetIcuPR().IsJSNativePointer()); 664514f5e3Sopenharmony_ci auto result = JSNativePointer::Cast(GetIcuPR().GetTaggedObject())->GetExternalPointer(); 674514f5e3Sopenharmony_ci return reinterpret_cast<icu::PluralRules *>(result); 684514f5e3Sopenharmony_ci} 694514f5e3Sopenharmony_ci 704514f5e3Sopenharmony_civoid JSPluralRules::FreeIcuPluralRules([[maybe_unused]] void *env, void *pointer, void* hint) 714514f5e3Sopenharmony_ci{ 724514f5e3Sopenharmony_ci if (pointer == nullptr) { 734514f5e3Sopenharmony_ci return; 744514f5e3Sopenharmony_ci } 754514f5e3Sopenharmony_ci auto icuPluralRules = reinterpret_cast<icu::PluralRules *>(pointer); 764514f5e3Sopenharmony_ci icuPluralRules->~PluralRules(); 774514f5e3Sopenharmony_ci if (hint != nullptr) { 784514f5e3Sopenharmony_ci reinterpret_cast<EcmaVM *>(hint)->GetNativeAreaAllocator()->FreeBuffer(pointer); 794514f5e3Sopenharmony_ci } 804514f5e3Sopenharmony_ci} 814514f5e3Sopenharmony_ci 824514f5e3Sopenharmony_civoid JSPluralRules::SetIcuPluralRules(JSThread *thread, const JSHandle<JSPluralRules> &pluralRules, 834514f5e3Sopenharmony_ci const icu::PluralRules &icuPR, const NativePointerCallback &callback) 844514f5e3Sopenharmony_ci{ 854514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope scope(thread); 864514f5e3Sopenharmony_ci EcmaVM *ecmaVm = thread->GetEcmaVM(); 874514f5e3Sopenharmony_ci ObjectFactory *factory = ecmaVm->GetFactory(); 884514f5e3Sopenharmony_ci 894514f5e3Sopenharmony_ci icu::PluralRules *icuPointer = ecmaVm->GetNativeAreaAllocator()->New<icu::PluralRules>(icuPR); 904514f5e3Sopenharmony_ci ASSERT(icuPointer != nullptr); 914514f5e3Sopenharmony_ci JSTaggedValue data = pluralRules->GetIcuPR(); 924514f5e3Sopenharmony_ci if (data.IsHeapObject() && data.IsJSNativePointer()) { 934514f5e3Sopenharmony_ci JSNativePointer *native = JSNativePointer::Cast(data.GetTaggedObject()); 944514f5e3Sopenharmony_ci native->ResetExternalPointer(thread, icuPointer); 954514f5e3Sopenharmony_ci return; 964514f5e3Sopenharmony_ci } 974514f5e3Sopenharmony_ci JSHandle<JSNativePointer> pointer = factory->NewJSNativePointer(icuPointer, callback, ecmaVm); 984514f5e3Sopenharmony_ci pluralRules->SetIcuPR(thread, pointer.GetTaggedValue()); 994514f5e3Sopenharmony_ci} 1004514f5e3Sopenharmony_ci 1014514f5e3Sopenharmony_ciJSHandle<TaggedArray> JSPluralRules::BuildLocaleSet(JSThread *thread, const std::set<std::string> &icuAvailableLocales) 1024514f5e3Sopenharmony_ci{ 1034514f5e3Sopenharmony_ci EcmaVM *ecmaVm = thread->GetEcmaVM(); 1044514f5e3Sopenharmony_ci ObjectFactory *factory = ecmaVm->GetFactory(); 1054514f5e3Sopenharmony_ci JSHandle<TaggedArray> locales = factory->NewTaggedArray(icuAvailableLocales.size()); 1064514f5e3Sopenharmony_ci int32_t index = 0; 1074514f5e3Sopenharmony_ci 1084514f5e3Sopenharmony_ci for (const std::string &locale : icuAvailableLocales) { 1094514f5e3Sopenharmony_ci JSHandle<EcmaString> localeStr = factory->NewFromStdString(locale); 1104514f5e3Sopenharmony_ci locales->Set(thread, index++, localeStr); 1114514f5e3Sopenharmony_ci } 1124514f5e3Sopenharmony_ci return locales; 1134514f5e3Sopenharmony_ci} 1144514f5e3Sopenharmony_ci 1154514f5e3Sopenharmony_cibool GetNextLocale(icu::StringEnumeration *locales, std::string &localeStr, int32_t *len) 1164514f5e3Sopenharmony_ci{ 1174514f5e3Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 1184514f5e3Sopenharmony_ci const char *locale = nullptr; 1194514f5e3Sopenharmony_ci locale = locales->next(len, status); 1204514f5e3Sopenharmony_ci if (!U_SUCCESS(status) || locale == nullptr) { 1214514f5e3Sopenharmony_ci localeStr = ""; 1224514f5e3Sopenharmony_ci return false; 1234514f5e3Sopenharmony_ci } 1244514f5e3Sopenharmony_ci localeStr = std::string(locale); 1254514f5e3Sopenharmony_ci return true; 1264514f5e3Sopenharmony_ci} 1274514f5e3Sopenharmony_ci 1284514f5e3Sopenharmony_ciJSHandle<TaggedArray> JSPluralRules::GetAvailableLocales(JSThread *thread) 1294514f5e3Sopenharmony_ci{ 1304514f5e3Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 1314514f5e3Sopenharmony_ci std::unique_ptr<icu::StringEnumeration> locales(icu::PluralRules::getAvailableLocales(status)); 1324514f5e3Sopenharmony_ci ASSERT(U_SUCCESS(status)); 1334514f5e3Sopenharmony_ci std::set<std::string> set; 1344514f5e3Sopenharmony_ci std::string localeStr; 1354514f5e3Sopenharmony_ci int32_t len = 0; 1364514f5e3Sopenharmony_ci { 1374514f5e3Sopenharmony_ci ThreadNativeScope nativeScope(thread); 1384514f5e3Sopenharmony_ci while (GetNextLocale(locales.get(), localeStr, &len)) { 1394514f5e3Sopenharmony_ci if (len >= STRING_SEPARATOR_LENGTH) { 1404514f5e3Sopenharmony_ci std::replace(localeStr.begin(), localeStr.end(), '_', '-'); 1414514f5e3Sopenharmony_ci } 1424514f5e3Sopenharmony_ci set.insert(localeStr); 1434514f5e3Sopenharmony_ci } 1444514f5e3Sopenharmony_ci } 1454514f5e3Sopenharmony_ci return BuildLocaleSet(thread, set); 1464514f5e3Sopenharmony_ci} 1474514f5e3Sopenharmony_ci 1484514f5e3Sopenharmony_ci// InitializePluralRules ( pluralRules, locales, options ) 1494514f5e3Sopenharmony_ciJSHandle<JSPluralRules> JSPluralRules::InitializePluralRules(JSThread *thread, 1504514f5e3Sopenharmony_ci const JSHandle<JSPluralRules> &pluralRules, 1514514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &locales, 1524514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &options) 1534514f5e3Sopenharmony_ci{ 1544514f5e3Sopenharmony_ci EcmaVM *ecmaVm = thread->GetEcmaVM(); 1554514f5e3Sopenharmony_ci ObjectFactory *factory = ecmaVm->GetFactory(); 1564514f5e3Sopenharmony_ci auto globalConst = thread->GlobalConstants(); 1574514f5e3Sopenharmony_ci 1584514f5e3Sopenharmony_ci // 1. Let requestedLocales be ? CanonicalizeLocaleList(locales). 1594514f5e3Sopenharmony_ci JSHandle<TaggedArray> requestedLocales = intl::LocaleHelper::CanonicalizeLocaleList(thread, locales); 1604514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSPluralRules, thread); 1614514f5e3Sopenharmony_ci 1624514f5e3Sopenharmony_ci // 2&3. If options is undefined, then Let options be ObjectCreate(null). else Let options be ? ToObject(options). 1634514f5e3Sopenharmony_ci JSHandle<JSObject> prOptions; 1644514f5e3Sopenharmony_ci if (!options->IsUndefined()) { 1654514f5e3Sopenharmony_ci prOptions = JSTaggedValue::ToObject(thread, options); 1664514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSPluralRules, thread); 1674514f5e3Sopenharmony_ci } else { 1684514f5e3Sopenharmony_ci prOptions = factory->CreateNullJSObject(); 1694514f5e3Sopenharmony_ci } 1704514f5e3Sopenharmony_ci 1714514f5e3Sopenharmony_ci // 5. Let matcher be ? GetOption(options, "localeMatcher", "string", « "lookup", "best fit" », "best fit"). 1724514f5e3Sopenharmony_ci LocaleMatcherOption matcher = 1734514f5e3Sopenharmony_ci JSLocale::GetOptionOfString(thread, prOptions, globalConst->GetHandledLocaleMatcherString(), 1744514f5e3Sopenharmony_ci {LocaleMatcherOption::LOOKUP, LocaleMatcherOption::BEST_FIT}, 1754514f5e3Sopenharmony_ci {"lookup", "best fit"}, LocaleMatcherOption::BEST_FIT); 1764514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSPluralRules, thread); 1774514f5e3Sopenharmony_ci 1784514f5e3Sopenharmony_ci // 7. Let t be ? GetOption(options, "type", "string", « "cardinal", "ordinal" », "cardinal"). 1794514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> property = JSHandle<JSTaggedValue>::Cast(globalConst->GetHandledTypeString()); 1804514f5e3Sopenharmony_ci TypeOption type = 1814514f5e3Sopenharmony_ci JSLocale::GetOptionOfString(thread, prOptions, property, { TypeOption::CARDINAL, TypeOption::ORDINAL }, 1824514f5e3Sopenharmony_ci { "cardinal", "ordinal" }, TypeOption::CARDINAL); 1834514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSPluralRules, thread); 1844514f5e3Sopenharmony_ci 1854514f5e3Sopenharmony_ci // set pluralRules.[[type]] to type 1864514f5e3Sopenharmony_ci pluralRules->SetType(type); 1874514f5e3Sopenharmony_ci 1884514f5e3Sopenharmony_ci // Let r be ResolveLocale(%PluralRules%.[[AvailableLocales]], requestedLocales, opt, 1894514f5e3Sopenharmony_ci // %PluralRules%.[[RelevantExtensionKeys]], localeData). 1904514f5e3Sopenharmony_ci JSHandle<TaggedArray> availableLocales; 1914514f5e3Sopenharmony_ci if (requestedLocales->GetLength() == 0) { 1924514f5e3Sopenharmony_ci availableLocales = factory->EmptyArray(); 1934514f5e3Sopenharmony_ci } else { 1944514f5e3Sopenharmony_ci availableLocales = GetAvailableLocales(thread); 1954514f5e3Sopenharmony_ci } 1964514f5e3Sopenharmony_ci std::set<std::string> relevantExtensionKeys{""}; 1974514f5e3Sopenharmony_ci ResolvedLocale r = 1984514f5e3Sopenharmony_ci JSLocale::ResolveLocale(thread, availableLocales, requestedLocales, matcher, relevantExtensionKeys); 1994514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSPluralRules, thread); 2004514f5e3Sopenharmony_ci icu::Locale icuLocale = r.localeData; 2014514f5e3Sopenharmony_ci 2024514f5e3Sopenharmony_ci // Get ICU numberFormatter with given locale 2034514f5e3Sopenharmony_ci icu::number::LocalizedNumberFormatter icuNumberFormatter = 2044514f5e3Sopenharmony_ci icu::number::NumberFormatter::withLocale(icuLocale).roundingMode(UNUM_ROUND_HALFUP); 2054514f5e3Sopenharmony_ci 2064514f5e3Sopenharmony_ci bool success = true; 2074514f5e3Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 2084514f5e3Sopenharmony_ci UPluralType icuType = UPLURAL_TYPE_CARDINAL; 2094514f5e3Sopenharmony_ci // Trans typeOption to ICU typeOption 2104514f5e3Sopenharmony_ci switch (type) { 2114514f5e3Sopenharmony_ci case TypeOption::ORDINAL: 2124514f5e3Sopenharmony_ci icuType = UPLURAL_TYPE_ORDINAL; 2134514f5e3Sopenharmony_ci break; 2144514f5e3Sopenharmony_ci case TypeOption::CARDINAL: 2154514f5e3Sopenharmony_ci icuType = UPLURAL_TYPE_CARDINAL; 2164514f5e3Sopenharmony_ci break; 2174514f5e3Sopenharmony_ci default: 2184514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 2194514f5e3Sopenharmony_ci UNREACHABLE(); 2204514f5e3Sopenharmony_ci } 2214514f5e3Sopenharmony_ci std::unique_ptr<icu::PluralRules> icuPluralRules(icu::PluralRules::forLocale(icuLocale, icuType, status)); 2224514f5e3Sopenharmony_ci if (U_FAILURE(status)) { // NOLINT(readability-implicit-bool-conversion) 2234514f5e3Sopenharmony_ci success = false; 2244514f5e3Sopenharmony_ci } 2254514f5e3Sopenharmony_ci 2264514f5e3Sopenharmony_ci // Trans typeOption to ICU typeOption 2274514f5e3Sopenharmony_ci if (!success || icuPluralRules == nullptr) { 2284514f5e3Sopenharmony_ci icu::Locale noExtensionLocale(icuLocale.getBaseName()); 2294514f5e3Sopenharmony_ci status = U_ZERO_ERROR; 2304514f5e3Sopenharmony_ci switch (type) { 2314514f5e3Sopenharmony_ci case TypeOption::ORDINAL: 2324514f5e3Sopenharmony_ci icuType = UPLURAL_TYPE_ORDINAL; 2334514f5e3Sopenharmony_ci break; 2344514f5e3Sopenharmony_ci case TypeOption::CARDINAL: 2354514f5e3Sopenharmony_ci icuType = UPLURAL_TYPE_CARDINAL; 2364514f5e3Sopenharmony_ci break; 2374514f5e3Sopenharmony_ci default: 2384514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 2394514f5e3Sopenharmony_ci UNREACHABLE(); 2404514f5e3Sopenharmony_ci } 2414514f5e3Sopenharmony_ci icuPluralRules.reset(icu::PluralRules::forLocale(icuLocale, icuType, status)); 2424514f5e3Sopenharmony_ci } 2434514f5e3Sopenharmony_ci if (U_FAILURE(status) || icuPluralRules == nullptr) { // NOLINT(readability-implicit-bool-conversion) 2444514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "cannot create icuPluralRules", pluralRules); 2454514f5e3Sopenharmony_ci } 2464514f5e3Sopenharmony_ci 2474514f5e3Sopenharmony_ci // 9. Perform ? SetNumberFormatDigitOptions(pluralRules, options, 0, 3, "standard"). 2484514f5e3Sopenharmony_ci JSLocale::SetNumberFormatDigitOptions(thread, pluralRules, JSHandle<JSTaggedValue>::Cast(prOptions), MNFD_DEFAULT, 2494514f5e3Sopenharmony_ci MXFD_DEFAULT, NotationOption::STANDARD); 2504514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSPluralRules, thread); 2514514f5e3Sopenharmony_ci icuNumberFormatter = JSNumberFormat::SetICUFormatterDigitOptions(icuNumberFormatter, pluralRules); 2524514f5e3Sopenharmony_ci 2534514f5e3Sopenharmony_ci // Set pluralRules.[[IcuPluralRules]] to icuPluralRules 2544514f5e3Sopenharmony_ci SetIcuPluralRules(thread, pluralRules, *icuPluralRules, JSPluralRules::FreeIcuPluralRules); 2554514f5e3Sopenharmony_ci 2564514f5e3Sopenharmony_ci // Set pluralRules.[[IcuNumberFormat]] to icuNumberFormatter 2574514f5e3Sopenharmony_ci SetIcuNumberFormatter(thread, pluralRules, icuNumberFormatter, JSPluralRules::FreeIcuNumberFormatter); 2584514f5e3Sopenharmony_ci 2594514f5e3Sopenharmony_ci // 12. Set pluralRules.[[Locale]] to the value of r.[[locale]]. 2604514f5e3Sopenharmony_ci JSHandle<EcmaString> localeStr = intl::LocaleHelper::ToLanguageTag(thread, icuLocale); 2614514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSPluralRules, thread); 2624514f5e3Sopenharmony_ci pluralRules->SetLocale(thread, localeStr.GetTaggedValue()); 2634514f5e3Sopenharmony_ci 2644514f5e3Sopenharmony_ci // 13. Return pluralRules. 2654514f5e3Sopenharmony_ci return pluralRules; 2664514f5e3Sopenharmony_ci} 2674514f5e3Sopenharmony_ci 2684514f5e3Sopenharmony_ciJSHandle<EcmaString> FormatNumericToString(JSThread *thread, const icu::number::LocalizedNumberFormatter *icuFormatter, 2694514f5e3Sopenharmony_ci const icu::PluralRules *icuPluralRules, double n) 2704514f5e3Sopenharmony_ci{ 2714514f5e3Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 2724514f5e3Sopenharmony_ci icu::number::FormattedNumber formatted = icuFormatter->formatDouble(n, status); 2734514f5e3Sopenharmony_ci if (U_FAILURE(status)) { // NOLINT(readability-implicit-bool-conversion) 2744514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> exception(thread, JSTaggedValue::Exception()); 2754514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "invalid resolve number", JSHandle<EcmaString>::Cast(exception)); 2764514f5e3Sopenharmony_ci } 2774514f5e3Sopenharmony_ci 2784514f5e3Sopenharmony_ci icu::UnicodeString uString = icuPluralRules->select(formatted, status); 2794514f5e3Sopenharmony_ci if (U_FAILURE(status)) { // NOLINT(readability-implicit-bool-conversion) 2804514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> exception(thread, JSTaggedValue::Exception()); 2814514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "invalid resolve number", JSHandle<EcmaString>::Cast(exception)); 2824514f5e3Sopenharmony_ci } 2834514f5e3Sopenharmony_ci 2844514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 2854514f5e3Sopenharmony_ci JSHandle<EcmaString> result = 2864514f5e3Sopenharmony_ci factory->NewFromUtf16(reinterpret_cast<const uint16_t *>(uString.getBuffer()), uString.length()); 2874514f5e3Sopenharmony_ci return result; 2884514f5e3Sopenharmony_ci} 2894514f5e3Sopenharmony_ciJSHandle<EcmaString> JSPluralRules::ResolvePlural(JSThread *thread, const JSHandle<JSPluralRules> &pluralRules, 2904514f5e3Sopenharmony_ci double n) 2914514f5e3Sopenharmony_ci{ 2924514f5e3Sopenharmony_ci icu::PluralRules *icuPluralRules = pluralRules->GetIcuPluralRules(); 2934514f5e3Sopenharmony_ci icu::number::LocalizedNumberFormatter *icuFormatter = pluralRules->GetIcuNumberFormatter(); 2944514f5e3Sopenharmony_ci if (icuPluralRules == nullptr || icuFormatter == nullptr) { 2954514f5e3Sopenharmony_ci return JSHandle<EcmaString>(thread, JSTaggedValue::Undefined()); 2964514f5e3Sopenharmony_ci } 2974514f5e3Sopenharmony_ci 2984514f5e3Sopenharmony_ci JSHandle<EcmaString> result = FormatNumericToString(thread, icuFormatter, icuPluralRules, n); 2994514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(EcmaString, thread); 3004514f5e3Sopenharmony_ci return result; 3014514f5e3Sopenharmony_ci} 3024514f5e3Sopenharmony_ci 3034514f5e3Sopenharmony_civoid JSPluralRules::ResolvedOptions(JSThread *thread, const JSHandle<JSPluralRules> &pluralRules, 3044514f5e3Sopenharmony_ci const JSHandle<JSObject> &options) 3054514f5e3Sopenharmony_ci{ 3064514f5e3Sopenharmony_ci EcmaVM *ecmaVm = thread->GetEcmaVM(); 3074514f5e3Sopenharmony_ci ObjectFactory *factory = ecmaVm->GetFactory(); 3084514f5e3Sopenharmony_ci auto globalConst = thread->GlobalConstants(); 3094514f5e3Sopenharmony_ci 3104514f5e3Sopenharmony_ci // [[Locale]] 3114514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> property = JSHandle<JSTaggedValue>::Cast(globalConst->GetHandledLocaleString()); 3124514f5e3Sopenharmony_ci JSHandle<EcmaString> locale(thread, pluralRules->GetLocale()); 3134514f5e3Sopenharmony_ci PropertyDescriptor localeDesc(thread, JSHandle<JSTaggedValue>::Cast(locale), true, true, true); 3144514f5e3Sopenharmony_ci JSObject::DefineOwnProperty(thread, options, property, localeDesc); 3154514f5e3Sopenharmony_ci 3164514f5e3Sopenharmony_ci // [[type]] 3174514f5e3Sopenharmony_ci property = JSHandle<JSTaggedValue>::Cast(globalConst->GetHandledTypeString()); 3184514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> typeValue; 3194514f5e3Sopenharmony_ci if (pluralRules->GetType() == TypeOption::CARDINAL) { 3204514f5e3Sopenharmony_ci typeValue = globalConst->GetHandledCardinalString(); 3214514f5e3Sopenharmony_ci } else { 3224514f5e3Sopenharmony_ci typeValue = globalConst->GetHandledOrdinalString(); 3234514f5e3Sopenharmony_ci } 3244514f5e3Sopenharmony_ci PropertyDescriptor typeDesc(thread, typeValue, true, true, true); 3254514f5e3Sopenharmony_ci JSObject::DefineOwnProperty(thread, options, property, typeDesc); 3264514f5e3Sopenharmony_ci 3274514f5e3Sopenharmony_ci // [[MinimumIntegerDigits]] 3284514f5e3Sopenharmony_ci property = JSHandle<JSTaggedValue>::Cast(globalConst->GetHandledMinimumIntegerDigitsString()); 3294514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> minimumIntegerDigits(thread, pluralRules->GetMinimumIntegerDigits()); 3304514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, minimumIntegerDigits); 3314514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 3324514f5e3Sopenharmony_ci 3334514f5e3Sopenharmony_ci RoundingType roundingType = pluralRules->GetRoundingType(); 3344514f5e3Sopenharmony_ci if (roundingType == RoundingType::SIGNIFICANTDIGITS) { 3354514f5e3Sopenharmony_ci // [[MinimumSignificantDigits]] 3364514f5e3Sopenharmony_ci property = globalConst->GetHandledMinimumSignificantDigitsString(); 3374514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> minimumSignificantDigits(thread, pluralRules->GetMinimumSignificantDigits()); 3384514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, minimumSignificantDigits); 3394514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 3404514f5e3Sopenharmony_ci // [[MaximumSignificantDigits]] 3414514f5e3Sopenharmony_ci property = globalConst->GetHandledMaximumSignificantDigitsString(); 3424514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> maximumSignificantDigits(thread, pluralRules->GetMaximumSignificantDigits()); 3434514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, maximumSignificantDigits); 3444514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 3454514f5e3Sopenharmony_ci } else { 3464514f5e3Sopenharmony_ci // [[MinimumFractionDigits]] 3474514f5e3Sopenharmony_ci property = globalConst->GetHandledMinimumFractionDigitsString(); 3484514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> minimumFractionDigits(thread, pluralRules->GetMinimumFractionDigits()); 3494514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, minimumFractionDigits); 3504514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 3514514f5e3Sopenharmony_ci // [[MaximumFractionDigits]] 3524514f5e3Sopenharmony_ci property = globalConst->GetHandledMaximumFractionDigitsString(); 3534514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> maximumFractionDigits(thread, pluralRules->GetMaximumFractionDigits()); 3544514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, maximumFractionDigits); 3554514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 3564514f5e3Sopenharmony_ci } 3574514f5e3Sopenharmony_ci 3584514f5e3Sopenharmony_ci // 5. Let pluralCategories be a List of Strings representing the possible results of PluralRuleSelect 3594514f5e3Sopenharmony_ci // for the selected locale pr.[[Locale]]. This List consists of unique String values, 3604514f5e3Sopenharmony_ci // from the the list "zero", "one", "two", "few", "many" and "other", 3614514f5e3Sopenharmony_ci // that are relevant for the locale whose localization is specified in LDML Language Plural Rules. 3624514f5e3Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 3634514f5e3Sopenharmony_ci icu::PluralRules *icuPluralRules = pluralRules->GetIcuPluralRules(); 3644514f5e3Sopenharmony_ci ASSERT(icuPluralRules != nullptr); 3654514f5e3Sopenharmony_ci std::unique_ptr<icu::StringEnumeration> categories(icuPluralRules->getKeywords(status)); 3664514f5e3Sopenharmony_ci int32_t count = categories->count(status); 3674514f5e3Sopenharmony_ci ASSERT(U_SUCCESS(status)); 3684514f5e3Sopenharmony_ci JSHandle<TaggedArray> pluralCategories = factory->NewTaggedArray(count); 3694514f5e3Sopenharmony_ci for (int32_t i = 0; i < count; i++) { 3704514f5e3Sopenharmony_ci const icu::UnicodeString *category = categories->snext(status); 3714514f5e3Sopenharmony_ci ASSERT(U_SUCCESS(status)); 3724514f5e3Sopenharmony_ci JSHandle<EcmaString> value = intl::LocaleHelper::UStringToString(thread, *category); 3734514f5e3Sopenharmony_ci pluralCategories->Set(thread, i, value); 3744514f5e3Sopenharmony_ci } 3754514f5e3Sopenharmony_ci 3764514f5e3Sopenharmony_ci // 6. Perform ! CreateDataProperty(options, "pluralCategories", CreateArrayFromList(pluralCategories)). 3774514f5e3Sopenharmony_ci property = globalConst->GetHandledPluralCategoriesString(); 3784514f5e3Sopenharmony_ci JSHandle<JSArray> jsPluralCategories = JSArray::CreateArrayFromList(thread, pluralCategories); 3794514f5e3Sopenharmony_ci JSObject::CreateDataPropertyOrThrow(thread, options, property, JSHandle<JSTaggedValue>::Cast(jsPluralCategories)); 3804514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 3814514f5e3Sopenharmony_ci} 3824514f5e3Sopenharmony_ci} // namespace panda::ecmascript 383