1/* 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "ecmascript/js_displaynames.h" 17 18#include <cstring> 19 20#include "ecmascript/intl/locale_helper.h" 21#include "ecmascript/object_factory-inl.h" 22 23#if defined(__clang__) 24#pragma clang diagnostic push 25#pragma clang diagnostic ignored "-Wshadow" 26#elif defined(__GNUC__) 27#pragma GCC diagnostic push 28#pragma GCC diagnostic ignored "-Wshadow" 29#endif 30#include "unicode/localebuilder.h" 31#if defined(__clang__) 32#pragma clang diagnostic pop 33#elif defined(__GNUC__) 34#pragma GCC diagnostic pop 35#endif 36 37namespace panda::ecmascript { 38 39const std::vector<LocaleMatcherOption> JSDisplayNames::LOCALE_MATCHER_OPTION = { 40 LocaleMatcherOption::LOOKUP, LocaleMatcherOption::BEST_FIT 41}; 42const std::vector<std::string> JSDisplayNames::LOCALE_MATCHER_OPTION_NAME = {"lookup", "best fit"}; 43 44const std::vector<StyOption> JSDisplayNames::STY_OPTION = { 45 StyOption::NARROW, StyOption::SHORT, StyOption::LONG 46}; 47const std::vector<std::string> JSDisplayNames::STY_OPTION_NAME = {"narrow", "short", "long"}; 48 49const std::vector<TypednsOption> JSDisplayNames::TYPED_NS_OPTION = { 50 TypednsOption::LANGUAGE, TypednsOption::REGION, 51 TypednsOption::SCRIPT, TypednsOption::CURRENCY, 52 TypednsOption::CALENDAR, TypednsOption::DATETIMEFIELD 53}; 54const std::vector<std::string> JSDisplayNames::TYPED_NS_OPTION_NAME = { 55 "language", "region", "script", "currency", 56 "calendar", "dateTimeField" 57}; 58 59const std::vector<FallbackOption> JSDisplayNames::FALLBACK_OPTION = { 60 FallbackOption::CODE, FallbackOption::NONE 61}; 62const std::vector<std::string> JSDisplayNames::FALLBACK_OPTION_OPTION_NAME = { 63 "code", "none" 64}; 65 66const std::vector<LanguageDisplayOption> JSDisplayNames::LANGUAGE_DISPLAY_OPTION = { 67 LanguageDisplayOption::DIALECT, LanguageDisplayOption::STANDARD 68}; 69const std::vector<std::string> JSDisplayNames::LANGUAGE_DISPLAY_OPTION_NAME = { 70 "dialect", "standard" 71}; 72 73icu::LocaleDisplayNames *JSDisplayNames::GetIcuLocaleDisplayNames() const 74{ 75 ASSERT(GetIcuLDN().IsJSNativePointer()); 76 auto result = JSNativePointer::Cast(GetIcuLDN().GetTaggedObject())->GetExternalPointer(); 77 return reinterpret_cast<icu::LocaleDisplayNames *>(result); 78} 79 80void JSDisplayNames::FreeIcuLocaleDisplayNames([[maybe_unused]] void *env, void *pointer, [[maybe_unused]] void* hint) 81{ 82 if (pointer == nullptr) { 83 return; 84 } 85 auto icuLocaleDisplayNames = reinterpret_cast<icu::LocaleDisplayNames *>(pointer); 86 delete icuLocaleDisplayNames; 87} 88 89void JSDisplayNames::SetIcuLocaleDisplayNames(JSThread *thread, const JSHandle<JSDisplayNames> &displayNames, 90 icu::LocaleDisplayNames* iculocaledisplaynames, 91 const NativePointerCallback &callback) 92{ 93 EcmaVM *ecmaVm = thread->GetEcmaVM(); 94 ObjectFactory *factory = ecmaVm->GetFactory(); 95 96 ASSERT(iculocaledisplaynames != nullptr); 97 JSTaggedValue data = displayNames->GetIcuLDN(); 98 if (data.IsJSNativePointer()) { 99 JSNativePointer *native = JSNativePointer::Cast(data.GetTaggedObject()); 100 native->ResetExternalPointer(thread, iculocaledisplaynames); 101 return; 102 } 103 JSHandle<JSNativePointer> pointer = factory->NewJSNativePointer(iculocaledisplaynames, callback); 104 displayNames->SetIcuLDN(thread, pointer.GetTaggedValue()); 105} 106 107JSHandle<TaggedArray> JSDisplayNames::GetAvailableLocales(JSThread *thread) 108{ 109 const char *key = "calendar"; 110 const char *path = nullptr; 111 std::vector<std::string> availableStringLocales = intl::LocaleHelper::GetAvailableLocales(thread, key, path); 112 JSHandle<TaggedArray> availableLocales = JSLocale::ConstructLocaleList(thread, availableStringLocales); 113 return availableLocales; 114} 115 116namespace { 117 bool IsUnicodeScriptSubtag(const std::string& value) 118 { 119 UErrorCode status = U_ZERO_ERROR; 120 icu::LocaleBuilder builder; 121 builder.setScript(value).build(status); 122 return U_SUCCESS(status); 123 } 124 125 bool IsUnicodeRegionSubtag(const std::string& value) 126 { 127 UErrorCode status = U_ZERO_ERROR; 128 icu::LocaleBuilder builder; 129 builder.setRegion(value).build(status); 130 return U_SUCCESS(status); 131 } 132} 133 134// InitializeDisplayNames ( displayNames, locales, options ) 135JSHandle<JSDisplayNames> JSDisplayNames::InitializeDisplayNames(JSThread *thread, 136 const JSHandle<JSDisplayNames> &displayNames, 137 const JSHandle<JSTaggedValue> &locales, 138 const JSHandle<JSTaggedValue> &options) 139{ 140 [[maybe_unused]] EcmaHandleScope scope(thread); 141 EcmaVM *ecmaVm = thread->GetEcmaVM(); 142 ObjectFactory *factory = ecmaVm->GetFactory(); 143 auto globalConst = thread->GlobalConstants(); 144 // 3. Let requestedLocales be ? CanonicalizeLocaleList(locales). 145 JSHandle<TaggedArray> requestedLocales = intl::LocaleHelper::CanonicalizeLocaleList(thread, locales); 146 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDisplayNames, thread); 147 148 // 4. If options is undefined, throw a TypeError exception. 149 if (options->IsUndefined()) { 150 THROW_TYPE_ERROR_AND_RETURN(thread, "options is undefined", displayNames); 151 } 152 153 // 5. Let options be ? GetOptionsObject(options). 154 JSHandle<JSObject> optionsObject = JSTaggedValue::ToObject(thread, options); 155 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDisplayNames, thread); 156 157 // Note: No need to create a record. It's not observable. 158 // 6. Let opt be a new Record. 159 // 7. Let localeData be %DisplayNames%.[[LocaleData]]. 160 // 8. Let matcher be ? GetOption(options, "localeMatcher", "string", « "lookup", "best fit" », "best fit"). 161 JSHandle<JSTaggedValue> property = globalConst->GetHandledLocaleMatcherString(); 162 auto matcher = JSLocale::GetOptionOfString<LocaleMatcherOption>( 163 thread, optionsObject, property, 164 JSDisplayNames::LOCALE_MATCHER_OPTION, JSDisplayNames::LOCALE_MATCHER_OPTION_NAME, 165 LocaleMatcherOption::BEST_FIT); 166 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDisplayNames, thread); 167 168 // 10. Let r be ResolveLocale(%DisplayNames%.[[AvailableLocales]], requestedLocales, opt, 169 // %DisplayNames%.[[RelevantExtensionKeys]]). 170 JSHandle<TaggedArray> availableLocales; 171 if (requestedLocales->GetLength() == 0) { 172 availableLocales = factory->EmptyArray(); 173 } else { 174 availableLocales = JSDisplayNames::GetAvailableLocales(thread); 175 } 176 std::set<std::string> relevantExtensionKeys {""}; 177 ResolvedLocale r = 178 JSLocale::ResolveLocale(thread, availableLocales, requestedLocales, matcher, relevantExtensionKeys); 179 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDisplayNames, thread); 180 icu::Locale icuLocale = r.localeData; 181 182 // 11. Let style be ? GetOption(options, "style", "string", « "narrow", "short", "long" », "long"). 183 property = globalConst->GetHandledStyleString(); 184 auto StyOpt = JSLocale::GetOptionOfString<StyOption>(thread, optionsObject, property, 185 JSDisplayNames::STY_OPTION, JSDisplayNames::STY_OPTION_NAME, 186 StyOption::LONG); 187 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDisplayNames, thread); 188 189 // 12. Set DisplayNames.[[Style]] to style. 190 displayNames->SetStyle(StyOpt); 191 192 // 13. Let type be ? GetOption(options, "type", "string", « "language", "region", "script", "currency" », 193 // "undefined"). 194 property = globalConst->GetHandledTypeString(); 195 auto type = JSLocale::GetOptionOfString<TypednsOption>(thread, optionsObject, property, 196 JSDisplayNames::TYPED_NS_OPTION, JSDisplayNames::TYPED_NS_OPTION_NAME, 197 TypednsOption::UNDEFINED); 198 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDisplayNames, thread); 199 200 // 14. If type is undefined, throw a TypeError exception. 201 if (type == TypednsOption::UNDEFINED) { 202 THROW_TYPE_ERROR_AND_RETURN(thread, "type is undefined", displayNames); 203 } 204 205 // 15. Set displayNames.[[Type]] to type. 206 displayNames->SetType(type); 207 208 // 16. Let fallback be ? GetOption(options, "fallback", "string", « "code", "none" », "code"). 209 property = globalConst->GetHandledFallbackString(); 210 auto fallback = JSLocale::GetOptionOfString<FallbackOption>(thread, optionsObject, property, 211 JSDisplayNames::FALLBACK_OPTION, JSDisplayNames::FALLBACK_OPTION_OPTION_NAME, 212 FallbackOption::CODE); 213 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDisplayNames, thread); 214 215 // 17. Set displayNames.[[Fallback]] to fallback. 216 displayNames->SetFallback(fallback); 217 218 // Let languageDisplay be ? GetOption(options, "languageDisplay", string, « "dialect", "standard" », "dialect"). 219 property = globalConst->GetHandledLanguageDisplayString(); 220 auto langDisplay = JSLocale::GetOptionOfString<LanguageDisplayOption>( 221 thread, optionsObject, property, 222 JSDisplayNames::LANGUAGE_DISPLAY_OPTION, 223 JSDisplayNames::LANGUAGE_DISPLAY_OPTION_NAME, LanguageDisplayOption::DIALECT); 224 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDisplayNames, thread); 225 displayNames->SetLanguageDisplay(langDisplay); 226 227 // 18. Set displayNames.[[Locale]] to the value of r.[[Locale]]. 228 JSHandle<EcmaString> localeStr = intl::LocaleHelper::ToLanguageTag(thread, icuLocale); 229 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDisplayNames, thread); 230 displayNames->SetLocale(thread, localeStr.GetTaggedValue()); 231 // 19. Let dataLocale be r.[[dataLocale]]. 232 // 20. Let dataLocaleData be localeData.[[<dataLocale>]]. 233 // 21. Let types be dataLocaleData.[[types]]. 234 // 22. Assert: types is a Record (see 12.3.3). 235 // 23. Let typeFields be types.[[<type>]]. 236 // 24. Assert: typeFields is a Record (see 12.3.3). 237 // 25. Let styleFields be typeFields.[[<style>]]. 238 // 26. Assert: styleFields is a Record (see 12.3.3). 239 // 27. Set displayNames.[[Fields]] to styleFields. 240 // 28. Return displayNames. 241 242 // Trans StyOption to ICU Style 243 UDisplayContext uStyle; 244 switch (StyOpt) { 245 case StyOption::LONG: 246 uStyle = UDISPCTX_LENGTH_FULL; 247 break; 248 case StyOption::SHORT: 249 uStyle = UDISPCTX_LENGTH_SHORT; 250 break; 251 case StyOption::NARROW: 252 uStyle = UDISPCTX_LENGTH_SHORT; 253 break; 254 default: 255 LOG_ECMA(FATAL) << "this branch is unreachable"; 256 UNREACHABLE(); 257 } 258 UDisplayContext displayContext[] = {uStyle}; 259 icu::LocaleDisplayNames *icudisplaynames(icu::LocaleDisplayNames::createInstance(icuLocale, displayContext, 1)); 260 if (icudisplaynames == nullptr) { 261 delete icudisplaynames; 262 THROW_RANGE_ERROR_AND_RETURN(thread, "create icu::LocaleDisplayNames failed", displayNames); 263 } 264 SetIcuLocaleDisplayNames(thread, displayNames, icudisplaynames, JSDisplayNames::FreeIcuLocaleDisplayNames); 265 return displayNames; 266} 267 268// CanonicalCodeForDisplayNames ( type, code ) 269JSHandle<EcmaString> JSDisplayNames::CanonicalCodeForDisplayNames(JSThread *thread, 270 const JSHandle<JSDisplayNames> &displayNames, 271 const TypednsOption &typeOpt, 272 const JSHandle<EcmaString> &code) 273{ 274 if (typeOpt == TypednsOption::LANGUAGE) { 275 // a. If code does not match the unicode_language_id production, throw a RangeError exception. 276 UErrorCode status = U_ZERO_ERROR; 277 std::string codeSt = intl::LocaleHelper::ConvertToStdString(code); 278 icu::Locale loc = icu::Locale(icu::Locale::forLanguageTag(codeSt, status).getBaseName()); 279 std::string checked = loc.toLanguageTag<std::string>(status); 280 if (checked.size() == 0) { 281 THROW_TYPE_ERROR_AND_RETURN(thread, "not match the language id", code); 282 } 283 if (U_FAILURE(status)) { 284 THROW_TYPE_ERROR_AND_RETURN(thread, "not match the unicode_language_id", code); 285 } 286 // b. If IsStructurallyValidLanguageTag(code) is false, throw a RangeError exception. 287 // c. Set code to CanonicalizeUnicodeLocaleId(code). 288 // d. Return code. 289 if (!intl::LocaleHelper::IsStructurallyValidLanguageTag(code)) { 290 THROW_TYPE_ERROR_AND_RETURN(thread, "not a structurally valid", code); 291 } 292 JSHandle<EcmaString> codeStr = intl::LocaleHelper::CanonicalizeUnicodeLocaleId(thread, code); 293 RETURN_HANDLE_IF_ABRUPT_COMPLETION(EcmaString, thread); 294 icu::LocaleDisplayNames *icuLocaldisplaynames = displayNames->GetIcuLocaleDisplayNames(); 295 icu::UnicodeString result; 296 std::string codeString = intl::LocaleHelper::ConvertToStdString(codeStr); 297 icuLocaldisplaynames->languageDisplayName(codeString.c_str(), result); 298 JSHandle<EcmaString> codeResult = intl::LocaleHelper::UStringToString(thread, result); 299 return codeResult; 300 } else if (typeOpt == TypednsOption::REGION) { 301 // a. If code does not match the unicode_region_subtag production, throw a RangeError exception. 302 std::string regionCode = intl::LocaleHelper::ConvertToStdString(code); 303 if (!IsUnicodeRegionSubtag(regionCode)) { 304 THROW_RANGE_ERROR_AND_RETURN(thread, "invalid region", code); 305 } 306 // b. Let code be the result of mapping code to upper case as described in 6.1. 307 // c. Return code. 308 icu::LocaleDisplayNames *icuLocaldisplaynames = displayNames->GetIcuLocaleDisplayNames(); 309 icu::UnicodeString result; 310 icuLocaldisplaynames->regionDisplayName(regionCode.c_str(), result); 311 JSHandle<EcmaString> codeResult = intl::LocaleHelper::UStringToString(thread, result); 312 return codeResult; 313 } else if (typeOpt == TypednsOption::SCRIPT) { 314 std::string scriptCode = intl::LocaleHelper::ConvertToStdString(code); 315 if (!IsUnicodeScriptSubtag(scriptCode)) { 316 THROW_RANGE_ERROR_AND_RETURN(thread, "invalid script", code); 317 } 318 icu::LocaleDisplayNames *icuLocaldisplaynames = displayNames->GetIcuLocaleDisplayNames(); 319 icu::UnicodeString result; 320 icuLocaldisplaynames->scriptDisplayName(scriptCode.c_str(), result); 321 JSHandle<EcmaString> codeResult = intl::LocaleHelper::UStringToString(thread, result); 322 return codeResult; 323 } else if (typeOpt == TypednsOption::CALENDAR) { 324 std::string calendarCode = intl::LocaleHelper::ConvertToStdString(code); 325 if (!JSLocale::IsWellFormedCalendarCode(calendarCode)) { 326 THROW_RANGE_ERROR_AND_RETURN(thread, "invalid calendar", code); 327 } 328 329 icu::LocaleDisplayNames *icuLocaldisplaynames = displayNames->GetIcuLocaleDisplayNames(); 330 icu::UnicodeString result; 331 std::string calendarStrCode = std::strcmp(calendarCode.c_str(), "gregory") == 0 332 ? "gregorian" 333 : std::strcmp(calendarCode.c_str(), "ethioaa") == 0 334 ? "ethiopic-amete-alem" 335 : calendarCode; 336 icuLocaldisplaynames->keyValueDisplayName("calendar", calendarStrCode.c_str(), result); 337 JSHandle<EcmaString> codeResult = intl::LocaleHelper::UStringToString(thread, result); 338 return codeResult; 339 } else if (typeOpt == TypednsOption::DATETIMEFIELD) { 340 StyOption style = displayNames->GetStyle(); 341 UDateTimePGDisplayWidth width; 342 switch (style) { 343 case StyOption::LONG: 344 width = UDATPG_WIDE; 345 break; 346 case StyOption::SHORT: 347 width = UDATPG_ABBREVIATED; 348 break; 349 case StyOption::NARROW: 350 width = UDATPG_NARROW; 351 break; 352 default: 353 break; 354 } 355 std::string datetimeCode = intl::LocaleHelper::ConvertToStdString(code); 356 UDateTimePatternField field = StringToUDateTimePatternField(datetimeCode.c_str()); 357 if (field == UDATPG_FIELD_COUNT) { 358 THROW_RANGE_ERROR_AND_RETURN(thread, "invalid datetimefield", code); 359 } 360 361 UErrorCode status = U_ZERO_ERROR; 362 icu::LocaleDisplayNames *icuLocaldisplaynames = displayNames->GetIcuLocaleDisplayNames(); 363 icu::Locale locales = icuLocaldisplaynames->getLocale(); 364 std::unique_ptr<icu::DateTimePatternGenerator> generator( 365 icu::DateTimePatternGenerator::createInstance(locales, status)); 366 icu::UnicodeString result = generator->getFieldDisplayName(field, width); 367 return intl::LocaleHelper::UStringToString(thread, result); 368 } 369 // 4. 4. Assert: type is "currency". 370 // 5. If ! IsWellFormedCurrencyCode(code) is false, throw a RangeError exception. 371 ASSERT(typeOpt == TypednsOption::CURRENCY); 372 std::string cCode = intl::LocaleHelper::ConvertToStdString(code); 373 if (!JSLocale::IsWellFormedCurrencyCode(cCode)) { 374 THROW_RANGE_ERROR_AND_RETURN(thread, "not a wellformed currency code", code); 375 } 376 icu::LocaleDisplayNames *icuLocaldisplaynames = displayNames->GetIcuLocaleDisplayNames(); 377 icu::UnicodeString result; 378 icuLocaldisplaynames->keyValueDisplayName("currency", cCode.c_str(), result); 379 JSHandle<EcmaString> codeResult = intl::LocaleHelper::UStringToString(thread, result); 380 return codeResult; 381} 382 383UDateTimePatternField JSDisplayNames::StringToUDateTimePatternField(const char* code) 384{ 385 if (std::strcmp(code, "day") == 0) { 386 return UDATPG_DAY_FIELD; 387 } 388 if (std::strcmp(code, "dayPeriod") == 0) { 389 return UDATPG_DAYPERIOD_FIELD; 390 } 391 if (std::strcmp(code, "era") == 0) { 392 return UDATPG_ERA_FIELD; 393 } 394 if (std::strcmp(code, "hour") == 0) { 395 return UDATPG_HOUR_FIELD; 396 } 397 if (std::strcmp(code, "minute") == 0) { 398 return UDATPG_MINUTE_FIELD; 399 } 400 if (std::strcmp(code, "month") == 0) { 401 return UDATPG_MONTH_FIELD; 402 } 403 if (std::strcmp(code, "quarter") == 0) { 404 return UDATPG_QUARTER_FIELD; 405 } 406 if (std::strcmp(code, "second") == 0) { 407 return UDATPG_SECOND_FIELD; 408 } 409 if (std::strcmp(code, "timeZoneName") == 0) { 410 return UDATPG_ZONE_FIELD; 411 } 412 if (std::strcmp(code, "weekOfYear") == 0) { 413 return UDATPG_WEEK_OF_YEAR_FIELD; 414 } 415 if (std::strcmp(code, "weekday") == 0) { 416 return UDATPG_WEEKDAY_FIELD; 417 } 418 if (std::strcmp(code, "year") == 0) { 419 return UDATPG_YEAR_FIELD; 420 } 421 return UDATPG_FIELD_COUNT; 422} 423 424JSHandle<JSTaggedValue> StyOptionToEcmaString(JSThread *thread, StyOption style) 425{ 426 JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined()); 427 auto globalConst = thread->GlobalConstants(); 428 switch (style) { 429 case StyOption::LONG: 430 result.Update(globalConst->GetHandledLongString().GetTaggedValue()); 431 break; 432 case StyOption::SHORT: 433 result.Update(globalConst->GetHandledShortString().GetTaggedValue()); 434 break; 435 case StyOption::NARROW: 436 result.Update(globalConst->GetHandledNarrowString().GetTaggedValue()); 437 break; 438 default: 439 LOG_ECMA(FATAL) << "this branch is unreachable"; 440 UNREACHABLE(); 441 } 442 return result; 443} 444 445JSHandle<JSTaggedValue> TypeOptionToEcmaString(JSThread *thread, TypednsOption type) 446{ 447 JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined()); 448 auto globalConst = thread->GlobalConstants(); 449 switch (type) { 450 case TypednsOption::LANGUAGE: 451 result.Update(globalConst->GetHandledLanguageString().GetTaggedValue()); 452 break; 453 case TypednsOption::CALENDAR: 454 result.Update(globalConst->GetHandledCalendarString().GetTaggedValue()); 455 break; 456 case TypednsOption::CURRENCY: 457 result.Update(globalConst->GetHandledCurrencyString().GetTaggedValue()); 458 break; 459 case TypednsOption::DATETIMEFIELD: 460 result.Update(globalConst->GetHandledDateTimeFieldString().GetTaggedValue()); 461 break; 462 case TypednsOption::REGION: 463 result.Update(globalConst->GetHandledRegionString().GetTaggedValue()); 464 break; 465 case TypednsOption::SCRIPT: 466 result.Update(globalConst->GetHandledScriptString().GetTaggedValue()); 467 break; 468 default: 469 LOG_ECMA(FATAL) << "this branch is unreachable"; 470 UNREACHABLE(); 471 } 472 return result; 473} 474 475JSHandle<JSTaggedValue> FallbackOptionToEcmaString(JSThread *thread, FallbackOption fallback) 476{ 477 JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined()); 478 auto globalConst = thread->GlobalConstants(); 479 switch (fallback) { 480 case FallbackOption::CODE: 481 result.Update(globalConst->GetHandledCodeString().GetTaggedValue()); 482 break; 483 case FallbackOption::NONE: 484 result.Update(globalConst->GetHandledNoneString().GetTaggedValue()); 485 break; 486 default: 487 LOG_ECMA(FATAL) << "this branch is unreachable"; 488 UNREACHABLE(); 489 } 490 return result; 491} 492 493JSHandle<JSTaggedValue> LanguageDisplayOptionToEcmaString(JSThread *thread, LanguageDisplayOption langDisplay) 494{ 495 JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined()); 496 auto globalConst = thread->GlobalConstants(); 497 switch (langDisplay) { 498 case LanguageDisplayOption::DIALECT: 499 result.Update(globalConst->GetHandledDialectString().GetTaggedValue()); 500 break; 501 case LanguageDisplayOption::STANDARD: 502 result.Update(globalConst->GetHandledStandardString().GetTaggedValue()); 503 break; 504 default: 505 LOG_ECMA(FATAL) << "this branch is unreachable"; 506 UNREACHABLE(); 507 } 508 return result; 509} 510 511void JSDisplayNames::ResolvedOptions(JSThread *thread, const JSHandle<JSDisplayNames> &displayNames, 512 const JSHandle<JSObject> &options) 513{ 514 auto globalConst = thread->GlobalConstants(); 515 516 // [[Locale]] 517 JSHandle<JSTaggedValue> propertyKey = globalConst->GetHandledLocaleString(); 518 JSHandle<JSTaggedValue> locale(thread, displayNames->GetLocale()); 519 JSObject::CreateDataPropertyOrThrow(thread, options, propertyKey, locale); 520 RETURN_IF_ABRUPT_COMPLETION(thread); 521 522 // [[Style]] 523 StyOption style = displayNames->GetStyle(); 524 propertyKey = globalConst->GetHandledStyleString(); 525 JSHandle<JSTaggedValue> styleString = StyOptionToEcmaString(thread, style); 526 JSObject::CreateDataPropertyOrThrow(thread, options, propertyKey, styleString); 527 RETURN_IF_ABRUPT_COMPLETION(thread); 528 529 // [[type]] 530 TypednsOption type = displayNames->GetType(); 531 propertyKey = globalConst->GetHandledTypeString(); 532 JSHandle<JSTaggedValue> typeString = TypeOptionToEcmaString(thread, type); 533 JSObject::CreateDataPropertyOrThrow(thread, options, propertyKey, typeString); 534 RETURN_IF_ABRUPT_COMPLETION(thread); 535 536 // [[fallback]] 537 FallbackOption fallback = displayNames->GetFallback(); 538 propertyKey = globalConst->GetHandledFallbackString(); 539 JSHandle<JSTaggedValue> fallbackString = FallbackOptionToEcmaString(thread, fallback); 540 JSObject::CreateDataPropertyOrThrow(thread, options, propertyKey, fallbackString); 541 RETURN_IF_ABRUPT_COMPLETION(thread); 542 543 // [[languageDisplay]] 544 // The default languageDisplay is 'dialect' if type is 'language' 545 if (type == TypednsOption::LANGUAGE) { 546 LanguageDisplayOption langDisplay = displayNames->GetLanguageDisplay(); 547 propertyKey = globalConst->GetHandledLanguageDisplayString(); 548 JSHandle<JSTaggedValue> langDisplayString = LanguageDisplayOptionToEcmaString(thread, langDisplay); 549 JSObject::CreateDataPropertyOrThrow(thread, options, propertyKey, langDisplayString); 550 RETURN_IF_ABRUPT_COMPLETION(thread); 551 } 552} 553} // namespace panda::ecmascript 554