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