LibJS: Migrate remaining Intl objects to use ResolveOptions

This is an editorial change in the ECMA-402 spec. See:
75e67db
This commit is contained in:
Timothy Flynn 2025-04-07 17:39:23 -04:00 committed by Tim Flynn
commit 2729c88154
Notes: github-actions[bot] 2025-04-08 10:52:47 +00:00
8 changed files with 92 additions and 215 deletions

View file

@ -23,17 +23,6 @@
namespace JS::Intl {
Optional<LocaleKey> locale_key_from_value(Value value)
{
if (value.is_undefined())
return OptionalNone {};
if (value.is_null())
return Empty {};
if (value.is_string())
return value.as_string().utf8_string();
VERIFY_NOT_REACHED();
}
// 6.2.1 IsStructurallyValidLanguageTag ( locale ), https://tc39.es/ecma402/#sec-isstructurallyvalidlanguagetag
bool is_structurally_valid_language_tag(StringView locale)
{

View file

@ -20,7 +20,6 @@
namespace JS::Intl {
using LocaleKey = Variant<Empty, String>;
Optional<LocaleKey> locale_key_from_value(Value);
struct LocaleOptions {
Value locale_matcher;

View file

@ -50,67 +50,45 @@ ThrowCompletionOr<GC::Ref<Object>> DurationFormatConstructor::construct(Function
{
auto& vm = this->vm();
auto locales = vm.argument(0);
auto locales_value = vm.argument(0);
auto options_value = vm.argument(1);
// 2. Let durationFormat be ? OrdinaryCreateFromConstructor(NewTarget, "%Intl.DurationFormatPrototype%", « [[InitializedDurationFormat]], [[Locale]], [[NumberingSystem]], [[Style]], [[YearsOptions]], [[MonthsOptions]], [[WeeksOptions]], [[DaysOptions]], [[HoursOptions]], [[MinutesOptions]], [[SecondsOptions]], [[MillisecondsOptions]], [[MicrosecondsOptions]], [[NanosecondsOptions]], [[HourMinuteSeparator]], [[MinuteSecondSeparator]], [[FractionalDigits]] »).
auto duration_format = TRY(ordinary_create_from_constructor<DurationFormat>(vm, new_target, &Intrinsics::intl_duration_format_prototype));
// 3. Let requestedLocales be ? CanonicalizeLocaleList(locales).
auto requested_locales = TRY(canonicalize_locale_list(vm, locales));
// 3. Let optionsResolution be ? ResolveOptions(%Intl.DurationFormat%, %Intl.DurationFormat%.[[LocaleData]], locales, options).
// 4. Set options to optionsResolution.[[Options]].
// 5. Let r be optionsResolution.[[ResolvedLocale]].
auto [options, result, _] = TRY(resolve_options(vm, duration_format, locales_value, options_value));
// 4. Let options be ? GetOptionsObject(options).
auto options = TRY(get_options_object(vm, options_value));
// 5. Let matcher be ? GetOption(options, "localeMatcher", STRING, « "lookup", "best fit" », "best fit").
auto matcher = TRY(get_option(vm, *options, vm.names.localeMatcher, OptionType::String, { "lookup"sv, "best fit"sv }, "best fit"sv));
// 6. Let numberingSystem be ? GetOption(options, "numberingSystem", STRING, EMPTY, undefined).
auto numbering_system = TRY(get_option(vm, *options, vm.names.numberingSystem, OptionType::String, {}, Empty {}));
// 7. If numberingSystem is not undefined, then
if (!numbering_system.is_undefined()) {
// a. If numberingSystem cannot be matched by the type Unicode locale nonterminal, throw a RangeError exception.
if (!Unicode::is_type_identifier(numbering_system.as_string().utf8_string_view()))
return vm.throw_completion<RangeError>(ErrorType::OptionIsNotValidValue, numbering_system, "numberingSystem"sv);
}
// 8. Let opt be the Record { [[localeMatcher]]: matcher, [[nu]]: numberingSystem }.
LocaleOptions opt {};
opt.locale_matcher = matcher;
opt.nu = locale_key_from_value(numbering_system);
// 9. Let r be ResolveLocale(%Intl.DurationFormat%.[[AvailableLocales]], requestedLocales, opt, %Intl.DurationFormat%.[[RelevantExtensionKeys]], %Intl.DurationFormat%.[[LocaleData]]).
auto result = resolve_locale(requested_locales, opt, duration_format->relevant_extension_keys());
// 10. Set durationFormat.[[Locale]] to r.[[Locale]].
// 6. Set durationFormat.[[Locale]] to r.[[Locale]].
duration_format->set_locale(move(result.locale));
// 11. Let resolvedLocaleData be r.[[LocaleData]].
// 7. Let resolvedLocaleData be r.[[LocaleData]].
// 12. Let digitalFormat be resolvedLocaleData.[[DigitalFormat]].
// 8. Let digitalFormat be resolvedLocaleData.[[DigitalFormat]].
auto digital_format = Unicode::digital_format(result.icu_locale);
// 13. Set durationFormat.[[HourMinuteSeparator]] to digitalFormat.[[HourMinuteSeparator]].
// 9. Set durationFormat.[[HourMinuteSeparator]] to digitalFormat.[[HourMinuteSeparator]].
duration_format->set_hour_minute_separator(move(digital_format.hours_minutes_separator));
// 14. Set durationFormat.[[MinuteSecondSeparator]] to digitalFormat.[[MinuteSecondSeparator]].
// 10. Set durationFormat.[[MinuteSecondSeparator]] to digitalFormat.[[MinuteSecondSeparator]].
duration_format->set_minute_second_separator(move(digital_format.minutes_seconds_separator));
// 15. Set durationFormat.[[NumberingSystem]] to r.[[nu]].
// 11. Set durationFormat.[[NumberingSystem]] to r.[[nu]].
if (auto* resolved_numbering_system = result.nu.get_pointer<String>())
duration_format->set_numbering_system(move(*resolved_numbering_system));
// 16. Let style be ? GetOption(options, "style", STRING, « "long", "short", "narrow", "digital" », "short").
// 12. Let style be ? GetOption(options, "style", STRING, « "long", "short", "narrow", "digital" », "short").
auto style = TRY(get_option(vm, *options, vm.names.style, OptionType::String, { "long"sv, "short"sv, "narrow"sv, "digital"sv }, "short"sv));
// 17. Set durationFormat.[[Style]] to style.
// 13. Set durationFormat.[[Style]] to style.
duration_format->set_style(style.as_string().utf8_string_view());
// 18. Let prevStyle be the empty String.
// 14. Let prevStyle be the empty String.
Optional<DurationFormat::ValueStyle> previous_style;
// 19. For each row of Table 20, except the header row, in table order, do
// 15. For each row of Table 20, except the header row, in table order, do
for (auto const& duration_instances_component : duration_instances_components) {
// a. Let slot be the Internal Slot value of the current row.
auto slot = duration_instances_component.set_internal_slot;
@ -137,10 +115,10 @@ ThrowCompletionOr<GC::Ref<Object>> DurationFormatConstructor::construct(Function
}
}
// 20. Set durationFormat.[[FractionalDigits]] to ? GetNumberOption(options, "fractionalDigits", 0, 9, undefined).
// 16. Set durationFormat.[[FractionalDigits]] to ? GetNumberOption(options, "fractionalDigits", 0, 9, undefined).
duration_format->set_fractional_digits(Optional<u8>(TRY(get_number_option(vm, *options, vm.names.fractionalDigits, 0, 9, {}))));
// 21. Return durationFormat.
// 17. Return durationFormat.
return duration_format;
}

View file

@ -48,55 +48,42 @@ ThrowCompletionOr<GC::Ref<Object>> ListFormatConstructor::construct(FunctionObje
{
auto& vm = this->vm();
auto locale_value = vm.argument(0);
auto locales_value = vm.argument(0);
auto options_value = vm.argument(1);
// 2. Let listFormat be ? OrdinaryCreateFromConstructor(NewTarget, "%Intl.ListFormat.prototype%", « [[InitializedListFormat]], [[Locale]], [[Type]], [[Style]], [[Templates]] »).
auto list_format = TRY(ordinary_create_from_constructor<ListFormat>(vm, new_target, &Intrinsics::intl_list_format_prototype));
// 3. Let requestedLocales be ? CanonicalizeLocaleList(locales).
auto requested_locales = TRY(canonicalize_locale_list(vm, locale_value));
// 3. Let optionsResolution be ? ResolveOptions(%Intl.ListFormat%, %Intl.ListFormat%.[[LocaleData]], locales, options).
// 4. Set options to optionsResolution.[[Options]].
// 5. Let r be optionsResolution.[[ResolvedLocale]].
auto [options, result, _] = TRY(resolve_options(vm, list_format, locales_value, options_value));
// 4. Set options to ? GetOptionsObject(options).
auto options = TRY(get_options_object(vm, options_value));
// 5. Let opt be a new Record.
LocaleOptions opt {};
// 6. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit").
auto matcher = TRY(get_option(vm, *options, vm.names.localeMatcher, OptionType::String, { "lookup"sv, "best fit"sv }, "best fit"sv));
// 7. Set opt.[[localeMatcher]] to matcher.
opt.locale_matcher = matcher;
// 8. Let r be ResolveLocale(%Intl.ListFormat%.[[AvailableLocales]], requestedLocales, opt, %Intl.ListFormat%.[[RelevantExtensionKeys]], %Intl.ListFormat%.[[LocaleData]]).
auto result = resolve_locale(requested_locales, opt, list_format->relevant_extension_keys());
// 9. Set listFormat.[[Locale]] to r.[[Locale]].
// 6. Set listFormat.[[Locale]] to r.[[Locale]].
list_format->set_locale(move(result.locale));
// 10. Let type be ? GetOption(options, "type", string, « "conjunction", "disjunction", "unit" », "conjunction").
// 7. Let type be ? GetOption(options, "type", string, « "conjunction", "disjunction", "unit" », "conjunction").
auto type = TRY(get_option(vm, *options, vm.names.type, OptionType::String, { "conjunction"sv, "disjunction"sv, "unit"sv }, "conjunction"sv));
// 11. Set listFormat.[[Type]] to type.
// 8. Set listFormat.[[Type]] to type.
list_format->set_type(type.as_string().utf8_string_view());
// 12. Let style be ? GetOption(options, "style", string, « "long", "short", "narrow" », "long").
// 9. Let style be ? GetOption(options, "style", string, « "long", "short", "narrow" », "long").
auto style = TRY(get_option(vm, *options, vm.names.style, OptionType::String, { "long"sv, "short"sv, "narrow"sv }, "long"sv));
// 14. Set listFormat.[[Style]] to style.
// 10. Set listFormat.[[Style]] to style.
list_format->set_style(style.as_string().utf8_string_view());
// 14. Let resolvedLocaleData be r.[[LocaleData]].
// 15. Let dataLocaleTypes be resolvedLocaleData.[[<type>]].
// 16. Set listFormat.[[Templates]] to dataLocaleTypes.[[<style>]].
// 11. Let resolvedLocaleData be r.[[LocaleData]].
// 12. Let dataLocaleTypes be resolvedLocaleData.[[<type>]].
// 13. Set listFormat.[[Templates]] to dataLocaleTypes.[[<style>]].
auto formatter = Unicode::ListFormat::create(
list_format->locale(),
list_format->type(),
list_format->style());
list_format->set_formatter(move(formatter));
// 17. Return listFormat.
// 14. Return listFormat.
return list_format;
}

View file

@ -54,62 +54,36 @@ ThrowCompletionOr<GC::Ref<Object>> NumberFormatConstructor::construct(FunctionOb
// 2. Let numberFormat be ? OrdinaryCreateFromConstructor(newTarget, "%Intl.NumberFormat.prototype%", « [[InitializedNumberFormat]], [[Locale]], [[LocaleData]], [[NumberingSystem]], [[Style]], [[Unit]], [[UnitDisplay]], [[Currency]], [[CurrencyDisplay]], [[CurrencySign]], [[MinimumIntegerDigits]], [[MinimumFractionDigits]], [[MaximumFractionDigits]], [[MinimumSignificantDigits]], [[MaximumSignificantDigits]], [[RoundingType]], [[Notation]], [[CompactDisplay]], [[UseGrouping]], [[SignDisplay]], [[RoundingIncrement]], [[RoundingMode]], [[ComputedRoundingPriority]], [[TrailingZeroDisplay]], [[BoundFormat]] »).
auto number_format = TRY(ordinary_create_from_constructor<NumberFormat>(vm, new_target, &Intrinsics::intl_number_format_prototype));
// 3. Let requestedLocales be ? CanonicalizeLocaleList(locales).
auto requested_locales = TRY(canonicalize_locale_list(vm, locales_value));
// 3. Let optionsResolution be ? ResolveOptions(%Intl.NumberFormat%, %Intl.NumberFormat%.[[LocaleData]], locales, options, « COERCE-OPTIONS »).
// 4. Set options to optionsResolution.[[Options]].
// 5. Let r be optionsResolution.[[ResolvedLocale]].
auto [options, result, _] = TRY(resolve_options(vm, number_format, locales_value, options_value, SpecialBehaviors::CoerceOptions));
// 4. Set options to ? CoerceOptionsToObject(options).
auto* options = TRY(coerce_options_to_object(vm, options_value));
// 5. Let opt be a new Record.
LocaleOptions opt {};
// 6. Let matcher be ? GetOption(options, "localeMatcher", STRING, « "lookup", "best fit" », "best fit").
auto matcher = TRY(get_option(vm, *options, vm.names.localeMatcher, OptionType::String, { "lookup"sv, "best fit"sv }, "best fit"sv));
// 7. Set opt.[[localeMatcher]] to matcher.
opt.locale_matcher = matcher;
// 8. Let numberingSystem be ? GetOption(options, "numberingSystem", STRING, EMPTY, undefined).
auto numbering_system = TRY(get_option(vm, *options, vm.names.numberingSystem, OptionType::String, {}, Empty {}));
// 9. If numberingSystem is not undefined, then
if (!numbering_system.is_undefined()) {
// a. If numberingSystem cannot be matched by the type Unicode locale nonterminal, throw a RangeError exception.
if (!Unicode::is_type_identifier(numbering_system.as_string().utf8_string_view()))
return vm.throw_completion<RangeError>(ErrorType::OptionIsNotValidValue, numbering_system, "numberingSystem"sv);
}
// 10. Set opt.[[nu]] to numberingSystem.
opt.nu = locale_key_from_value(numbering_system);
// 11. Let r be ResolveLocale(%Intl.NumberFormat%.[[AvailableLocales]], requestedLocales, opt, %Intl.NumberFormat%.[[RelevantExtensionKeys]], %Intl.NumberFormat%.[[LocaleData]]).
auto result = resolve_locale(requested_locales, opt, number_format->relevant_extension_keys());
// 12. Set numberFormat.[[Locale]] to r.[[Locale]].
// 6. Set numberFormat.[[Locale]] to r.[[Locale]].
number_format->set_locale(move(result.locale));
// 13. Set numberFormat.[[LocaleData]] to r.[[LocaleData]].
// 7. Set numberFormat.[[LocaleData]] to r.[[LocaleData]].
// 14. Set numberFormat.[[NumberingSystem]] to r.[[nu]].
// 8. Set numberFormat.[[NumberingSystem]] to r.[[nu]].
if (auto* resolved_numbering_system = result.nu.get_pointer<String>())
number_format->set_numbering_system(move(*resolved_numbering_system));
// 15. Perform ? SetNumberFormatUnitOptions(numberFormat, options).
// 9. Perform ? SetNumberFormatUnitOptions(numberFormat, options).
TRY(set_number_format_unit_options(vm, number_format, *options));
// 16. Let style be numberFormat.[[Style]].
// 10. Let style be numberFormat.[[Style]].
auto style = number_format->style();
// 17. Let notation be ? GetOption(options, "notation", STRING, « "standard", "scientific", "engineering", "compact" », "standard").
// 11. Let notation be ? GetOption(options, "notation", STRING, « "standard", "scientific", "engineering", "compact" », "standard").
auto notation = TRY(get_option(vm, *options, vm.names.notation, OptionType::String, { "standard"sv, "scientific"sv, "engineering"sv, "compact"sv }, "standard"sv));
// 18. Set numberFormat.[[Notation]] to notation.
// 12. Set numberFormat.[[Notation]] to notation.
number_format->set_notation(notation.as_string().utf8_string_view());
int default_min_fraction_digits = 0;
int default_max_fraction_digits = 0;
// 19. If style is "currency" and notation is "standard", then
// 13. If style is "currency" and notation is "standard", then
if (style == Unicode::NumberFormatStyle::Currency && number_format->notation() == Unicode::Notation::Standard) {
// a. Let currency be numberFormat.[[Currency]].
auto const& currency = number_format->currency();
@ -123,7 +97,7 @@ ThrowCompletionOr<GC::Ref<Object>> NumberFormatConstructor::construct(FunctionOb
// d. Let mxfdDefault be cDigits.
default_max_fraction_digits = digits;
}
// 20. Else,
// 14. Else,
else {
// a. Let mnfdDefault be 0.
default_min_fraction_digits = 0;
@ -135,16 +109,16 @@ ThrowCompletionOr<GC::Ref<Object>> NumberFormatConstructor::construct(FunctionOb
default_max_fraction_digits = style == Unicode::NumberFormatStyle::Percent ? 0 : 3;
}
// 21. Perform ? SetNumberFormatDigitOptions(numberFormat, options, mnfdDefault, mxfdDefault, notation).
// 15. Perform ? SetNumberFormatDigitOptions(numberFormat, options, mnfdDefault, mxfdDefault, notation).
TRY(set_number_format_digit_options(vm, number_format, *options, default_min_fraction_digits, default_max_fraction_digits, number_format->notation()));
// 22. Let compactDisplay be ? GetOption(options, "compactDisplay", STRING, « "short", "long" », "short").
// 16. Let compactDisplay be ? GetOption(options, "compactDisplay", STRING, « "short", "long" », "short").
auto compact_display = TRY(get_option(vm, *options, vm.names.compactDisplay, OptionType::String, { "short"sv, "long"sv }, "short"sv));
// 23. Let defaultUseGrouping be "auto".
// 17. Let defaultUseGrouping be "auto".
auto default_use_grouping = "auto"sv;
// 24. If notation is "compact", then
// 18. If notation is "compact", then
if (number_format->notation() == Unicode::Notation::Compact) {
// a. Set numberFormat.[[CompactDisplay]] to compactDisplay.
number_format->set_compact_display(compact_display.as_string().utf8_string_view());
@ -153,32 +127,32 @@ ThrowCompletionOr<GC::Ref<Object>> NumberFormatConstructor::construct(FunctionOb
default_use_grouping = "min2"sv;
}
// 25. NOTE: For historical reasons, the strings "true" and "false" are accepted and replaced with the default value.
// 26. Let useGrouping be ? GetBooleanOrStringNumberFormatOption(options, "useGrouping", « "min2", "auto", "always", "true", "false" », defaultUseGrouping).
// 19. NOTE: For historical reasons, the strings "true" and "false" are accepted and replaced with the default value.
// 20. Let useGrouping be ? GetBooleanOrStringNumberFormatOption(options, "useGrouping", « "min2", "auto", "always", "true", "false" », defaultUseGrouping).
auto use_grouping = TRY(get_boolean_or_string_number_format_option(vm, *options, vm.names.useGrouping, { "min2"sv, "auto"sv, "always"sv, "true"sv, "false"sv }, default_use_grouping));
// 27. If useGrouping is "true" or useGrouping is "false", set useGrouping to defaultUseGrouping.
// 21. If useGrouping is "true" or useGrouping is "false", set useGrouping to defaultUseGrouping.
if (auto const* use_grouping_string = use_grouping.get_pointer<StringView>()) {
if (use_grouping_string->is_one_of("true"sv, "false"sv))
use_grouping = default_use_grouping;
}
// 28. If useGrouping is true, set useGrouping to "always".
// 22. If useGrouping is true, set useGrouping to "always".
if (auto const* use_grouping_boolean = use_grouping.get_pointer<bool>()) {
if (*use_grouping_boolean)
use_grouping = "always"sv;
}
// 29. Set numberFormat.[[UseGrouping]] to useGrouping.
// 23. Set numberFormat.[[UseGrouping]] to useGrouping.
number_format->set_use_grouping(use_grouping);
// 30. Let signDisplay be ? GetOption(options, "signDisplay", STRING, « "auto", "never", "always", "exceptZero", "negative" », "auto").
// 24. Let signDisplay be ? GetOption(options, "signDisplay", STRING, « "auto", "never", "always", "exceptZero", "negative" », "auto").
auto sign_display = TRY(get_option(vm, *options, vm.names.signDisplay, OptionType::String, { "auto"sv, "never"sv, "always"sv, "exceptZero"sv, "negative"sv }, "auto"sv));
// 31. Set numberFormat.[[SignDisplay]] to signDisplay.
// 25. Set numberFormat.[[SignDisplay]] to signDisplay.
number_format->set_sign_display(sign_display.as_string().utf8_string_view());
// 32. If the implementation supports the normative optional constructor mode of 4.3 Note 1, then
// 26. If the implementation supports the normative optional constructor mode of 4.3 Note 1, then
// a. Let this be the this value.
// b. Return ? ChainNumberFormat(numberFormat, NewTarget, this).
@ -189,7 +163,7 @@ ThrowCompletionOr<GC::Ref<Object>> NumberFormatConstructor::construct(FunctionOb
number_format->rounding_options());
number_format->set_formatter(move(formatter));
// 33. Return numberFormat.
// 27. Return numberFormat.
return number_format;
}

View file

@ -55,34 +55,21 @@ ThrowCompletionOr<GC::Ref<Object>> PluralRulesConstructor::construct(FunctionObj
// 2. Let pluralRules be ? OrdinaryCreateFromConstructor(NewTarget, "%Intl.PluralRules.prototype%", « [[InitializedPluralRules]], [[Locale]], [[Type]], [[MinimumIntegerDigits]], [[MinimumFractionDigits]], [[MaximumFractionDigits]], [[MinimumSignificantDigits]], [[MaximumSignificantDigits]], [[RoundingType]], [[RoundingIncrement]], [[RoundingMode]], [[ComputedRoundingPriority]], [[TrailingZeroDisplay]] »).
auto plural_rules = TRY(ordinary_create_from_constructor<PluralRules>(vm, new_target, &Intrinsics::intl_plural_rules_prototype));
// 3. Let requestedLocales be ? CanonicalizeLocaleList(locales).
auto requested_locales = TRY(canonicalize_locale_list(vm, locales_value));
// 3. Let optionsResolution be ? ResolveOptions(%Intl.PluralRules%, %Intl.PluralRules%.[[LocaleData]], locales, options, « COERCE-OPTIONS »).
// 4. Set options to optionsResolution.[[Options]].
// 5. Let r be optionsResolution.[[ResolvedLocale]].
auto [options, result, _] = TRY(resolve_options(vm, plural_rules, locales_value, options_value, SpecialBehaviors::CoerceOptions));
// 4. Set options to ? CoerceOptionsToObject(options).
auto* options = TRY(coerce_options_to_object(vm, options_value));
// 5. Let opt be a new Record.
LocaleOptions opt {};
// 6. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit").
auto matcher = TRY(get_option(vm, *options, vm.names.localeMatcher, OptionType::String, AK::Array { "lookup"sv, "best fit"sv }, "best fit"sv));
// 7. Set opt.[[localeMatcher]] to matcher.
opt.locale_matcher = matcher;
// 8. Let r be ResolveLocale(%Intl.PluralRules%.[[AvailableLocales]], requestedLocales, opt, %Intl.PluralRules%.[[RelevantExtensionKeys]], %Intl.PluralRules%.[[LocaleData]]).
auto result = resolve_locale(requested_locales, opt, plural_rules->relevant_extension_keys());
// 9. Set pluralRules.[[Locale]] to r.[[locale]].
// 6. Set pluralRules.[[Locale]] to r.[[locale]].
plural_rules->set_locale(move(result.locale));
// 10. Let t be ? GetOption(options, "type", string, « "cardinal", "ordinal" », "cardinal").
// 7. Let t be ? GetOption(options, "type", string, « "cardinal", "ordinal" », "cardinal").
auto type = TRY(get_option(vm, *options, vm.names.type, OptionType::String, AK::Array { "cardinal"sv, "ordinal"sv }, "cardinal"sv));
// 11. Set pluralRules.[[Type]] to t.
// 8. Set pluralRules.[[Type]] to t.
plural_rules->set_type(type.as_string().utf8_string_view());
// 12. Perform ? SetNumberFormatDigitOptions(pluralRules, options, 0, 3, "standard").
// 9. Perform ? SetNumberFormatDigitOptions(pluralRules, options, 0, 3, "standard").
TRY(set_number_format_digit_options(vm, plural_rules, *options, 0, 3, Unicode::Notation::Standard));
// Non-standard, create an ICU number formatter for this Intl object.
@ -94,7 +81,7 @@ ThrowCompletionOr<GC::Ref<Object>> PluralRulesConstructor::construct(FunctionObj
formatter->create_plural_rules(plural_rules->type());
plural_rules->set_formatter(move(formatter));
// 13. Return pluralRules.
// 10. Return pluralRules.
return plural_rules;
}

View file

@ -54,69 +54,45 @@ ThrowCompletionOr<GC::Ref<Object>> RelativeTimeFormatConstructor::construct(Func
// 2. Let relativeTimeFormat be ? OrdinaryCreateFromConstructor(NewTarget, "%Intl.RelativeTimeFormat.prototype%", « [[InitializedRelativeTimeFormat]], [[Locale]], [[LocaleData]], [[Style]], [[Numeric]], [[NumberFormat]], [[NumberingSystem]], [[PluralRules]] »).
auto relative_time_format = TRY(ordinary_create_from_constructor<RelativeTimeFormat>(vm, new_target, &Intrinsics::intl_relative_time_format_prototype));
// 3. Let requestedLocales be ? CanonicalizeLocaleList(locales).
auto requested_locales = TRY(canonicalize_locale_list(vm, locales_value));
// 3. Let optionsResolution be ? ResolveOptions(%Intl.RelativeTimeFormat%, %Intl.RelativeTimeFormat%.[[LocaleData]], locales, options, « COERCE-OPTIONS »).
// 4. Set options to optionsResolution.[[Options]].
// 5. Let r be optionsResolution.[[ResolvedLocale]].
auto [options, result, _] = TRY(resolve_options(vm, relative_time_format, locales_value, options_value, SpecialBehaviors::CoerceOptions));
// 4. Set options to ? CoerceOptionsToObject(options).
auto* options = TRY(coerce_options_to_object(vm, options_value));
// 5. Let opt be a new Record.
LocaleOptions opt {};
// 6. Let matcher be ? GetOption(options, "localeMatcher", STRING, « "lookup", "best fit" », "best fit").
auto matcher = TRY(get_option(vm, *options, vm.names.localeMatcher, OptionType::String, AK::Array { "lookup"sv, "best fit"sv }, "best fit"sv));
// 7. Set opt.[[LocaleMatcher]] to matcher.
opt.locale_matcher = matcher;
// 8. Let numberingSystem be ? GetOption(options, "numberingSystem", STRING, EMPTY, undefined).
auto numbering_system = TRY(get_option(vm, *options, vm.names.numberingSystem, OptionType::String, {}, Empty {}));
// 9. If numberingSystem is not undefined, then
if (!numbering_system.is_undefined()) {
// a. If numberingSystem cannot be matched by the type Unicode locale nonterminal, throw a RangeError exception.
if (!Unicode::is_type_identifier(numbering_system.as_string().utf8_string_view()))
return vm.throw_completion<RangeError>(ErrorType::OptionIsNotValidValue, numbering_system, "numberingSystem"sv);
}
// 10. Set opt.[[nu]] to numberingSystem.
opt.nu = locale_key_from_value(numbering_system);
// 11. Let r be ResolveLocale(%Intl.RelativeTimeFormat%.[[AvailableLocales]], requestedLocales, opt, %Intl.RelativeTimeFormat%.[[RelevantExtensionKeys]], %Intl.RelativeTimeFormat%.[[LocaleData]]).
auto result = resolve_locale(requested_locales, opt, relative_time_format->relevant_extension_keys());
// 12. Let locale be r.[[Locale]].
// 6. Let locale be r.[[Locale]].
auto locale = move(result.locale);
// 13. Set relativeTimeFormat.[[Locale]] to locale.
// 7. Set relativeTimeFormat.[[Locale]] to locale.
relative_time_format->set_locale(locale);
// 14. Set relativeTimeFormat.[[LocaleData]] to r.[[LocaleData]].
// 8. Set relativeTimeFormat.[[LocaleData]] to r.[[LocaleData]].
// 15. Set relativeTimeFormat.[[NumberingSystem]] to r.[[nu]].
// 9. Set relativeTimeFormat.[[NumberingSystem]] to r.[[nu]].
if (auto* resolved_numbering_system = result.nu.get_pointer<String>())
relative_time_format->set_numbering_system(move(*resolved_numbering_system));
// 16. Let style be ? GetOption(options, "style", STRING, « "long", "short", "narrow" », "long").
// 10. Let style be ? GetOption(options, "style", STRING, « "long", "short", "narrow" », "long").
auto style = TRY(get_option(vm, *options, vm.names.style, OptionType::String, { "long"sv, "short"sv, "narrow"sv }, "long"sv));
// 17. Set relativeTimeFormat.[[Style]] to style.
// 11. Set relativeTimeFormat.[[Style]] to style.
relative_time_format->set_style(style.as_string().utf8_string_view());
// 18. Let numeric be ? GetOption(options, "numeric", STRING, « "always", "auto" », "always").
// 12. Let numeric be ? GetOption(options, "numeric", STRING, « "always", "auto" », "always").
auto numeric = TRY(get_option(vm, *options, vm.names.numeric, OptionType::String, { "always"sv, "auto"sv }, "always"sv));
// 19. Set relativeTimeFormat.[[Numeric]] to numeric.
// 13. Set relativeTimeFormat.[[Numeric]] to numeric.
relative_time_format->set_numeric(numeric.as_string().utf8_string_view());
// 20. Let relativeTimeFormat.[[NumberFormat]] be ! Construct(%Intl.NumberFormat%, « locale »).
// 21. Let relativeTimeFormat.[[PluralRules]] be ! Construct(%Intl.PluralRules%, « locale »).
// 14. Let nfOptions be OrdinaryObjectCreate(null).
// 15. Perform ! CreateDataPropertyOrThrow(nfOptions, "numberingSystem", relativeTimeFormat.[[NumberingSystem]]).
// 16. Let relativeTimeFormat.[[NumberFormat]] be ! Construct(%Intl.NumberFormat%, « locale, nfOptions »).
// 17. Let relativeTimeFormat.[[PluralRules]] be ! Construct(%Intl.PluralRules%, « locale »).
auto formatter = Unicode::RelativeTimeFormat::create(
result.icu_locale,
relative_time_format->style());
relative_time_format->set_formatter(move(formatter));
// 22. Return relativeTimeFormat.
// 18. Return relativeTimeFormat.
return relative_time_format;
}

View file

@ -48,44 +48,31 @@ ThrowCompletionOr<GC::Ref<Object>> SegmenterConstructor::construct(FunctionObjec
{
auto& vm = this->vm();
auto locales = vm.argument(0);
auto locales_value = vm.argument(0);
auto options_value = vm.argument(1);
// 2. Let internalSlotsList be « [[InitializedSegmenter]], [[Locale]], [[SegmenterGranularity]] ».
// 3. Let segmenter be ? OrdinaryCreateFromConstructor(NewTarget, "%Intl.Segmenter.prototype%", internalSlotsList).
auto segmenter = TRY(ordinary_create_from_constructor<Segmenter>(vm, new_target, &Intrinsics::intl_segmenter_prototype));
// 4. Let requestedLocales be ? CanonicalizeLocaleList(locales).
auto requested_locales = TRY(canonicalize_locale_list(vm, locales));
// 4. Let optionsResolution be ? ResolveOptions(%Intl.Segmenter%, %Intl.Segmenter%.[[LocaleData]], locales, options).
// 5. Set options to optionsResolution.[[Options]].
// 6. Let r be optionsResolution.[[ResolvedLocale]].
auto [options, result, _] = TRY(resolve_options(vm, segmenter, locales_value, options_value));
// 5. Set options to ? GetOptionsObject(options).
auto options = TRY(get_options_object(vm, options_value));
// 6. Let opt be a new Record.
LocaleOptions opt {};
// 7. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit").
auto matcher = TRY(get_option(vm, *options, vm.names.localeMatcher, OptionType::String, { "lookup"sv, "best fit"sv }, "best fit"sv));
// 8. Set opt.[[localeMatcher]] to matcher.
opt.locale_matcher = matcher;
// 9. Let r be ResolveLocale(%Intl.Segmenter%.[[AvailableLocales]], requestedLocales, opt, %Intl.Segmenter%.[[RelevantExtensionKeys]], %Intl.Segmenter%.[[LocaleData]]).
auto result = resolve_locale(requested_locales, opt, segmenter->relevant_extension_keys());
// 10. Set segmenter.[[Locale]] to r.[[locale]].
// 7. Set segmenter.[[Locale]] to r.[[locale]].
segmenter->set_locale(move(result.locale));
// 11. Let granularity be ? GetOption(options, "granularity", string, « "grapheme", "word", "sentence" », "grapheme").
// 8. Let granularity be ? GetOption(options, "granularity", string, « "grapheme", "word", "sentence" », "grapheme").
auto granularity = TRY(get_option(vm, *options, vm.names.granularity, OptionType::String, { "grapheme"sv, "word"sv, "sentence"sv }, "grapheme"sv));
// 12. Set segmenter.[[SegmenterGranularity]] to granularity.
// 9. Set segmenter.[[SegmenterGranularity]] to granularity.
segmenter->set_segmenter_granularity(granularity.as_string().utf8_string_view());
auto locale_segmenter = Unicode::Segmenter::create(segmenter->locale(), segmenter->segmenter_granularity());
segmenter->set_segmenter(move(locale_segmenter));
// 13. Return segmenter.
// 10. Return segmenter.
return segmenter;
}