• 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 
19 #include "ecmascript/intl/locale_helper.h"
20 #include "ecmascript/object_factory-inl.h"
21 
22 #if defined(__clang__)
23 #pragma clang diagnostic push
24 #pragma clang diagnostic ignored "-Wshadow"
25 #elif defined(__GNUC__)
26 #pragma GCC diagnostic push
27 #pragma GCC diagnostic ignored "-Wshadow"
28 #endif
29 #include "unicode/localebuilder.h"
30 #if defined(__clang__)
31 #pragma clang diagnostic pop
32 #elif defined(__GNUC__)
33 #pragma GCC diagnostic pop
34 #endif
35 
36 namespace panda::ecmascript {
37 
38 const std::vector<LocaleMatcherOption> JSDisplayNames::LOCALE_MATCHER_OPTION = {
39     LocaleMatcherOption::LOOKUP, LocaleMatcherOption::BEST_FIT
40 };
41 const std::vector<std::string> JSDisplayNames::LOCALE_MATCHER_OPTION_NAME = {"lookup", "best fit"};
42 
43 const std::vector<StyOption> JSDisplayNames::STY_OPTION = {
44     StyOption::NARROW, StyOption::SHORT, StyOption::LONG
45 };
46 const std::vector<std::string> JSDisplayNames::STY_OPTION_NAME = {"narrow", "short", "long"};
47 
48 const std::vector<TypednsOption> JSDisplayNames::TYPED_NS_OPTION = {
49     TypednsOption::LANGUAGE, TypednsOption::REGION,
50     TypednsOption::SCRIPT, TypednsOption::CURRENCY,
51     TypednsOption::CALENDAR, TypednsOption::DATETIMEFIELD
52 };
53 const std::vector<std::string> JSDisplayNames::TYPED_NS_OPTION_NAME = {
54     "language", "region", "script", "currency",
55     "calendar", "dateTimeField"
56 };
57 
58 const std::vector<FallbackOption> JSDisplayNames::FALLBACK_OPTION = {
59     FallbackOption::CODE, FallbackOption::NONE
60 };
61 const std::vector<std::string> JSDisplayNames::FALLBACK_OPTION_OPTION_NAME = {
62     "code", "none"
63 };
64 
65 const std::vector<LanguageDisplayOption> JSDisplayNames::LANGUAGE_DISPLAY_OPTION = {
66     LanguageDisplayOption::DIALECT, LanguageDisplayOption::STANDARD
67 };
68 const std::vector<std::string> JSDisplayNames::LANGUAGE_DISPLAY_OPTION_NAME = {
69     "dialect", "standard"
70 };
71 
GetIcuLocaleDisplayNames() const72 icu::LocaleDisplayNames *JSDisplayNames::GetIcuLocaleDisplayNames() const
73 {
74     ASSERT(GetIcuLDN().IsJSNativePointer());
75     auto result = JSNativePointer::Cast(GetIcuLDN().GetTaggedObject())->GetExternalPointer();
76     return reinterpret_cast<icu::LocaleDisplayNames *>(result);
77 }
78 
FreeIcuLocaleDisplayNames(void * env,void * pointer,void * hint)79 void JSDisplayNames::FreeIcuLocaleDisplayNames([[maybe_unused]] void *env, void *pointer, [[maybe_unused]] void* hint)
80 {
81     if (pointer == nullptr) {
82         return;
83     }
84     auto icuLocaleDisplayNames = reinterpret_cast<icu::LocaleDisplayNames *>(pointer);
85     delete icuLocaleDisplayNames;
86 }
87 
SetIcuLocaleDisplayNames(JSThread * thread,const JSHandle<JSDisplayNames> & displayNames,icu::LocaleDisplayNames * iculocaledisplaynames,const NativePointerCallback & callback)88 void JSDisplayNames::SetIcuLocaleDisplayNames(JSThread *thread, const JSHandle<JSDisplayNames> &displayNames,
89                                               icu::LocaleDisplayNames* iculocaledisplaynames,
90                                               const NativePointerCallback &callback)
91 {
92     EcmaVM *ecmaVm = thread->GetEcmaVM();
93     ObjectFactory *factory = ecmaVm->GetFactory();
94 
95     ASSERT(iculocaledisplaynames != nullptr);
96     JSTaggedValue data = displayNames->GetIcuLDN();
97     if (data.IsJSNativePointer()) {
98         JSNativePointer *native = JSNativePointer::Cast(data.GetTaggedObject());
99         native->ResetExternalPointer(thread, iculocaledisplaynames);
100         return;
101     }
102     JSHandle<JSNativePointer> pointer = factory->NewJSNativePointer(iculocaledisplaynames, callback);
103     displayNames->SetIcuLDN(thread, pointer.GetTaggedValue());
104 }
105 
GetAvailableLocales(JSThread * thread)106 JSHandle<TaggedArray> JSDisplayNames::GetAvailableLocales(JSThread *thread)
107 {
108     const char *key = "calendar";
109     const char *path = nullptr;
110     std::vector<std::string> availableStringLocales = intl::LocaleHelper::GetAvailableLocales(thread, key, path);
111     JSHandle<TaggedArray> availableLocales = JSLocale::ConstructLocaleList(thread, availableStringLocales);
112     return availableLocales;
113 }
114 
115 namespace {
IsUnicodeScriptSubtag(const std::string & value)116     bool IsUnicodeScriptSubtag(const std::string& value)
117     {
118         UErrorCode status = U_ZERO_ERROR;
119         icu::LocaleBuilder builder;
120         builder.setScript(value).build(status);
121         return U_SUCCESS(status);
122     }
123 
IsUnicodeRegionSubtag(const std::string & value)124     bool IsUnicodeRegionSubtag(const std::string& value)
125     {
126         UErrorCode status = U_ZERO_ERROR;
127         icu::LocaleBuilder builder;
128         builder.setRegion(value).build(status);
129         return U_SUCCESS(status);
130     }
131 }
132 
133 // InitializeDisplayNames ( displayNames, locales, options )
InitializeDisplayNames(JSThread * thread,const JSHandle<JSDisplayNames> & displayNames,const JSHandle<JSTaggedValue> & locales,const JSHandle<JSTaggedValue> & options)134 JSHandle<JSDisplayNames> JSDisplayNames::InitializeDisplayNames(JSThread *thread,
135                                                                 const JSHandle<JSDisplayNames> &displayNames,
136                                                                 const JSHandle<JSTaggedValue> &locales,
137                                                                 const JSHandle<JSTaggedValue> &options)
138 {
139     [[maybe_unused]] EcmaHandleScope scope(thread);
140     EcmaVM *ecmaVm = thread->GetEcmaVM();
141     ObjectFactory *factory = ecmaVm->GetFactory();
142     auto globalConst = thread->GlobalConstants();
143     // 3. Let requestedLocales be ? CanonicalizeLocaleList(locales).
144     JSHandle<TaggedArray> requestedLocales = intl::LocaleHelper::CanonicalizeLocaleList(thread, locales);
145     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDisplayNames, thread);
146 
147     // 4. If options is undefined, throw a TypeError exception.
148     if (options->IsUndefined()) {
149         THROW_TYPE_ERROR_AND_RETURN(thread, "options is undefined", displayNames);
150     }
151 
152     // 5. Let options be ? GetOptionsObject(options).
153     JSHandle<JSObject> optionsObject = JSTaggedValue::ToObject(thread, options);
154     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDisplayNames, thread);
155 
156     // Note: No need to create a record. It's not observable.
157     // 6. Let opt be a new Record.
158     // 7. Let localeData be %DisplayNames%.[[LocaleData]].
159     // 8. Let matcher be ? GetOption(options, "localeMatcher", "string", « "lookup", "best fit" », "best fit").
160     JSHandle<JSTaggedValue> property = globalConst->GetHandledLocaleMatcherString();
161     auto matcher = JSLocale::GetOptionOfString<LocaleMatcherOption>(
162         thread, optionsObject, property,
163         JSDisplayNames::LOCALE_MATCHER_OPTION, JSDisplayNames::LOCALE_MATCHER_OPTION_NAME,
164         LocaleMatcherOption::BEST_FIT);
165     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDisplayNames, thread);
166 
167     // 10. Let r be ResolveLocale(%DisplayNames%.[[AvailableLocales]], requestedLocales, opt,
168     // %DisplayNames%.[[RelevantExtensionKeys]]).
169     JSHandle<TaggedArray> availableLocales;
170     if (requestedLocales->GetLength() == 0) {
171         availableLocales = factory->EmptyArray();
172     } else {
173         availableLocales = JSDisplayNames::GetAvailableLocales(thread);
174     }
175     std::set<std::string> relevantExtensionKeys {""};
176     ResolvedLocale r =
177         JSLocale::ResolveLocale(thread, availableLocales, requestedLocales, matcher, relevantExtensionKeys);
178     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDisplayNames, thread);
179     icu::Locale icuLocale = r.localeData;
180 
181     // 11. Let style be ? GetOption(options, "style", "string", « "narrow", "short", "long" », "long").
182     property = globalConst->GetHandledStyleString();
183     auto StyOpt = JSLocale::GetOptionOfString<StyOption>(thread, optionsObject, property,
184         JSDisplayNames::STY_OPTION, JSDisplayNames::STY_OPTION_NAME,
185         StyOption::LONG);
186     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDisplayNames, thread);
187 
188     // 12. Set DisplayNames.[[Style]] to style.
189     displayNames->SetStyle(StyOpt);
190 
191     // 13. Let type be ? GetOption(options, "type", "string", « "language", "region", "script", "currency" »,
192     // "undefined").
193     property = globalConst->GetHandledTypeString();
194     auto type = JSLocale::GetOptionOfString<TypednsOption>(thread, optionsObject, property,
195         JSDisplayNames::TYPED_NS_OPTION, JSDisplayNames::TYPED_NS_OPTION_NAME,
196         TypednsOption::UNDEFINED);
197     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDisplayNames, thread);
198 
199     // 14. If type is undefined, throw a TypeError exception.
200     if (type == TypednsOption::UNDEFINED) {
201         THROW_TYPE_ERROR_AND_RETURN(thread, "type is undefined", displayNames);
202     }
203 
204     // 15. Set displayNames.[[Type]] to type.
205     displayNames->SetType(type);
206 
207     // 16. Let fallback be ? GetOption(options, "fallback", "string", « "code", "none" », "code").
208     property = globalConst->GetHandledFallbackString();
209     auto fallback = JSLocale::GetOptionOfString<FallbackOption>(thread, optionsObject, property,
210         JSDisplayNames::FALLBACK_OPTION, JSDisplayNames::FALLBACK_OPTION_OPTION_NAME,
211         FallbackOption::CODE);
212     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDisplayNames, thread);
213 
214     // 17. Set displayNames.[[Fallback]] to fallback.
215     displayNames->SetFallback(fallback);
216 
217     // Let languageDisplay be ? GetOption(options, "languageDisplay", string, « "dialect", "standard" », "dialect").
218     property = globalConst->GetHandledLanguageDisplayString();
219     auto langDisplay = JSLocale::GetOptionOfString<LanguageDisplayOption>(
220         thread, optionsObject, property,
221         JSDisplayNames::LANGUAGE_DISPLAY_OPTION,
222         JSDisplayNames::LANGUAGE_DISPLAY_OPTION_NAME, LanguageDisplayOption::DIALECT);
223     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDisplayNames, thread);
224     displayNames->SetLanguageDisplay(langDisplay);
225 
226     // 18. Set displayNames.[[Locale]] to the value of r.[[Locale]].
227     JSHandle<EcmaString> localeStr = intl::LocaleHelper::ToLanguageTag(thread, icuLocale);
228     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSDisplayNames, thread);
229     displayNames->SetLocale(thread, localeStr.GetTaggedValue());
230     // 19. Let dataLocale be r.[[dataLocale]].
231     // 20. Let dataLocaleData be localeData.[[<dataLocale>]].
232     // 21. Let types be dataLocaleData.[[types]].
233     // 22. Assert: types is a Record (see 12.3.3).
234     // 23. Let typeFields be types.[[<type>]].
235     // 24. Assert: typeFields is a Record (see 12.3.3).
236     // 25. Let styleFields be typeFields.[[<style>]].
237     // 26. Assert: styleFields is a Record (see 12.3.3).
238     // 27. Set displayNames.[[Fields]] to styleFields.
239     // 28. Return displayNames.
240 
241     // Trans StyOption to ICU Style
242     UDisplayContext uStyle;
243     switch (StyOpt) {
244         case StyOption::LONG:
245             uStyle = UDISPCTX_LENGTH_FULL;
246             break;
247         case StyOption::SHORT:
248             uStyle = UDISPCTX_LENGTH_SHORT;
249             break;
250         case StyOption::NARROW:
251             uStyle = UDISPCTX_LENGTH_SHORT;
252             break;
253         default:
254             LOG_ECMA(FATAL) << "this branch is unreachable";
255             UNREACHABLE();
256     }
257     UDisplayContext displayContext[] = {uStyle};
258     icu::LocaleDisplayNames *icudisplaynames(icu::LocaleDisplayNames::createInstance(icuLocale, displayContext, 1));
259     if (icudisplaynames == nullptr) {
260         delete icudisplaynames;
261         THROW_RANGE_ERROR_AND_RETURN(thread, "create icu::LocaleDisplayNames failed", displayNames);
262     }
263     SetIcuLocaleDisplayNames(thread, displayNames, icudisplaynames, JSDisplayNames::FreeIcuLocaleDisplayNames);
264     return displayNames;
265 }
266 
267 // CanonicalCodeForDisplayNames ( type, code )
CanonicalCodeForDisplayNames(JSThread * thread,const JSHandle<JSDisplayNames> & displayNames,const TypednsOption & typeOpt,const JSHandle<EcmaString> & code)268 JSHandle<EcmaString> JSDisplayNames::CanonicalCodeForDisplayNames(JSThread *thread,
269                                                                   const JSHandle<JSDisplayNames> &displayNames,
270                                                                   const TypednsOption &typeOpt,
271                                                                   const JSHandle<EcmaString> &code)
272 {
273     if (typeOpt == TypednsOption::LANGUAGE) {
274         // a. If code does not match the unicode_language_id production, throw a RangeError exception.
275         UErrorCode status = U_ZERO_ERROR;
276         std::string codeSt = intl::LocaleHelper::ConvertToStdString(code);
277         icu::Locale loc = icu::Locale(icu::Locale::forLanguageTag(codeSt, status).getBaseName());
278         std::string checked = loc.toLanguageTag<std::string>(status);
279         if (checked.size() == 0) {
280             THROW_TYPE_ERROR_AND_RETURN(thread, "not match the language id", code);
281         }
282         if (U_FAILURE(status)) {
283             THROW_TYPE_ERROR_AND_RETURN(thread, "not match the unicode_language_id", code);
284         }
285         // b. If IsStructurallyValidLanguageTag(code) is false, throw a RangeError exception.
286         // c. Set code to CanonicalizeUnicodeLocaleId(code).
287         // d. Return code.
288         if (!intl::LocaleHelper::IsStructurallyValidLanguageTag(code)) {
289             THROW_TYPE_ERROR_AND_RETURN(thread, "not a structurally valid", code);
290         }
291         JSHandle<EcmaString> codeStr = intl::LocaleHelper::CanonicalizeUnicodeLocaleId(thread, code);
292         RETURN_HANDLE_IF_ABRUPT_COMPLETION(EcmaString, thread);
293         icu::LocaleDisplayNames *icuLocaldisplaynames = displayNames->GetIcuLocaleDisplayNames();
294         icu::UnicodeString result;
295         std::string codeString = intl::LocaleHelper::ConvertToStdString(codeStr);
296         icuLocaldisplaynames->languageDisplayName(codeString.c_str(), result);
297         JSHandle<EcmaString> codeResult = intl::LocaleHelper::UStringToString(thread, result);
298         return codeResult;
299     } else if (typeOpt == TypednsOption::REGION) {
300         // a. If code does not match the unicode_region_subtag production, throw a RangeError exception.
301         std::string regionCode = intl::LocaleHelper::ConvertToStdString(code);
302         if (!IsUnicodeRegionSubtag(regionCode)) {
303             THROW_RANGE_ERROR_AND_RETURN(thread, "invalid region", code);
304         }
305         // b. Let code be the result of mapping code to upper case as described in 6.1.
306         // c. Return code.
307         icu::LocaleDisplayNames *icuLocaldisplaynames = displayNames->GetIcuLocaleDisplayNames();
308         icu::UnicodeString result;
309         icuLocaldisplaynames->regionDisplayName(regionCode.c_str(), result);
310         JSHandle<EcmaString> codeResult = intl::LocaleHelper::UStringToString(thread, result);
311         return codeResult;
312     } else if (typeOpt == TypednsOption::SCRIPT) {
313         std::string scriptCode = intl::LocaleHelper::ConvertToStdString(code);
314         if (!IsUnicodeScriptSubtag(scriptCode)) {
315             THROW_RANGE_ERROR_AND_RETURN(thread, "invalid script", code);
316         }
317         icu::LocaleDisplayNames *icuLocaldisplaynames = displayNames->GetIcuLocaleDisplayNames();
318         icu::UnicodeString result;
319         icuLocaldisplaynames->scriptDisplayName(scriptCode.c_str(), result);
320         JSHandle<EcmaString> codeResult = intl::LocaleHelper::UStringToString(thread, result);
321         return codeResult;
322     } else if (typeOpt == TypednsOption::CALENDAR) {
323         std::string calendarCode = intl::LocaleHelper::ConvertToStdString(code);
324         if (!JSLocale::IsWellFormedCalendarCode(calendarCode)) {
325             THROW_RANGE_ERROR_AND_RETURN(thread, "invalid calendar", code);
326         }
327 
328         icu::LocaleDisplayNames *icuLocaldisplaynames = displayNames->GetIcuLocaleDisplayNames();
329         icu::UnicodeString result;
330         std::string calendarStrCode = std::strcmp(calendarCode.c_str(), "gregory") == 0
331                                         ? "gregorian"
332                                         : std::strcmp(calendarCode.c_str(), "ethioaa") == 0
333                                             ? "ethiopic-amete-alem"
334                                             : calendarCode;
335         icuLocaldisplaynames->keyValueDisplayName("calendar", calendarStrCode.c_str(), result);
336         JSHandle<EcmaString> codeResult = intl::LocaleHelper::UStringToString(thread, result);
337         return codeResult;
338     } else if (typeOpt == TypednsOption::DATETIMEFIELD) {
339         StyOption style = displayNames->GetStyle();
340         UDateTimePGDisplayWidth width;
341         switch (style) {
342             case StyOption::LONG:
343                 width = UDATPG_WIDE;
344                 break;
345             case StyOption::SHORT:
346                 width = UDATPG_ABBREVIATED;
347                 break;
348             case StyOption::NARROW:
349                 width = UDATPG_NARROW;
350                 break;
351             default:
352                 LOG_ECMA(FATAL) << "this branch is unreachable";
353                 UNREACHABLE();
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 
StringToUDateTimePatternField(const char * code)383 UDateTimePatternField 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 
StyOptionToEcmaString(JSThread * thread,StyOption style)424 JSHandle<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 
TypeOptionToEcmaString(JSThread * thread,TypednsOption type)445 JSHandle<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 
FallbackOptionToEcmaString(JSThread * thread,FallbackOption fallback)475 JSHandle<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 
LanguageDisplayOptionToEcmaString(JSThread * thread,LanguageDisplayOption langDisplay)493 JSHandle<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 
ResolvedOptions(JSThread * thread,const JSHandle<JSDisplayNames> & displayNames,const JSHandle<JSObject> & options)511 void 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