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