1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 02:47:35 +00:00

LibLocale+LibJS: Make locale data APIs infallible

These APIs only perform small allocations, and are only used by LibJS.
Callers which could only have failed from these APIs are also made to
be infallible here.
This commit is contained in:
Timothy Flynn 2023-08-22 15:39:18 -04:00 committed by Andreas Kling
parent a98201f889
commit cd526813e6
20 changed files with 340 additions and 364 deletions

View file

@ -22,7 +22,7 @@ namespace JS::Intl {
// 6.2.2 IsStructurallyValidLanguageTag ( locale ), https://tc39.es/ecma402/#sec-isstructurallyvalidlanguagetag
ThrowCompletionOr<Optional<::Locale::LocaleID>> is_structurally_valid_language_tag(VM& vm, StringView locale)
{
auto contains_duplicate_variant = [&](auto& variants) -> ThrowCompletionOr<bool> {
auto contains_duplicate_variant = [&](auto& variants) {
if (variants.is_empty())
return false;
@ -39,7 +39,7 @@ ThrowCompletionOr<Optional<::Locale::LocaleID>> is_structurally_valid_language_t
// IsStructurallyValidLanguageTag returns true if all of the following conditions hold, false otherwise:
// locale can be generated from the EBNF grammar for unicode_locale_id in Unicode Technical Standard #35 LDML § 3.2 Unicode Locale Identifier;
auto locale_id = TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale));
auto locale_id = ::Locale::parse_unicode_locale_id(locale);
if (!locale_id.has_value())
return OptionalNone {};
@ -49,7 +49,7 @@ ThrowCompletionOr<Optional<::Locale::LocaleID>> is_structurally_valid_language_t
return OptionalNone {};
// the unicode_language_id within locale contains no duplicate unicode_variant_subtag subtags; and
if (TRY(contains_duplicate_variant(locale_id->language_id.variants)))
if (contains_duplicate_variant(locale_id->language_id.variants))
return OptionalNone {};
// if locale contains an extensions* component, that component
@ -72,7 +72,7 @@ ThrowCompletionOr<Optional<::Locale::LocaleID>> is_structurally_valid_language_t
// the tlang component contains no duplicate unicode_variant_subtag subtags.
if (auto* transformed = extension.get_pointer<::Locale::TransformedExtension>()) {
auto& language = transformed->language;
if (language.has_value() && TRY(contains_duplicate_variant(language->variants)))
if (language.has_value() && contains_duplicate_variant(language->variants))
return Optional<::Locale::LocaleID> {};
}
}
@ -115,7 +115,7 @@ ThrowCompletionOr<String> canonicalize_unicode_locale_id(VM& vm, ::Locale::Local
// 1. Let localeId be the string locale after performing the algorithm to transform it to canonical syntax per Unicode Technical Standard #35 LDML § 3.2.1 Canonical Unicode Locale Identifiers.
// 2. Let localeId be the string localeId after performing the algorithm to transform it to canonical form.
auto locale_id = TRY_OR_THROW_OOM(vm, ::Locale::canonicalize_unicode_locale_id(locale));
auto locale_id = ::Locale::canonicalize_unicode_locale_id(locale);
VERIFY(locale_id.has_value());
// 4. Return localeId.
@ -302,12 +302,12 @@ static ThrowCompletionOr<MatcherResult> lookup_matcher(VM& vm, Vector<String> co
// 2. For each element locale of requestedLocales, do
for (auto const& locale : requested_locales) {
auto locale_id = TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale));
auto locale_id = ::Locale::parse_unicode_locale_id(locale);
VERIFY(locale_id.has_value());
// a. Let noExtensionsLocale be the String value that is locale with any Unicode locale extension sequences removed.
auto extensions = locale_id->remove_extension_type<::Locale::LocaleExtension>();
auto no_extensions_locale = TRY_OR_THROW_OOM(vm, locale_id->to_string());
auto no_extensions_locale = locale_id->to_string();
// b. Let availableLocale be ! BestAvailableLocale(availableLocales, noExtensionsLocale).
auto available_locale = best_available_locale(no_extensions_locale);
@ -433,7 +433,7 @@ ThrowCompletionOr<LocaleResult> resolve_locale(VM& vm, Vector<String> const& req
// NOTE: ECMA-402 assumes keyLocaleData is sorted by locale preference. Our list is sorted
// alphabetically, so we get the locale's preferred value from LibUnicode.
Optional<String> value;
if (auto preference = TRY_OR_THROW_OOM(vm, ::Locale::get_preferred_keyword_value_for_locale(found_locale, key)); preference.has_value())
if (auto preference = ::Locale::get_preferred_keyword_value_for_locale(found_locale, key); preference.has_value())
value = TRY_OR_THROW_OOM(vm, String::from_utf8(*preference));
// g. Let supportedExtensionAddition be "".
@ -481,7 +481,7 @@ ThrowCompletionOr<LocaleResult> resolve_locale(VM& vm, Vector<String> const& req
if (options_value.has_value()) {
// 1. Let optionsValue be the string optionsValue after performing the algorithm steps to transform Unicode extension values to canonical syntax per Unicode Technical Standard #35 LDML § 3.2.1 Canonical Unicode Locale Identifiers, treating key as ukey and optionsValue as uvalue productions.
// 2. Let optionsValue be the string optionsValue after performing the algorithm steps to replace Unicode extension values with their canonical form per Unicode Technical Standard #35 LDML § 3.2.1 Canonical Unicode Locale Identifiers, treating key as ukey and optionsValue as uvalue productions.
TRY_OR_THROW_OOM(vm, ::Locale::canonicalize_unicode_extension_values(key, *options_value, true));
::Locale::canonicalize_unicode_extension_values(key, *options_value, true);
// 3. If optionsValue is the empty String, then
if (options_value->is_empty()) {
@ -509,7 +509,7 @@ ThrowCompletionOr<LocaleResult> resolve_locale(VM& vm, Vector<String> const& req
// 10. If supportedExtension is not "-u", then
if (!supported_extension.keywords.is_empty()) {
auto locale_id = TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(found_locale));
auto locale_id = ::Locale::parse_unicode_locale_id(found_locale);
VERIFY(locale_id.has_value());
// a. Set foundLocale to InsertUnicodeExtensionAndCanonicalize(foundLocale, supportedExtension).
@ -531,12 +531,12 @@ static ThrowCompletionOr<Vector<String>> lookup_supported_locales(VM& vm, Vector
// 2. For each element locale of requestedLocales, do
for (auto const& locale : requested_locales) {
auto locale_id = TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale));
auto locale_id = ::Locale::parse_unicode_locale_id(locale);
VERIFY(locale_id.has_value());
// a. Let noExtensionsLocale be the String value that is locale with any Unicode locale extension sequences removed.
locale_id->remove_extension_type<::Locale::LocaleExtension>();
auto no_extensions_locale = TRY_OR_THROW_OOM(vm, locale_id->to_string());
auto no_extensions_locale = locale_id->to_string();
// b. Let availableLocale be ! BestAvailableLocale(availableLocales, noExtensionsLocale).
auto available_locale = best_available_locale(no_extensions_locale);

View file

@ -719,7 +719,7 @@ ThrowCompletionOr<Vector<PatternPartition>> format_date_time_pattern(VM& vm, Dat
// Non-standard, TR-35 requires the decimal separator before injected {fractionalSecondDigits} partitions
// to adhere to the selected locale. This depends on other generated data, so it is deferred to here.
else if (part == "decimal"sv) {
auto decimal_symbol = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(data_locale, date_time_format.numbering_system(), ::Locale::NumericSymbol::Decimal)).value_or("."sv);
auto decimal_symbol = ::Locale::get_number_system_symbol(data_locale, date_time_format.numbering_system(), ::Locale::NumericSymbol::Decimal).value_or("."sv);
TRY_OR_THROW_OOM(vm, result.try_append({ "literal"sv, TRY_OR_THROW_OOM(vm, String::from_utf8(decimal_symbol)) }));
}

View file

@ -106,7 +106,7 @@ ThrowCompletionOr<Value> canonical_code_for_display_names(VM& vm, DisplayNames::
// 1. If type is "language", then
if (type == DisplayNames::Type::Language) {
// a. If code does not match the unicode_language_id production, throw a RangeError exception.
if (!TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_language_id(code)).has_value())
if (!::Locale::parse_unicode_language_id(code).has_value())
return vm.throw_completion<RangeError>(ErrorType::OptionIsNotValidValue, code, "language"sv);
// b. If IsStructurallyValidLanguageTag(code) is false, throw a RangeError exception.

View file

@ -63,7 +63,7 @@ JS_DEFINE_NATIVE_FUNCTION(DisplayNamesPrototype::of)
}
if (auto locale = MUST_OR_THROW_OOM(is_structurally_valid_language_tag(vm, code_string)); locale.has_value())
formatted_result = TRY_OR_THROW_OOM(vm, ::Locale::format_locale_for_display(display_names->locale(), locale.release_value()));
formatted_result = ::Locale::format_locale_for_display(display_names->locale(), locale.release_value());
break;
case DisplayNames::Type::Region:
result = ::Locale::get_locale_territory_mapping(display_names->locale(), code_string);

View file

@ -482,7 +482,7 @@ ThrowCompletionOr<Vector<PatternPartition>> partition_duration_format_pattern(VM
// c. If nextValue is not 0 or nextDisplay is not "auto", then
if (next_value != 0.0 || next_display != DurationFormat::Display::Auto) {
// i. Let separator be dataLocaleData.[[formats]].[[digital]].[[separator]].
auto separator = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(data_locale, duration_format.numbering_system(), ::Locale::NumericSymbol::TimeSeparator)).value_or(":"sv);
auto separator = ::Locale::get_number_system_symbol(data_locale, duration_format.numbering_system(), ::Locale::NumericSymbol::TimeSeparator).value_or(":"sv);
// ii. Append the new Record { [[Type]]: "literal", [[Value]]: separator} to the end of result.
TRY_OR_THROW_OOM(vm, result.try_append({ "literal"sv, TRY_OR_THROW_OOM(vm, String::from_utf8(separator)) }));

View file

@ -14,10 +14,10 @@
namespace JS::Intl {
ThrowCompletionOr<NonnullGCPtr<Locale>> Locale::create(Realm& realm, ::Locale::LocaleID locale_id)
NonnullGCPtr<Locale> Locale::create(Realm& realm, ::Locale::LocaleID locale_id)
{
auto locale = realm.heap().allocate<Locale>(realm, realm.intrinsics().intl_locale_prototype());
locale->set_locale(TRY_OR_THROW_OOM(realm.vm(), locale_id.to_string()));
locale->set_locale(locale_id.to_string());
for (auto& extension : locale_id.extensions) {
if (!extension.has<::Locale::LocaleExtension>())
@ -51,7 +51,7 @@ Locale::Locale(Object& prototype)
}
// 1.1.1 CreateArrayFromListOrRestricted ( list , restricted )
static ThrowCompletionOr<NonnullGCPtr<Array>> create_array_from_list_or_restricted(VM& vm, Vector<StringView> list, Optional<String> restricted)
static NonnullGCPtr<Array> create_array_from_list_or_restricted(VM& vm, Vector<StringView> list, Optional<String> restricted)
{
auto& realm = *vm.current_realm();
@ -63,12 +63,12 @@ static ThrowCompletionOr<NonnullGCPtr<Array>> create_array_from_list_or_restrict
// 2. Return ! CreateArrayFromList( list ).
return Array::create_from<StringView>(realm, list, [&vm](auto value) {
return PrimitiveString::create(vm, String::from_utf8(value).release_value());
return PrimitiveString::create(vm, MUST(String::from_utf8(value)));
});
}
// 1.1.2 CalendarsOfLocale ( loc ), https://tc39.es/proposal-intl-locale-info/#sec-calendars-of-locale
ThrowCompletionOr<NonnullGCPtr<Array>> calendars_of_locale(VM& vm, Locale const& locale_object)
NonnullGCPtr<Array> calendars_of_locale(VM& vm, Locale const& locale_object)
{
// 1. Let restricted be loc.[[Calendar]].
Optional<String> restricted = locale_object.has_calendar() ? locale_object.calendar() : Optional<String> {};
@ -77,17 +77,17 @@ ThrowCompletionOr<NonnullGCPtr<Array>> calendars_of_locale(VM& vm, Locale const&
auto const& locale = locale_object.locale();
// 3. Assert: locale matches the unicode_locale_id production.
VERIFY(TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale)).has_value());
VERIFY(::Locale::parse_unicode_locale_id(locale).has_value());
// 4. Let list be a List of 1 or more unique canonical calendar identifiers, which must be lower case String values conforming to the type sequence from UTS 35 Unicode Locale Identifier, section 3.2, sorted in descending preference of those in common use for date and time formatting in locale.
auto list = TRY_OR_THROW_OOM(vm, ::Locale::get_keywords_for_locale(locale, "ca"sv));
auto list = ::Locale::get_keywords_for_locale(locale, "ca"sv);
// 5. Return ! CreateArrayFromListOrRestricted( list, restricted ).
return create_array_from_list_or_restricted(vm, move(list), move(restricted));
}
// 1.1.3 CollationsOfLocale ( loc ), https://tc39.es/proposal-intl-locale-info/#sec-collations-of-locale
ThrowCompletionOr<NonnullGCPtr<Array>> collations_of_locale(VM& vm, Locale const& locale_object)
NonnullGCPtr<Array> collations_of_locale(VM& vm, Locale const& locale_object)
{
// 1. Let restricted be loc.[[Collation]].
Optional<String> restricted = locale_object.has_collation() ? locale_object.collation() : Optional<String> {};
@ -96,17 +96,17 @@ ThrowCompletionOr<NonnullGCPtr<Array>> collations_of_locale(VM& vm, Locale const
auto const& locale = locale_object.locale();
// 3. Assert: locale matches the unicode_locale_id production.
VERIFY(TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale)).has_value());
VERIFY(::Locale::parse_unicode_locale_id(locale).has_value());
// 4. Let list be a List of 1 or more unique canonical collation identifiers, which must be lower case String values conforming to the type sequence from UTS 35 Unicode Locale Identifier, section 3.2, ordered as if an Array of the same values had been sorted, using %Array.prototype.sort% using undefined as comparefn, of those in common use for string comparison in locale. The values "standard" and "search" must be excluded from list.
auto list = TRY_OR_THROW_OOM(vm, ::Locale::get_keywords_for_locale(locale, "co"sv));
auto list = ::Locale::get_keywords_for_locale(locale, "co"sv);
// 5. Return ! CreateArrayFromListOrRestricted( list, restricted ).
return create_array_from_list_or_restricted(vm, move(list), move(restricted));
}
// 1.1.4 HourCyclesOfLocale ( loc ), https://tc39.es/proposal-intl-locale-info/#sec-hour-cycles-of-locale
ThrowCompletionOr<NonnullGCPtr<Array>> hour_cycles_of_locale(VM& vm, Locale const& locale_object)
NonnullGCPtr<Array> hour_cycles_of_locale(VM& vm, Locale const& locale_object)
{
// 1. Let restricted be loc.[[HourCycle]].
Optional<String> restricted = locale_object.has_hour_cycle() ? locale_object.hour_cycle() : Optional<String> {};
@ -115,17 +115,17 @@ ThrowCompletionOr<NonnullGCPtr<Array>> hour_cycles_of_locale(VM& vm, Locale cons
auto const& locale = locale_object.locale();
// 3. Assert: locale matches the unicode_locale_id production.
VERIFY(TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale)).has_value());
VERIFY(::Locale::parse_unicode_locale_id(locale).has_value());
// 4. Let list be a List of 1 or more unique hour cycle identifiers, which must be lower case String values indicating either the 12-hour format ("h11", "h12") or the 24-hour format ("h23", "h24"), sorted in descending preference of those in common use for date and time formatting in locale.
auto list = TRY_OR_THROW_OOM(vm, ::Locale::get_keywords_for_locale(locale, "hc"sv));
auto list = ::Locale::get_keywords_for_locale(locale, "hc"sv);
// 5. Return ! CreateArrayFromListOrRestricted( list, restricted ).
return create_array_from_list_or_restricted(vm, move(list), move(restricted));
}
// 1.1.5 NumberingSystemsOfLocale ( loc ), https://tc39.es/proposal-intl-locale-info/#sec-numbering-systems-of-locale
ThrowCompletionOr<NonnullGCPtr<Array>> numbering_systems_of_locale(VM& vm, Locale const& locale_object)
NonnullGCPtr<Array> numbering_systems_of_locale(VM& vm, Locale const& locale_object)
{
// 1. Let restricted be loc.[[NumberingSystem]].
Optional<String> restricted = locale_object.has_numbering_system() ? locale_object.numbering_system() : Optional<String> {};
@ -134,10 +134,10 @@ ThrowCompletionOr<NonnullGCPtr<Array>> numbering_systems_of_locale(VM& vm, Local
auto const& locale = locale_object.locale();
// 3. Assert: locale matches the unicode_locale_id production.
VERIFY(TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale)).has_value());
VERIFY(::Locale::parse_unicode_locale_id(locale).has_value());
// 4. Let list be a List of 1 or more unique canonical numbering system identifiers, which must be lower case String values conforming to the type sequence from UTS 35 Unicode Locale Identifier, section 3.2, sorted in descending preference of those in common use for formatting numeric values in locale.
auto list = TRY_OR_THROW_OOM(vm, ::Locale::get_keywords_for_locale(locale, "nu"sv));
auto list = ::Locale::get_keywords_for_locale(locale, "nu"sv);
// 5. Return ! CreateArrayFromListOrRestricted( list, restricted ).
return create_array_from_list_or_restricted(vm, move(list), move(restricted));
@ -145,7 +145,7 @@ ThrowCompletionOr<NonnullGCPtr<Array>> numbering_systems_of_locale(VM& vm, Local
// 1.1.6 TimeZonesOfLocale ( loc ), https://tc39.es/proposal-intl-locale-info/#sec-time-zones-of-locale
// NOTE: Our implementation takes a region rather than a Locale object to avoid needlessly parsing the locale twice.
ThrowCompletionOr<NonnullGCPtr<Array>> time_zones_of_locale(VM& vm, StringView region)
NonnullGCPtr<Array> time_zones_of_locale(VM& vm, StringView region)
{
auto& realm = *vm.current_realm();
@ -164,13 +164,13 @@ ThrowCompletionOr<NonnullGCPtr<Array>> time_zones_of_locale(VM& vm, StringView r
}
// 1.1.7 CharacterDirectionOfLocale ( loc ), https://tc39.es/proposal-intl-locale-info/#sec-character-direction-of-locale
ThrowCompletionOr<StringView> character_direction_of_locale(VM& vm, Locale const& locale_object)
StringView character_direction_of_locale(Locale const& locale_object)
{
// 1. Let locale be loc.[[Locale]].
auto const& locale = locale_object.locale();
// 2. Assert: locale matches the unicode_locale_id production.
VERIFY(TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale)).has_value());
VERIFY(::Locale::parse_unicode_locale_id(locale).has_value());
// 3. If the default general ordering of characters (characterOrder) within a line in locale is right-to-left, return "rtl".
// NOTE: LibUnicode handles both LTR and RTL character orders in this call, not just RTL. We then fallback to LTR
@ -231,7 +231,7 @@ ThrowCompletionOr<WeekInfo> week_info_of_locale(VM& vm, Locale const& locale_obj
auto const& locale = locale_object.locale();
// 2. Assert: locale matches the unicode_locale_id production.
VERIFY(TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale)).has_value());
VERIFY(::Locale::parse_unicode_locale_id(locale).has_value());
// 3. Return a record whose fields are defined by Table 1, with values based on locale.
WeekInfo week_info {};

View file

@ -22,7 +22,7 @@ class Locale final : public Object {
JS_OBJECT(Locale, Object);
public:
static ThrowCompletionOr<NonnullGCPtr<Locale>> create(Realm&, ::Locale::LocaleID);
static NonnullGCPtr<Locale> create(Realm&, ::Locale::LocaleID);
static constexpr auto relevant_extension_keys()
{
@ -82,12 +82,12 @@ struct WeekInfo {
Vector<u8> weekend; // [[Weekend]]
};
ThrowCompletionOr<NonnullGCPtr<Array>> calendars_of_locale(VM&, Locale const&);
ThrowCompletionOr<NonnullGCPtr<Array>> collations_of_locale(VM&, Locale const& locale);
ThrowCompletionOr<NonnullGCPtr<Array>> hour_cycles_of_locale(VM&, Locale const& locale);
ThrowCompletionOr<NonnullGCPtr<Array>> numbering_systems_of_locale(VM&, Locale const&);
ThrowCompletionOr<NonnullGCPtr<Array>> time_zones_of_locale(VM&, StringView region);
ThrowCompletionOr<StringView> character_direction_of_locale(VM&, Locale const&);
NonnullGCPtr<Array> calendars_of_locale(VM&, Locale const&);
NonnullGCPtr<Array> collations_of_locale(VM&, Locale const& locale);
NonnullGCPtr<Array> hour_cycles_of_locale(VM&, Locale const& locale);
NonnullGCPtr<Array> numbering_systems_of_locale(VM&, Locale const&);
NonnullGCPtr<Array> time_zones_of_locale(VM&, StringView region);
StringView character_direction_of_locale(Locale const&);
ThrowCompletionOr<WeekInfo> week_info_of_locale(VM&, Locale const&);
}

View file

@ -69,7 +69,7 @@ static ThrowCompletionOr<String> apply_options_to_tag(VM& vm, StringView tag, Ob
auto canonicalized_tag = MUST_OR_THROW_OOM(canonicalize_unicode_locale_id(vm, *locale_id));
// 11. Assert: tag matches the unicode_locale_id production.
locale_id = TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(canonicalized_tag));
locale_id = ::Locale::parse_unicode_locale_id(canonicalized_tag);
VERIFY(locale_id.has_value());
// 12. Let languageId be the substring of tag corresponding to the unicode_language_id production.
@ -109,7 +109,7 @@ static ThrowCompletionOr<LocaleAndKeys> apply_unicode_extension_to_tag(VM& vm, S
{
// 1. Assert: Type(tag) is String.
// 2. Assert: tag matches the unicode_locale_id production.
auto locale_id = TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(tag));
auto locale_id = ::Locale::parse_unicode_locale_id(tag);
VERIFY(locale_id.has_value());
Vector<String> attributes;
@ -198,7 +198,7 @@ static ThrowCompletionOr<LocaleAndKeys> apply_unicode_extension_to_tag(VM& vm, S
// 7. Let locale be the String value that is tag with any Unicode locale extension sequences removed.
locale_id->remove_extension_type<::Locale::LocaleExtension>();
auto locale = TRY_OR_THROW_OOM(vm, locale_id->to_string());
auto locale = locale_id->to_string();
// 8. Let newExtension be a Unicode BCP 47 U Extension based on attributes and keywords.
::Locale::LocaleExtension new_extension { move(attributes), move(keywords) };

View file

@ -61,15 +61,15 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::maximize)
// 2. Perform ? RequireInternalSlot(loc, [[InitializedLocale]]).
auto locale_object = TRY(typed_this_object(vm));
auto locale = TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale_object->locale()));
auto locale = ::Locale::parse_unicode_locale_id(locale_object->locale());
VERIFY(locale.has_value());
// 3. Let maximal be the result of the Add Likely Subtags algorithm applied to loc.[[Locale]]. If an error is signaled, set maximal to loc.[[Locale]].
if (auto maximal = TRY_OR_THROW_OOM(vm, ::Locale::add_likely_subtags(locale->language_id)); maximal.has_value())
if (auto maximal = ::Locale::add_likely_subtags(locale->language_id); maximal.has_value())
locale->language_id = maximal.release_value();
// 4. Return ! Construct(%Locale%, maximal).
return MUST_OR_THROW_OOM(Locale::create(realm, locale.release_value()));
return Locale::create(realm, locale.release_value());
}
// 14.3.4 Intl.Locale.prototype.minimize ( ), https://tc39.es/ecma402/#sec-Intl.Locale.prototype.minimize
@ -81,15 +81,15 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::minimize)
// 2. Perform ? RequireInternalSlot(loc, [[InitializedLocale]]).
auto locale_object = TRY(typed_this_object(vm));
auto locale = TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale_object->locale()));
auto locale = ::Locale::parse_unicode_locale_id(locale_object->locale());
VERIFY(locale.has_value());
// 3. Let minimal be the result of the Remove Likely Subtags algorithm applied to loc.[[Locale]]. If an error is signaled, set minimal to loc.[[Locale]].
if (auto minimal = TRY_OR_THROW_OOM(vm, ::Locale::remove_likely_subtags(locale->language_id)); minimal.has_value())
if (auto minimal = ::Locale::remove_likely_subtags(locale->language_id); minimal.has_value())
locale->language_id = minimal.release_value();
// 4. Return ! Construct(%Locale%, minimal).
return MUST_OR_THROW_OOM(Locale::create(realm, locale.release_value()));
return Locale::create(realm, locale.release_value());
}
// 14.3.5 Intl.Locale.prototype.toString ( ), https://tc39.es/ecma402/#sec-Intl.Locale.prototype.toString
@ -111,11 +111,11 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::base_name)
auto locale_object = TRY(typed_this_object(vm));
// 3. Let locale be loc.[[Locale]].
auto locale = TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale_object->locale()));
auto locale = ::Locale::parse_unicode_locale_id(locale_object->locale());
VERIFY(locale.has_value());
// 4. Return the substring of locale corresponding to the unicode_language_id production.
return PrimitiveString::create(vm, TRY_OR_THROW_OOM(vm, locale->language_id.to_string()));
return PrimitiveString::create(vm, locale->language_id.to_string());
}
#define JS_ENUMERATE_LOCALE_KEYWORD_PROPERTIES \
@ -160,7 +160,7 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::language)
auto locale_object = TRY(typed_this_object(vm));
// 3. Let locale be loc.[[Locale]].
auto locale = TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale_object->locale()));
auto locale = ::Locale::parse_unicode_locale_id(locale_object->locale());
// 4. Assert: locale matches the unicode_locale_id production.
VERIFY(locale.has_value());
@ -177,7 +177,7 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::script)
auto locale_object = TRY(typed_this_object(vm));
// 3. Let locale be loc.[[Locale]].
auto locale = TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale_object->locale()));
auto locale = ::Locale::parse_unicode_locale_id(locale_object->locale());
// 4. Assert: locale matches the unicode_locale_id production.
VERIFY(locale.has_value());
@ -198,7 +198,7 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::region)
auto locale_object = TRY(typed_this_object(vm));
// 3. Let locale be loc.[[Locale]].
auto locale = TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale_object->locale()));
auto locale = ::Locale::parse_unicode_locale_id(locale_object->locale());
// 4. Assert: locale matches the unicode_locale_id production.
VERIFY(locale.has_value());
@ -221,11 +221,11 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::region)
// 1.4.17 get Intl.Locale.prototype.collations, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.collations
// 1.4.18 get Intl.Locale.prototype.hourCycles, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.hourCycles
// 1.4.19 get Intl.Locale.prototype.numberingSystems, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.numberingSystems
#define __JS_ENUMERATE(keyword) \
JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::keyword) \
{ \
auto locale_object = TRY(typed_this_object(vm)); \
return MUST_OR_THROW_OOM(keyword##_of_locale(vm, locale_object)); \
#define __JS_ENUMERATE(keyword) \
JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::keyword) \
{ \
auto locale_object = TRY(typed_this_object(vm)); \
return keyword##_of_locale(vm, locale_object); \
}
JS_ENUMERATE_LOCALE_INFO_PROPERTIES
#undef __JS_ENUMERATE
@ -238,14 +238,14 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::time_zones)
auto locale_object = TRY(typed_this_object(vm));
// 3. Let locale be loc.[[Locale]].
auto locale = TRY_OR_THROW_OOM(vm, ::Locale::parse_unicode_locale_id(locale_object->locale()));
auto locale = ::Locale::parse_unicode_locale_id(locale_object->locale());
// 4. If the unicode_language_id production of locale does not contain the ["-" unicode_region_subtag] sequence, return undefined.
if (!locale.has_value() || !locale->language_id.region.has_value())
return js_undefined();
// 5. Return ! TimeZonesOfLocale(loc).
return MUST_OR_THROW_OOM(time_zones_of_locale(vm, locale->language_id.region.value()));
return time_zones_of_locale(vm, locale->language_id.region.value());
}
// 1.4.21 get Intl.Locale.prototype.textInfo, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.textInfo
@ -261,7 +261,7 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::text_info)
auto info = Object::create(realm, realm.intrinsics().object_prototype());
// 4. Let dir be ! CharacterDirectionOfLocale(loc).
auto direction = MUST_OR_THROW_OOM(character_direction_of_locale(vm, locale_object));
auto direction = character_direction_of_locale(locale_object);
// 5. Perform ! CreateDataPropertyOrThrow(info, "direction", dir).
MUST(info->create_data_property_or_throw(vm.names.direction, PrimitiveString::create(vm, direction)));

