/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
deps/v8/src/objects/js-list-format.cc
310 строк
11 KB
Michaël Zasso
deps: update V8 to 14.1.146.11
04 окт 2025, 19:47
Не верифицирован
04 окт 2025, 19:47
7772a2d
Код
Авторство
О чём код?
// Copyright 2018 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_INTL_SUPPORT #error Internationalization is expected to be enabled. #endif // V8_INTL_SUPPORT #include "src/objects/js-list-format.h" #include <memory> #include <vector> #include "src/execution/isolate.h" #include "src/heap/factory.h" #include "src/objects/elements-inl.h" #include "src/objects/elements.h" #include "src/objects/intl-objects.h" #include "src/objects/js-array-inl.h" #include "src/objects/js-list-format-inl.h" #include "src/objects/managed-inl.h" #include "src/objects/objects-inl.h" #include "src/objects/option-utils.h" #include "unicode/fieldpos.h" #include "unicode/fpositer.h" #include "unicode/listformatter.h" #include "unicode/ulistformatter.h" namespace v8 { namespace internal { namespace { UListFormatterWidth GetIcuWidth(JSListFormat::Style style) { switch (style) { case JSListFormat::Style::LONG: return ULISTFMT_WIDTH_WIDE; case JSListFormat::Style::SHORT: return ULISTFMT_WIDTH_SHORT; case JSListFormat::Style::NARROW: return ULISTFMT_WIDTH_NARROW; } UNREACHABLE(); } UListFormatterType GetIcuType(JSListFormat::Type type) { switch (type) { case JSListFormat::Type::CONJUNCTION: return ULISTFMT_TYPE_AND; case JSListFormat::Type::DISJUNCTION: return ULISTFMT_TYPE_OR; case JSListFormat::Type::UNIT: return ULISTFMT_TYPE_UNITS; } UNREACHABLE(); } } // namespace MaybeDirectHandle<JSListFormat> JSListFormat::New( Isolate* isolate, DirectHandle<Map> map, DirectHandle<Object> locales, DirectHandle<Object> input_options, const char* service) { // 3. Let requestedLocales be ? CanonicalizeLocaleList(locales). Maybe<std::vector<std::string>> maybe_requested_locales = Intl::CanonicalizeLocaleList(isolate, locales); MAYBE_RETURN(maybe_requested_locales, DirectHandle<JSListFormat>()); std::vector<std::string> requested_locales = maybe_requested_locales.FromJust(); DirectHandle<JSReceiver> options; // 4. Let options be GetOptionsObject(_options_). ASSIGN_RETURN_ON_EXCEPTION(isolate, options, GetOptionsObject(isolate, input_options, service)); // Note: No need to create a record. It's not observable. // 6. Let opt be a new Record. // 7. Let matcher be ? GetOption(options, "localeMatcher", "string", « // "lookup", "best fit" », "best fit"). Maybe<Intl::MatcherOption> maybe_locale_matcher = Intl::GetLocaleMatcher(isolate, options, service); MAYBE_RETURN(maybe_locale_matcher, MaybeDirectHandle<JSListFormat>()); // 8. Set opt.[[localeMatcher]] to matcher. Intl::MatcherOption matcher = maybe_locale_matcher.FromJust(); // 10. Let r be ResolveLocale(%ListFormat%.[[AvailableLocales]], // requestedLocales, opt, undefined, localeData). Intl::ResolvedLocale r; if (!Intl::ResolveLocale(isolate, JSListFormat::GetAvailableLocales(), requested_locales, matcher, {}) .To(&r)) { THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError)); } DirectHandle<String> locale_str = isolate->factory()->NewStringFromAsciiChecked(r.locale.c_str()); // 12. Let t be GetOption(options, "type", "string", «"conjunction", // "disjunction", "unit"», "conjunction"). Maybe<Type> maybe_type = GetStringOption<Type>( isolate, options, isolate->factory()->type_string(), service, std::to_array<const std::string_view>( {"conjunction", "disjunction", "unit"}), std::array{Type::CONJUNCTION, Type::DISJUNCTION, Type::UNIT}, Type::CONJUNCTION); MAYBE_RETURN(maybe_type, MaybeDirectHandle<JSListFormat>()); Type type_enum = maybe_type.FromJust(); // 14. Let s be ? GetOption(options, "style", "string", // «"long", "short", "narrow"», "long"). Maybe<Style> maybe_style = GetStringOption<Style>( isolate, options, isolate->factory()->style_string(), service, std::to_array<const std::string_view>({"long", "short", "narrow"}), std::array{Style::LONG, Style::SHORT, Style::NARROW}, Style::LONG); MAYBE_RETURN(maybe_style, MaybeDirectHandle<JSListFormat>()); Style style_enum = maybe_style.FromJust(); icu::Locale icu_locale = r.icu_locale; UErrorCode status = U_ZERO_ERROR; std::shared_ptr<icu::ListFormatter> formatter{ icu::ListFormatter::createInstance(icu_locale, GetIcuType(type_enum), GetIcuWidth(style_enum), status)}; if (U_FAILURE(status) || formatter == nullptr) { THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError)); } DirectHandle<Managed<icu::ListFormatter>> managed_formatter = Managed<icu::ListFormatter>::From(isolate, 0, std::move(formatter)); // Now all properties are ready, so we can allocate the result object. DirectHandle<JSListFormat> list_format = Cast<JSListFormat>(isolate->factory()->NewFastOrSlowJSObjectFromMap(map)); DisallowGarbageCollection no_gc; list_format->set_flags(0); list_format->set_icu_formatter(*managed_formatter); // 11. Set listFormat.[[Locale]] to r.[[Locale]]. list_format->set_locale(*locale_str); // 13. Set listFormat.[[Type]] to t. list_format->set_type(type_enum); // 15. Set listFormat.[[Style]] to s. list_format->set_style(style_enum); return list_format; } // ecma402 #sec-intl.pluralrules.prototype.resolvedoptions DirectHandle<JSObject> JSListFormat::ResolvedOptions( Isolate* isolate, DirectHandle<JSListFormat> format) { Factory* factory = isolate->factory(); // 4. Let options be ! ObjectCreate(%ObjectPrototype%). DirectHandle<JSObject> result = factory->NewJSObject(isolate->object_function()); // 5. For each row of Table 1, except the header row, do // Table 1: Resolved Options of ListFormat Instances // Internal Slot Property // [[Locale]] "locale" // [[Type]] "type" // [[Style]] "style" DirectHandle<String> locale(format->locale(), isolate); JSObject::AddProperty(isolate, result, factory->locale_string(), locale, NONE); JSObject::AddProperty(isolate, result, factory->type_string(), format->TypeAsString(isolate), NONE); JSObject::AddProperty(isolate, result, factory->style_string(), format->StyleAsString(isolate), NONE); // 6. Return options. return result; } Handle<String> JSListFormat::StyleAsString(Isolate* isolate) const { switch (style()) { case Style::LONG: return isolate->factory()->long_string(); case Style::SHORT: return isolate->factory()->short_string(); case Style::NARROW: return isolate->factory()->narrow_string(); } UNREACHABLE(); } Handle<String> JSListFormat::TypeAsString(Isolate* isolate) const { switch (type()) { case Type::CONJUNCTION: return isolate->factory()->conjunction_string(); case Type::DISJUNCTION: return isolate->factory()->disjunction_string(); case Type::UNIT: return isolate->factory()->unit_string(); } UNREACHABLE(); } namespace { // Extract String from FixedArray into array of UnicodeString Maybe<std::vector<icu::UnicodeString>> ToUnicodeStringArray( Isolate* isolate, DirectHandle<FixedArray> array) { int length = array->length(); std::vector<icu::UnicodeString> result; for (int i = 0; i < length; i++) { Handle<Object> item(array->get(i), isolate); DCHECK(IsString(*item)); Handle<String> item_str = Cast<String>(item); if (!item_str->IsFlat()) item_str = String::Flatten(isolate, item_str); result.push_back(Intl::ToICUUnicodeString(isolate, item_str)); } return Just(result); } template <typename T> MaybeDirectHandle<T> FormatListCommon( Isolate* isolate, DirectHandle<JSListFormat> format, DirectHandle<FixedArray> list, const std::function<MaybeDirectHandle<T>( Isolate*, const icu::FormattedValue&)>& formatToResult) { DCHECK(!IsUndefined(*list)); Maybe<std::vector<icu::UnicodeString>> maybe_array = ToUnicodeStringArray(isolate, list); MAYBE_RETURN(maybe_array, DirectHandle<T>()); std::vector<icu::UnicodeString> array = maybe_array.FromJust(); icu::ListFormatter* formatter = format->icu_formatter()->raw(); DCHECK_NOT_NULL(formatter); UErrorCode status = U_ZERO_ERROR; icu::FormattedList formatted = formatter->formatStringsToValue( array.data(), static_cast<int32_t>(array.size()), status); if (U_FAILURE(status)) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError)); } return formatToResult(isolate, formatted); } DirectHandle<String> IcuFieldIdToType(Isolate* isolate, int32_t field_id) { switch (field_id) { case ULISTFMT_LITERAL_FIELD: return isolate->factory()->literal_string(); case ULISTFMT_ELEMENT_FIELD: return isolate->factory()->element_string(); default: UNREACHABLE(); } } // A helper function to convert the FormattedList to a // MaybeHandle<JSArray> for the implementation of formatToParts. MaybeDirectHandle<JSArray> FormattedListToJSArray( Isolate* isolate, const icu::FormattedValue& formatted) { DirectHandle<JSArray> array = isolate->factory()->NewJSArray(0); icu::ConstrainedFieldPosition cfpos; cfpos.constrainCategory(UFIELD_CATEGORY_LIST); int index = 0; UErrorCode status = U_ZERO_ERROR; icu::UnicodeString string = formatted.toString(status); DirectHandle<String> substring; while (formatted.nextPosition(cfpos, status) && U_SUCCESS(status)) { ASSIGN_RETURN_ON_EXCEPTION( isolate, substring, Intl::ToString(isolate, string, cfpos.getStart(), cfpos.getLimit())); Intl::AddElement(isolate, array, index++, IcuFieldIdToType(isolate, cfpos.getField()), substring); } if (U_FAILURE(status)) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError)); } JSObject::ValidateElements(isolate, *array); return array; } } // namespace // ecma402 #sec-formatlist MaybeDirectHandle<String> JSListFormat::FormatList( Isolate* isolate, DirectHandle<JSListFormat> format, DirectHandle<FixedArray> list) { return FormatListCommon<String>(isolate, format, list, Intl::FormattedToString); } // ecma42 #sec-formatlisttoparts MaybeDirectHandle<JSArray> JSListFormat::FormatListToParts( Isolate* isolate, DirectHandle<JSListFormat> format, DirectHandle<FixedArray> list) { return FormatListCommon<JSArray>(isolate, format, list, FormattedListToJSArray); } namespace { struct CheckListPattern { static const char* key() { return "listPattern"; } static const char* path() { return nullptr; } }; } // namespace const std::set<std::string>& JSListFormat::GetAvailableLocales() { static base::LazyInstance<Intl::AvailableLocales<CheckListPattern>>::type available_locales = LAZY_INSTANCE_INITIALIZER; return available_locales.Pointer()->Get(); } } // namespace internal } // namespace v8