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