View file

@ -537,13 +537,13 @@ ThrowCompletionOr<Vector<PatternPartition>> partition_number_pattern(VM& vm, Num
// 2. If x is not-a-number, then
if (number.is_nan()) {
// a. Let n be an implementation- and locale-dependent (ILD) String value indicating the NaN value.
auto symbol = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::NaN)).value_or("NaN"sv);
auto symbol = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::NaN).value_or("NaN"sv);
formatted_string = TRY_OR_THROW_OOM(vm, String::from_utf8(symbol));
}
// 3. Else if x is positive-infinity, then
else if (number.is_positive_infinity()) {
// a. Let n be an ILD String value indicating positive infinity.
auto symbol = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::Infinity)).value_or("infinity"sv);
auto symbol = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::Infinity).value_or("infinity"sv);
formatted_string = TRY_OR_THROW_OOM(vm, String::from_utf8(symbol));
}
// 4. Else if x is negative-infinity, then
@ -551,7 +551,7 @@ ThrowCompletionOr<Vector<PatternPartition>> partition_number_pattern(VM& vm, Num
// a. Let n be an ILD String value indicating negative infinity.
// NOTE: The CLDR does not contain unique strings for negative infinity. The negative sign will
// be inserted by the pattern returned from GetNumberFormatPattern.
auto symbol = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::Infinity)).value_or("infinity"sv);
auto symbol = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::Infinity).value_or("infinity"sv);
formatted_string = TRY_OR_THROW_OOM(vm, String::from_utf8(symbol));
}
// 5. Else,
@ -617,7 +617,7 @@ ThrowCompletionOr<Vector<PatternPartition>> partition_number_pattern(VM& vm, Num
// d. Else if p is equal to "plusSign", then
else if (part == "plusSign"sv) {
// i. Let plusSignSymbol be the ILND String representing the plus sign.
auto plus_sign_symbol = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::PlusSign)).value_or("+"sv);
auto plus_sign_symbol = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::PlusSign).value_or("+"sv);
// ii. Append a new Record { [[Type]]: "plusSign", [[Value]]: plusSignSymbol } as the last element of result.
TRY_OR_THROW_OOM(vm, result.try_append({ "plusSign"sv, TRY_OR_THROW_OOM(vm, String::from_utf8(plus_sign_symbol)) }));
}
@ -625,7 +625,7 @@ ThrowCompletionOr<Vector<PatternPartition>> partition_number_pattern(VM& vm, Num
// e. Else if p is equal to "minusSign", then
else if (part == "minusSign"sv) {
// i. Let minusSignSymbol be the ILND String representing the minus sign.
auto minus_sign_symbol = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::MinusSign)).value_or("-"sv);
auto minus_sign_symbol = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::MinusSign).value_or("-"sv);
// ii. Append a new Record { [[Type]]: "minusSign", [[Value]]: minusSignSymbol } as the last element of result.
TRY_OR_THROW_OOM(vm, result.try_append({ "minusSign"sv, TRY_OR_THROW_OOM(vm, String::from_utf8(minus_sign_symbol)) }));
}
@ -633,7 +633,7 @@ ThrowCompletionOr<Vector<PatternPartition>> partition_number_pattern(VM& vm, Num
// f. Else if p is equal to "percentSign" and numberFormat.[[Style]] is "percent", then
else if ((part == "percentSign"sv) && (number_format.style() == NumberFormat::Style::Percent)) {
// i. Let percentSignSymbol be the ILND String representing the percent sign.
auto percent_sign_symbol = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::PercentSign)).value_or("%"sv);
auto percent_sign_symbol = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::PercentSign).value_or("%"sv);
// ii. Append a new Record { [[Type]]: "percentSign", [[Value]]: percentSignSymbol } as the last element of result.
TRY_OR_THROW_OOM(vm, result.try_append({ "percentSign"sv, TRY_OR_THROW_OOM(vm, String::from_utf8(percent_sign_symbol)) }));
}
@ -744,7 +744,7 @@ ThrowCompletionOr<Vector<PatternPartition>> partition_notation_sub_pattern(VM& v
// 1. Let result be a new empty List.
Vector<PatternPartition> result;
auto grouping_sizes = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_groupings(number_format.data_locale(), number_format.numbering_system()));
auto grouping_sizes = ::Locale::get_number_system_groupings(number_format.data_locale(), number_format.numbering_system());
if (!grouping_sizes.has_value())
return Vector<PatternPartition> {};
@ -827,7 +827,7 @@ ThrowCompletionOr<Vector<PatternPartition>> partition_notation_sub_pattern(VM& v
// 7. Else,
else {
// a. Let groupSepSymbol be the implementation-, locale-, and numbering system-dependent (ILND) String representing the grouping separator.
auto group_sep_symbol = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::Group)).value_or(","sv);
auto group_sep_symbol = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::Group).value_or(","sv);
// b. Let groups be a List whose elements are, in left to right order, the substrings defined by ILND set of locations within the integer, which may depend on the value of numberFormat.[[UseGrouping]].
auto groups = MUST_OR_THROW_OOM(separate_integer_into_groups(vm, *grouping_sizes, move(integer), number_format.use_grouping()));
@ -854,7 +854,7 @@ ThrowCompletionOr<Vector<PatternPartition>> partition_notation_sub_pattern(VM& v
// 8. If fraction is not undefined, then
if (fraction.has_value()) {
// a. Let decimalSepSymbol be the ILND String representing the decimal separator.
auto decimal_sep_symbol = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::Decimal)).value_or("."sv);
auto decimal_sep_symbol = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::Decimal).value_or("."sv);
// b. Append a new Record { [[Type]]: "decimal", [[Value]]: decimalSepSymbol } as the last element of result.
TRY_OR_THROW_OOM(vm, result.try_append({ "decimal"sv, TRY_OR_THROW_OOM(vm, String::from_utf8(decimal_sep_symbol)) }));
// c. Append a new Record { [[Type]]: "fraction", [[Value]]: fraction } as the last element of result.
@ -878,7 +878,7 @@ ThrowCompletionOr<Vector<PatternPartition>> partition_notation_sub_pattern(VM& v
// vi. Else if p is equal to "scientificSeparator", then
else if (part == "scientificSeparator"sv) {
// 1. Let scientificSeparator be the ILND String representing the exponent separator.
auto scientific_separator = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::Exponential)).value_or("E"sv);
auto scientific_separator = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::Exponential).value_or("E"sv);
// 2. Append a new Record { [[Type]]: "exponentSeparator", [[Value]]: scientificSeparator } as the last element of result.
TRY_OR_THROW_OOM(vm, result.try_append({ "exponentSeparator"sv, TRY_OR_THROW_OOM(vm, String::from_utf8(scientific_separator)) }));
}
@ -887,7 +887,7 @@ ThrowCompletionOr<Vector<PatternPartition>> partition_notation_sub_pattern(VM& v
// 1. If exponent < 0, then
if (exponent < 0) {
// a. Let minusSignSymbol be the ILND String representing the minus sign.
auto minus_sign_symbol = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::MinusSign)).value_or("-"sv);
auto minus_sign_symbol = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::MinusSign).value_or("-"sv);
// b. Append a new Record { [[Type]]: "exponentMinusSign", [[Value]]: minusSignSymbol } as the last element of result.
TRY_OR_THROW_OOM(vm, result.try_append({ "exponentMinusSign"sv, TRY_OR_THROW_OOM(vm, String::from_utf8(minus_sign_symbol)) }));
@ -1854,7 +1854,7 @@ ThrowCompletionOr<Vector<PatternPartitionWithSource>> partition_number_range_pat
}
// 7. Let rangeSeparator be an ILND String value used to separate two numbers.
auto range_separator_symbol = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::RangeSeparator)).value_or("-"sv);
auto range_separator_symbol = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::RangeSeparator).value_or("-"sv);
auto range_separator = TRY_OR_THROW_OOM(vm, ::Locale::augment_range_pattern(range_separator_symbol, result.last().value, end_result[0].value));
// 8. Append a new Record { [[Type]]: "literal", [[Value]]: rangeSeparator, [[Source]]: "shared" } element to result.
@ -1887,7 +1887,7 @@ ThrowCompletionOr<Vector<PatternPartitionWithSource>> partition_number_range_pat
ThrowCompletionOr<Vector<PatternPartitionWithSource>> format_approximately(VM& vm, NumberFormat& number_format, Vector<PatternPartitionWithSource> result)
{
// 1. Let approximatelySign be an ILND String value used to signify that a number is approximate.
auto approximately_sign = TRY_OR_THROW_OOM(vm, ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::ApproximatelySign));
auto approximately_sign = ::Locale::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), ::Locale::NumericSymbol::ApproximatelySign);
// 2. If approximatelySign is not empty, insert a new Record { [[Type]]: "approximatelySign", [[Value]]: approximatelySign } at an ILND index in result. For example, if numberFormat has [[Locale]] "en-US" and [[NumberingSystem]] "latn" and [[Style]] "decimal", the new Record might be inserted before the first element of result.
if (approximately_sign.has_value() && !approximately_sign->is_empty()) {

View file

@ -1262,18 +1262,18 @@ static ThrowCompletionOr<String> transform_case(VM& vm, String const& string, Va
// 2. If requestedLocales is not an empty List, then
if (!requested_locales.is_empty()) {
// a. Let requestedLocale be requestedLocales[0].
requested_locale = TRY_OR_THROW_OOM(vm, Locale::parse_unicode_locale_id(requested_locales[0]));
requested_locale = Locale::parse_unicode_locale_id(requested_locales[0]);
}
// 3. Else,
else {
// a. Let requestedLocale be ! DefaultLocale().
requested_locale = TRY_OR_THROW_OOM(vm, Locale::parse_unicode_locale_id(Locale::default_locale()));
requested_locale = Locale::parse_unicode_locale_id(Locale::default_locale());
}
VERIFY(requested_locale.has_value());
// 4. Let noExtensionsLocale be the String value that is requestedLocale with any Unicode locale extension sequences (6.2.1) removed.
requested_locale->remove_extension_type<Locale::LocaleExtension>();
auto no_extensions_locale = TRY_OR_THROW_OOM(vm, requested_locale->to_string());
auto no_extensions_locale = requested_locale->to_string();
// 5. Let availableLocales be a List with language tags that includes the languages for which the Unicode Character Database contains language sensitive case mappings. Implementations may add additional language tags if they support case mapping for additional locales.
// 6. Let locale be ! BestAvailableLocale(availableLocales, noExtensionsLocale).