浏览代码

LibJS: Include hour-cycle in DateTimeFormat options

This is a normative change to the Intl spec:
https://github.com/tc39/ecma402/commit/20e5c26

Note that this doesn't actually affect us. Its purpose is to provide the
hour-cycle to BestFitFormatMatcher. This AO is implementation defined,
and ours just invokes BasicFormatMatcher, which doesn't use this field.
We could now have LibUnicode generate this field and use it to find a
better format pattern, though.
Timothy Flynn 3 年之前
父节点
当前提交
05de9b82b8
共有 1 个文件被更改,包括 86 次插入91 次删除
  1. 86 91
      Userland/Libraries/LibJS/Runtime/Intl/DateTimeFormat.cpp

+ 86 - 91
Userland/Libraries/LibJS/Runtime/Intl/DateTimeFormat.cpp

@@ -179,7 +179,7 @@ ThrowCompletionOr<DateTimeFormat*> initialize_date_time_format(GlobalObject& glo
     // 27. Set dateTimeFormat.[[TimeZone]] to timeZone.
     // 27. Set dateTimeFormat.[[TimeZone]] to timeZone.
     date_time_format.set_time_zone(move(time_zone));
     date_time_format.set_time_zone(move(time_zone));
 
 
-    // 28. Let opt be a new Record.
+    // 28. Let formatOptions be a new Record.
     Unicode::CalendarPattern format_options {};
     Unicode::CalendarPattern format_options {};
 
 
     // 29. For each row of Table 4, except the header row, in table order, do
     // 29. For each row of Table 4, except the header row, in table order, do
@@ -193,7 +193,7 @@ ThrowCompletionOr<DateTimeFormat*> initialize_date_time_format(GlobalObject& glo
             // i. Let value be ? GetNumberOption(options, "fractionalSecondDigits", 1, 3, undefined).
             // i. Let value be ? GetNumberOption(options, "fractionalSecondDigits", 1, 3, undefined).
             auto value = TRY(get_number_option(global_object, *options, property, 1, 3, {}));
             auto value = TRY(get_number_option(global_object, *options, property, 1, 3, {}));
 
 
-            // d. Set opt.[[<prop>]] to value.
+            // d. Set formatOptions.[[<prop>]] to value.
             if (value.has_value())
             if (value.has_value())
                 option = static_cast<ValueType>(value.value());
                 option = static_cast<ValueType>(value.value());
         }
         }
@@ -202,7 +202,7 @@ ThrowCompletionOr<DateTimeFormat*> initialize_date_time_format(GlobalObject& glo
             // i. Let value be ? GetOption(options, prop, "string", « the strings given in the Values column of the row », undefined).
             // i. Let value be ? GetOption(options, prop, "string", « the strings given in the Values column of the row », undefined).
             auto value = TRY(get_option(global_object, *options, property, Value::Type::String, defaults, Empty {}));
             auto value = TRY(get_option(global_object, *options, property, Value::Type::String, defaults, Empty {}));
 
 
-            // d. Set opt.[[<prop>]] to value.
+            // d. Set formatOptions.[[<prop>]] to value.
             if (!value.is_undefined())
             if (!value.is_undefined())
                 option = Unicode::calendar_pattern_style_from_string(value.as_string().string());
                 option = Unicode::calendar_pattern_style_from_string(value.as_string().string());
         }
         }
@@ -212,31 +212,81 @@ ThrowCompletionOr<DateTimeFormat*> initialize_date_time_format(GlobalObject& glo
 
 
     // 30. Let dataLocaleData be localeData.[[<dataLocale>]].
     // 30. Let dataLocaleData be localeData.[[<dataLocale>]].
 
 
-    // 31. Let matcher be ? GetOption(options, "formatMatcher", "string", « "basic", "best fit" », "best fit").
+    // 31. Let hcDefault be dataLocaleData.[[hourCycle]].
+    auto default_hour_cycle = Unicode::get_default_regional_hour_cycle(data_locale);
+
+    // Non-standard, default_hour_cycle will be empty if Unicode data generation is disabled.
+    if (!default_hour_cycle.has_value())
+        return &date_time_format;
+
+    // 32. Let hc be dateTimeFormat.[[HourCycle]].
+    // 33. If hc is null, then
+    //     a. Set hc to hcDefault.
+    auto hour_cycle_value = date_time_format.has_hour_cycle() ? date_time_format.hour_cycle() : *default_hour_cycle;
+
+    // 34. If hour12 is true, then
+    if (hour12.is_boolean() && hour12.as_bool()) {
+        // a. If hcDefault is "h11" or "h23", then
+        if ((default_hour_cycle == Unicode::HourCycle::H11) || (default_hour_cycle == Unicode::HourCycle::H23)) {
+            // i. Set hc to "h11".
+            hour_cycle_value = Unicode::HourCycle::H11;
+        }
+        // b. Else,
+        else {
+            // i. Set hc to "h12".
+            hour_cycle_value = Unicode::HourCycle::H12;
+        }
+    }
+    // 35. Else if hour12 is false, then
+    else if (hour12.is_boolean() && !hour12.as_bool()) {
+        // a. If hcDefault is "h11" or "h23", then
+        if ((default_hour_cycle == Unicode::HourCycle::H11) || (default_hour_cycle == Unicode::HourCycle::H23)) {
+            // i. Set hc to "h23".
+            hour_cycle_value = Unicode::HourCycle::H23;
+        }
+        // b. Else,
+        else {
+            // i. Set hc to "h24".
+            hour_cycle_value = Unicode::HourCycle::H24;
+        }
+    }
+    // 36. Else,
+    else {
+        // a. Assert: hour12 is undefined.
+        VERIFY(hour12.is_undefined());
+    }
+
+    // 37. Set dateTimeFormat.[[HourCycle]] to hc.
+    date_time_format.set_hour_cycle(hour_cycle_value);
+
+    // 38. Set formatOptions.[[hourCycle]] to hc.
+    format_options.hour_cycle = hour_cycle_value;
+
+    // 39. Let matcher be ? GetOption(options, "formatMatcher", "string", « "basic", "best fit" », "best fit").
     matcher = TRY(get_option(global_object, *options, vm.names.formatMatcher, Value::Type::String, AK::Array { "basic"sv, "best fit"sv }, "best fit"sv));
     matcher = TRY(get_option(global_object, *options, vm.names.formatMatcher, Value::Type::String, AK::Array { "basic"sv, "best fit"sv }, "best fit"sv));
 
 
-    // 32. Let dateStyle be ? GetOption(options, "dateStyle", "string", « "full", "long", "medium", "short" », undefined).
+    // 40. Let dateStyle be ? GetOption(options, "dateStyle", "string", « "full", "long", "medium", "short" », undefined).
     auto date_style = TRY(get_option(global_object, *options, vm.names.dateStyle, Value::Type::String, AK::Array { "full"sv, "long"sv, "medium"sv, "short"sv }, Empty {}));
     auto date_style = TRY(get_option(global_object, *options, vm.names.dateStyle, Value::Type::String, AK::Array { "full"sv, "long"sv, "medium"sv, "short"sv }, Empty {}));
 
 
-    // 33. Set dateTimeFormat.[[DateStyle]] to dateStyle.
+    // 41. Set dateTimeFormat.[[DateStyle]] to dateStyle.
     if (!date_style.is_undefined())
     if (!date_style.is_undefined())
         date_time_format.set_date_style(date_style.as_string().string());
         date_time_format.set_date_style(date_style.as_string().string());
 
 
-    // 34. Let timeStyle be ? GetOption(options, "timeStyle", "string", « "full", "long", "medium", "short" », undefined).
+    // 42. Let timeStyle be ? GetOption(options, "timeStyle", "string", « "full", "long", "medium", "short" », undefined).
     auto time_style = TRY(get_option(global_object, *options, vm.names.timeStyle, Value::Type::String, AK::Array { "full"sv, "long"sv, "medium"sv, "short"sv }, Empty {}));
     auto time_style = TRY(get_option(global_object, *options, vm.names.timeStyle, Value::Type::String, AK::Array { "full"sv, "long"sv, "medium"sv, "short"sv }, Empty {}));
 
 
-    // 35. Set dateTimeFormat.[[TimeStyle]] to timeStyle.
+    // 43. Set dateTimeFormat.[[TimeStyle]] to timeStyle.
     if (!time_style.is_undefined())
     if (!time_style.is_undefined())
         date_time_format.set_time_style(time_style.as_string().string());
         date_time_format.set_time_style(time_style.as_string().string());
 
 
     Optional<Unicode::CalendarPattern> best_format {};
     Optional<Unicode::CalendarPattern> best_format {};
 
 
-    // 36. If dateStyle is not undefined or timeStyle is not undefined, then
+    // 44. If dateStyle is not undefined or timeStyle is not undefined, then
     if (date_time_format.has_date_style() || date_time_format.has_time_style()) {
     if (date_time_format.has_date_style() || date_time_format.has_time_style()) {
         // a. For each row in Table 4, except the header row, do
         // a. For each row in Table 4, except the header row, do
         TRY(for_each_calendar_field(global_object, format_options, [&](auto const& option, auto const& property, auto const&) -> ThrowCompletionOr<void> {
         TRY(for_each_calendar_field(global_object, format_options, [&](auto const& option, auto const& property, auto const&) -> ThrowCompletionOr<void> {
             // i. Let prop be the name given in the Property column of the row.
             // i. Let prop be the name given in the Property column of the row.
-            // ii. Let p be opt.[[<prop>]].
+            // ii. Let p be formatOptions.[[<prop>]].
             // iii. If p is not undefined, then
             // iii. If p is not undefined, then
             if (option.has_value()) {
             if (option.has_value()) {
                 // 1. Throw a TypeError exception.
                 // 1. Throw a TypeError exception.
@@ -250,28 +300,24 @@ ThrowCompletionOr<DateTimeFormat*> initialize_date_time_format(GlobalObject& glo
         // c. Let bestFormat be DateTimeStyleFormat(dateStyle, timeStyle, styles).
         // c. Let bestFormat be DateTimeStyleFormat(dateStyle, timeStyle, styles).
         best_format = date_time_style_format(data_locale, date_time_format);
         best_format = date_time_style_format(data_locale, date_time_format);
     }
     }
-    // 37. Else,
+    // 45. Else,
     else {
     else {
         // a. Let formats be dataLocaleData.[[formats]].[[<calendar>]].
         // a. Let formats be dataLocaleData.[[formats]].[[<calendar>]].
         auto formats = Unicode::get_calendar_available_formats(data_locale, date_time_format.calendar());
         auto formats = Unicode::get_calendar_available_formats(data_locale, date_time_format.calendar());
 
 
         // b. If matcher is "basic", then
         // b. If matcher is "basic", then
         if (matcher.as_string().string() == "basic"sv) {
         if (matcher.as_string().string() == "basic"sv) {
-            // i. Let bestFormat be BasicFormatMatcher(opt, formats).
+            // i. Let bestFormat be BasicFormatMatcher(formatOptions, formats).
             best_format = basic_format_matcher(format_options, move(formats));
             best_format = basic_format_matcher(format_options, move(formats));
         }
         }
         // c. Else,
         // c. Else,
         else {
         else {
-            // i. Let bestFormat be BestFitFormatMatcher(opt, formats).
+            // i. Let bestFormat be BestFitFormatMatcher(formatOptions, formats).
             best_format = best_fit_format_matcher(format_options, move(formats));
             best_format = best_fit_format_matcher(format_options, move(formats));
         }
         }
     }
     }
 
 
-    // Non-standard, best_format will be empty if Unicode data generation is disabled.
-    if (!best_format.has_value())
-        return &date_time_format;
-
-    // 38. For each row in Table 4, except the header row, in table order, do
+    // 46. For each row in Table 4, except the header row, in table order, do
     date_time_format.for_each_calendar_field_zipped_with(*best_format, [&](auto& date_time_format_field, auto const& best_format_field, auto) {
     date_time_format.for_each_calendar_field_zipped_with(*best_format, [&](auto& date_time_format_field, auto const& best_format_field, auto) {
         // a. Let prop be the name given in the Property column of the row.
         // a. Let prop be the name given in the Property column of the row.
         // b. If bestFormat has a field [[<prop>]], then
         // b. If bestFormat has a field [[<prop>]], then
@@ -285,93 +331,42 @@ ThrowCompletionOr<DateTimeFormat*> initialize_date_time_format(GlobalObject& glo
     String pattern;
     String pattern;
     Vector<Unicode::CalendarRangePattern> range_patterns;
     Vector<Unicode::CalendarRangePattern> range_patterns;
 
 
-    // 39. If dateTimeFormat.[[Hour]] is undefined, then
+    // 47. If dateTimeFormat.[[Hour]] is undefined, then
     if (!date_time_format.has_hour()) {
     if (!date_time_format.has_hour()) {
         // a. Set dateTimeFormat.[[HourCycle]] to undefined.
         // a. Set dateTimeFormat.[[HourCycle]] to undefined.
         date_time_format.clear_hour_cycle();
         date_time_format.clear_hour_cycle();
+    }
 
 
-        // b. Let pattern be bestFormat.[[pattern]].
-        pattern = move(best_format->pattern);
+    // 48. If dateTimeformat.[[HourCycle]] is "h11" or "h12", then
+    if ((hour_cycle_value == Unicode::HourCycle::H11) || (hour_cycle_value == Unicode::HourCycle::H12)) {
+        // a. Let pattern be bestFormat.[[pattern12]].
+        if (best_format->pattern12.has_value()) {
+            pattern = best_format->pattern12.release_value();
+        } else {
+            // Non-standard, LibUnicode only provides [[pattern12]] when [[pattern]] has a day
+            // period. Other implementations provide [[pattern12]] as a copy of [[pattern]].
+            pattern = move(best_format->pattern);
+        }
 
 
-        // c. Let rangePatterns be bestFormat.[[rangePatterns]].
-        range_patterns = Unicode::get_calendar_range_formats(data_locale, date_time_format.calendar(), best_format->skeleton);
+        // b. Let rangePatterns be bestFormat.[[rangePatterns12]].
+        range_patterns = Unicode::get_calendar_range12_formats(data_locale, date_time_format.calendar(), best_format->skeleton);
     }
     }
-    // 40. Else,
+    // 49. Else,
     else {
     else {
-        // a. Let hcDefault be dataLocaleData.[[hourCycle]].
-        auto default_hour_cycle = Unicode::get_default_regional_hour_cycle(data_locale);
-        VERIFY(default_hour_cycle.has_value());
-
-        // b. Let hc be dateTimeFormat.[[HourCycle]].
-        // c. If hc is null, then
-        //     i. Set hc to hcDefault.
-        auto hour_cycle = date_time_format.has_hour_cycle() ? date_time_format.hour_cycle() : *default_hour_cycle;
-
-        // d. If hour12 is not undefined, then
-        if (!hour12.is_undefined()) {
-            // i. If hour12 is true, then
-            if (hour12.as_bool()) {
-                // 1. If hcDefault is "h11" or "h23", then
-                if ((default_hour_cycle == Unicode::HourCycle::H11) || (default_hour_cycle == Unicode::HourCycle::H23)) {
-                    // a. Set hc to "h11".
-                    hour_cycle = Unicode::HourCycle::H11;
-                }
-                // 2. Else,
-                else {
-                    // a. Set hc to "h12".
-                    hour_cycle = Unicode::HourCycle::H12;
-                }
-            }
-            // ii. Else,
-            else {
-                // 1. Assert: hour12 is false.
-                // 2. If hcDefault is "h11" or "h23", then
-                if ((default_hour_cycle == Unicode::HourCycle::H11) || (default_hour_cycle == Unicode::HourCycle::H23)) {
-                    // a. Set hc to "h23".
-                    hour_cycle = Unicode::HourCycle::H23;
-                }
-                // 3. Else,
-                else {
-                    // a. Set hc to "h24".
-                    hour_cycle = Unicode::HourCycle::H24;
-                }
-            }
-        }
-
-        // e. Set dateTimeFormat.[[HourCycle]] to hc.
-        date_time_format.set_hour_cycle(hour_cycle);
-
-        // f. If dateTimeformat.[[HourCycle]] is "h11" or "h12", then
-        if ((hour_cycle == Unicode::HourCycle::H11) || (hour_cycle == Unicode::HourCycle::H12)) {
-            // i. Let pattern be bestFormat.[[pattern12]].
-            if (best_format->pattern12.has_value()) {
-                pattern = best_format->pattern12.release_value();
-            } else {
-                // Non-standard, LibUnicode only provides [[pattern12]] when [[pattern]] has a day
-                // period. Other implementations provide [[pattern12]] as a copy of [[pattern]].
-                pattern = move(best_format->pattern);
-            }
-
-            // ii. Let rangePatterns be bestFormat.[[rangePatterns12]].
-            range_patterns = Unicode::get_calendar_range12_formats(data_locale, date_time_format.calendar(), best_format->skeleton);
-        }
-        // g. Else,
-        else {
-            // i. Let pattern be bestFormat.[[pattern]].
-            pattern = move(best_format->pattern);
+        // a. Let pattern be bestFormat.[[pattern]].
+        pattern = move(best_format->pattern);
 
 
-            // ii. Let rangePatterns be bestFormat.[[rangePatterns]].
-            range_patterns = Unicode::get_calendar_range_formats(data_locale, date_time_format.calendar(), best_format->skeleton);
-        }
+        // b. Let rangePatterns be bestFormat.[[rangePatterns]].
+        range_patterns = Unicode::get_calendar_range_formats(data_locale, date_time_format.calendar(), best_format->skeleton);
     }
     }
 
 
-    // 41. Set dateTimeFormat.[[Pattern]] to pattern.
+    // 50. Set dateTimeFormat.[[Pattern]] to pattern.
     date_time_format.set_pattern(move(pattern));
     date_time_format.set_pattern(move(pattern));
 
 
-    // 42. Set dateTimeFormat.[[RangePatterns]] to rangePatterns.
+    // 51. Set dateTimeFormat.[[RangePatterns]] to rangePatterns.
     date_time_format.set_range_patterns(move(range_patterns));
     date_time_format.set_range_patterns(move(range_patterns));
 
 
-    // 43. Return dateTimeFormat.
+    // 52. Return dateTimeFormat.
     return &date_time_format;
     return &date_time_format;
 }
 }