diff --git a/Libraries/LibJS/Runtime/Intl/DurationFormat.cpp b/Libraries/LibJS/Runtime/Intl/DurationFormat.cpp index 8dbf52c3e28..5bb30451797 100644 --- a/Libraries/LibJS/Runtime/Intl/DurationFormat.cpp +++ b/Libraries/LibJS/Runtime/Intl/DurationFormat.cpp @@ -185,7 +185,7 @@ static GC::Ref construct_list_format(VM& vm, DurationFormat const& d return static_cast(*list_format); } -// 13.1.6 GetDurationUnitOptions ( unit, options, baseStyle, stylesList, digitalBase, prevStyle, twoDigitHours ), https://tc39.es/ecma402/#sec-getdurationunitoptions +// 13.5.6 GetDurationUnitOptions ( unit, options, baseStyle, stylesList, digitalBase, prevStyle, twoDigitHours ), https://tc39.es/ecma402/#sec-getdurationunitoptions ThrowCompletionOr get_duration_unit_options(VM& vm, DurationFormat::Unit unit, Object const& options, DurationFormat::Style base_style, ReadonlySpan styles_list, DurationFormat::ValueStyle digital_base, Optional previous_style, bool two_digit_hours) { auto const& unit_property_key = unit_to_property_key(vm, unit); @@ -295,7 +295,7 @@ ThrowCompletionOr get_duration_unit_options(VM& vm, Duratio return DurationUnitOptions { .style = style, .display = display }; } -// 13.1.7 ComputeFractionalDigits ( durationFormat, duration ), https://tc39.es/ecma402/#sec-computefractionaldigits +// 13.5.7 ComputeFractionalDigits ( durationFormat, duration ), https://tc39.es/ecma402/#sec-computefractionaldigits // 15.9.6 ComputeFractionalDigits ( durationFormat, duration ), https://tc39.es/proposal-temporal/#sec-computefractionaldigits Crypto::BigFraction compute_fractional_digits(DurationFormat const& duration_format, Temporal::Duration const& duration) { @@ -305,7 +305,7 @@ Crypto::BigFraction compute_fractional_digits(DurationFormat const& duration_for // 2. Let exponent be 3. double exponent = 3; - // 3. For each row of Table 21, except the header row, in table order, do + // 3. For each row of Table 23, except the header row, in table order, do for (auto const& duration_instances_component : duration_instances_components) { // a. Let style be the value of durationFormat's internal slot whose name is the Style Slot value of the current row. auto style = (duration_format.*duration_instances_component.get_style_slot)(); @@ -334,7 +334,7 @@ Crypto::BigFraction compute_fractional_digits(DurationFormat const& duration_for return result; } -// 13.1.8 NextUnitFractional ( durationFormat, unit ), https://tc39.es/ecma402/#sec-nextunitfractional +// 13.5.8 NextUnitFractional ( durationFormat, unit ), https://tc39.es/ecma402/#sec-nextunitfractional bool next_unit_fractional(DurationFormat const& duration_format, DurationFormat::Unit unit) { // 1. Assert: unit is "seconds", "milliseconds", or "microseconds". @@ -356,7 +356,7 @@ bool next_unit_fractional(DurationFormat const& duration_format, DurationFormat: return false; } -// 13.1.9 FormatNumericHours ( durationFormat, hoursValue, signDisplayed ), https://tc39.es/ecma402/#sec-formatnumerichours +// 13.5.9 FormatNumericHours ( durationFormat, hoursValue, signDisplayed ), https://tc39.es/ecma402/#sec-formatnumerichours Vector format_numeric_hours(VM& vm, DurationFormat const& duration_format, MathematicalValue const& hours_value, bool sign_displayed) { auto& realm = *vm.current_realm(); @@ -412,7 +412,7 @@ Vector format_numeric_hours(VM& vm, DurationFormat const& du return result; } -// 13.1.10 FormatNumericMinutes ( durationFormat, minutesValue, hoursDisplayed, signDisplayed ), https://tc39.es/ecma402/#sec-formatnumericminutes +// 13.5.10 FormatNumericMinutes ( durationFormat, minutesValue, hoursDisplayed, signDisplayed ), https://tc39.es/ecma402/#sec-formatnumericminutes Vector format_numeric_minutes(VM& vm, DurationFormat const& duration_format, MathematicalValue const& minutes_value, bool hours_displayed, bool sign_displayed) { auto& realm = *vm.current_realm(); @@ -477,7 +477,7 @@ Vector format_numeric_minutes(VM& vm, DurationFormat const& return result; } -// 13.1.11 FormatNumericSeconds ( durationFormat, secondsValue, minutesDisplayed, signDisplayed ), https://tc39.es/ecma402/#sec-formatnumericseconds +// 13.5.11 FormatNumericSeconds ( durationFormat, secondsValue, minutesDisplayed, signDisplayed ), https://tc39.es/ecma402/#sec-formatnumericseconds Vector format_numeric_seconds(VM& vm, DurationFormat const& duration_format, MathematicalValue const& seconds_value, bool minutes_displayed, bool sign_displayed) { auto& realm = *vm.current_realm(); @@ -571,7 +571,7 @@ Vector format_numeric_seconds(VM& vm, DurationFormat const& return result; } -// 13.1.12 FormatNumericUnits ( durationFormat, duration, firstNumericUnit, signDisplayed ), https://tc39.es/ecma402/#sec-formatnumericunits +// 13.5.12 FormatNumericUnits ( durationFormat, duration, firstNumericUnit, signDisplayed ), https://tc39.es/ecma402/#sec-formatnumericunits // 15.9.7 FormatNumericUnits ( durationFormat, duration, firstNumericUnit, signDisplayed ), https://tc39.es/proposal-temporal/#sec-formatnumericunits Vector format_numeric_units(VM& vm, DurationFormat const& duration_format, Temporal::Duration const& duration, DurationFormat::Unit first_numeric_unit, bool sign_displayed) { @@ -699,7 +699,7 @@ Vector format_numeric_units(VM& vm, DurationFormat const& du return numeric_parts_list; } -// 13.1.13 ListFormatParts ( durationFormat, partitionedPartsList ), https://tc39.es/ecma402/#sec-listformatparts +// 13.5.13 ListFormatParts ( durationFormat, partitionedPartsList ), https://tc39.es/ecma402/#sec-listformatparts Vector list_format_parts(VM& vm, DurationFormat const& duration_format, Vector>& partitioned_parts_list) { auto& realm = *vm.current_realm(); @@ -790,7 +790,7 @@ Vector list_format_parts(VM& vm, DurationFormat const& durat return flattened_parts_list; } -// 13.1.14 PartitionDurationFormatPattern ( durationFormat, duration ), https://tc39.es/ecma402/#sec-partitiondurationformatpattern +// 13.5.14 PartitionDurationFormatPattern ( durationFormat, duration ), https://tc39.es/ecma402/#sec-partitiondurationformatpattern // 15.9.8 PartitionDurationFormatPattern ( durationFormat, duration ), https://tc39.es/proposal-temporal/#sec-formatnumericunits Vector partition_duration_format_pattern(VM& vm, DurationFormat const& duration_format, Temporal::Duration const& duration) { @@ -805,7 +805,7 @@ Vector partition_duration_format_pattern(VM& vm, DurationFor // 3. Let numericUnitFound be false. auto numeric_unit_found = false; - // 4. While numericUnitFound is false, repeat for each row in Table 21 in table order, except the header row: + // 4. While numericUnitFound is false, repeat for each row in Table 23 in table order, except the header row: for (size_t i = 0; !numeric_unit_found && i < duration_instances_components.size(); ++i) { auto const& duration_instances_component = duration_instances_components[i]; diff --git a/Libraries/LibJS/Runtime/Intl/DurationFormat.h b/Libraries/LibJS/Runtime/Intl/DurationFormat.h index a7dec2c40b2..3445ede3429 100644 --- a/Libraries/LibJS/Runtime/Intl/DurationFormat.h +++ b/Libraries/LibJS/Runtime/Intl/DurationFormat.h @@ -68,7 +68,7 @@ public: static constexpr auto relevant_extension_keys() { - // 13.3.3 Internal slots, https://tc39.es/ecma402/#sec-Intl.DurationFormat-internal-slots + // 13.2.3 Internal slots, https://tc39.es/ecma402/#sec-Intl.DurationFormat-internal-slots // The value of the [[RelevantExtensionKeys]] internal slot is « "nu" ». return AK::Array { "nu"sv }; } @@ -218,8 +218,8 @@ struct DurationInstanceComponent { DurationFormat::ValueStyle digital_default; }; -// Table 21: DurationFormat instance internal slots and properties relevant to PartitionDurationFormatPattern, https://tc39.es/ecma402/#table-partition-duration-format-pattern -// Table 22: Internal slots and property names of DurationFormat instances relevant to Intl.DurationFormat constructor, https://tc39.es/ecma402/#table-durationformat +// Table 20: Internal slots and property names of DurationFormat instances relevant to Intl.DurationFormat constructor, https://tc39.es/ecma402/#table-durationformat +// Table 23: DurationFormat instance internal slots and properties relevant to PartitionDurationFormatPattern, https://tc39.es/ecma402/#table-partition-duration-format-pattern static constexpr auto date_values = AK::Array { "long"sv, "short"sv, "narrow"sv }; static constexpr auto time_values = AK::Array { "long"sv, "short"sv, "narrow"sv, "numeric"sv, "2-digit"sv }; static constexpr auto sub_second_values = AK::Array { "long"sv, "short"sv, "narrow"sv, "numeric"sv }; diff --git a/Libraries/LibJS/Runtime/Intl/DurationFormatConstructor.cpp b/Libraries/LibJS/Runtime/Intl/DurationFormatConstructor.cpp index eb1ead39bcd..8f7724e9529 100644 --- a/Libraries/LibJS/Runtime/Intl/DurationFormatConstructor.cpp +++ b/Libraries/LibJS/Runtime/Intl/DurationFormatConstructor.cpp @@ -18,7 +18,7 @@ namespace JS::Intl { GC_DEFINE_ALLOCATOR(DurationFormatConstructor); -// 13.2 The Intl.DurationFormat Constructor, https://tc39.es/ecma402/#sec-intl-durationformat-constructor +// 13.1 The Intl.DurationFormat Constructor, https://tc39.es/ecma402/#sec-intl-durationformat-constructor DurationFormatConstructor::DurationFormatConstructor(Realm& realm) : NativeFunction(realm.vm().names.DurationFormat.as_string(), realm.intrinsics().function_prototype()) { @@ -38,14 +38,14 @@ void DurationFormatConstructor::initialize(Realm& realm) define_native_function(realm, vm.names.supportedLocalesOf, supported_locales_of, 1, attr); } -// 13.2.1 Intl.DurationFormat ( [ locales [ , options ] ] ), https://tc39.es/ecma402/#sec-Intl.DurationFormat +// 13.1.1 Intl.DurationFormat ( [ locales [ , options ] ] ), https://tc39.es/ecma402/#sec-Intl.DurationFormat ThrowCompletionOr DurationFormatConstructor::call() { // 1. If NewTarget is undefined, throw a TypeError exception. return vm().throw_completion(ErrorType::ConstructorWithoutNew, "Intl.DurationFormat"); } -// 13.2.1 Intl.DurationFormat ( [ locales [ , options ] ] ), https://tc39.es/ecma402/#sec-Intl.DurationFormat +// 13.1.1 Intl.DurationFormat ( [ locales [ , options ] ] ), https://tc39.es/ecma402/#sec-Intl.DurationFormat ThrowCompletionOr> DurationFormatConstructor::construct(FunctionObject& new_target) { auto& vm = this->vm(); @@ -110,7 +110,7 @@ ThrowCompletionOr> DurationFormatConstructor::construct(Function // 18. Let prevStyle be the empty String. Optional previous_style; - // 19. For each row of Table 22, except the header row, in table order, do + // 19. 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 styleSlot be the Style Slot value of the current row. auto style_slot = duration_instances_component.set_style_slot; @@ -150,7 +150,7 @@ ThrowCompletionOr> DurationFormatConstructor::construct(Function return duration_format; } -// 13.3.2 Intl.DurationFormat.supportedLocalesOf ( locales [ , options ] ), https://tc39.es/ecma402/#sec-Intl.DurationFormat.supportedLocalesOf +// 13.2.2 Intl.DurationFormat.supportedLocalesOf ( locales [ , options ] ), https://tc39.es/ecma402/#sec-Intl.DurationFormat.supportedLocalesOf JS_DEFINE_NATIVE_FUNCTION(DurationFormatConstructor::supported_locales_of) { auto locales = vm.argument(0); diff --git a/Libraries/LibJS/Runtime/Intl/DurationFormatPrototype.cpp b/Libraries/LibJS/Runtime/Intl/DurationFormatPrototype.cpp index e8e364a308d..c2278c70aaf 100644 --- a/Libraries/LibJS/Runtime/Intl/DurationFormatPrototype.cpp +++ b/Libraries/LibJS/Runtime/Intl/DurationFormatPrototype.cpp @@ -16,7 +16,7 @@ namespace JS::Intl { GC_DEFINE_ALLOCATOR(DurationFormatPrototype); -// 13.4 Properties of the Intl.DurationFormat Prototype Object, https://tc39.es/ecma402/#sec-properties-of-intl-durationformat-prototype-object +// 13.3 Properties of the Intl.DurationFormat Prototype Object, https://tc39.es/ecma402/#sec-properties-of-intl-durationformat-prototype-object DurationFormatPrototype::DurationFormatPrototype(Realm& realm) : PrototypeObject(realm.intrinsics().object_prototype()) { @@ -28,88 +28,16 @@ void DurationFormatPrototype::initialize(Realm& realm) auto& vm = this->vm(); - // 13.4.2 Intl.DurationFormat.prototype [ @@toStringTag ], https://tc39.es/ecma402/#sec-Intl.DurationFormat.prototype-@@tostringtag + // 13.3.5 Intl.DurationFormat.prototype [ %Symbol.toStringTag% ], https://tc39.es/ecma402/#sec-Intl.DurationFormat.prototype-%symbol.tostringtag% define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Intl.DurationFormat"_string), Attribute::Configurable); u8 attr = Attribute::Writable | Attribute::Configurable; + define_native_function(realm, vm.names.resolvedOptions, resolved_options, 0, attr); define_native_function(realm, vm.names.format, format, 1, attr); define_native_function(realm, vm.names.formatToParts, format_to_parts, 1, attr); - define_native_function(realm, vm.names.resolvedOptions, resolved_options, 0, attr); } -// 13.4.3 Intl.DurationFormat.prototype.format ( duration ), https://tc39.es/ecma402/#sec-Intl.DurationFormat.prototype.format -// 15.10.1 Intl.DurationFormat.prototype.format ( durationLike ), https://tc39.es/proposal-temporal/#sec-Intl.DurationFormat.prototype.format -JS_DEFINE_NATIVE_FUNCTION(DurationFormatPrototype::format) -{ - // 1. Let df be this value. - // 2. Perform ? RequireInternalSlot(df, [[InitializedDurationFormat]]). - auto duration_format = TRY(typed_this_object(vm)); - - // 3. Let duration be ? ToTemporalDuration(durationLike). - auto duration = TRY(Temporal::to_temporal_duration(vm, vm.argument(0))); - - // 4. Let parts be PartitionDurationFormatPattern(df, duration). - auto parts = partition_duration_format_pattern(vm, duration_format, duration); - - // 5. Let result be a new empty String. - StringBuilder result; - - // 6. For each Record { [[Type]], [[Value]], [[Unit]] } part in parts, do - for (auto const& part : parts) { - // a. Set result to the string-concatenation of result and part.[[Value]]. - result.append(part.value); - } - - // 7. Return result. - return PrimitiveString::create(vm, MUST(result.to_string())); -} - -// 13.4.4 Intl.DurationFormat.prototype.formatToParts ( duration ), https://tc39.es/ecma402/#sec-Intl.DurationFormat.prototype.formatToParts -// 15.10.2 Intl.DurationFormat.prototype.formatToParts ( durationLike ), https://tc39.es/proposal-temporal/#sec-Intl.DurationFormat.prototype.formatToParts -JS_DEFINE_NATIVE_FUNCTION(DurationFormatPrototype::format_to_parts) -{ - auto& realm = *vm.current_realm(); - - // 1. Let df be this value. - // 2. Perform ? RequireInternalSlot(df, [[InitializedDurationFormat]]). - auto duration_format = TRY(typed_this_object(vm)); - - // 3. Let duration be ? ToTemporalDuration(durationLike). - auto duration = TRY(Temporal::to_temporal_duration(vm, vm.argument(0))); - - // 4. Let parts be PartitionDurationFormatPattern(df, duration). - auto parts = partition_duration_format_pattern(vm, duration_format, duration); - - // 5. Let result be ! ArrayCreate(0). - auto result = MUST(Array::create(realm, 0)); - - // 6. Let n be 0. - // 7. For each Record { [[Type]], [[Value]], [[Unit]] } part in parts, do - for (auto [n, part] : enumerate(parts)) { - // a. Let obj be OrdinaryObjectCreate(%Object.prototype%). - auto object = Object::create(realm, realm.intrinsics().object_prototype()); - - // b. Perform ! CreateDataPropertyOrThrow(obj, "type", part.[[Type]]). - MUST(object->create_data_property_or_throw(vm.names.type, PrimitiveString::create(vm, part.type))); - - // c. Perform ! CreateDataPropertyOrThrow(obj, "value", part.[[Value]]). - MUST(object->create_data_property_or_throw(vm.names.value, PrimitiveString::create(vm, move(part.value)))); - - // d. If part.[[Unit]] is not empty, perform ! CreateDataPropertyOrThrow(obj, "unit", part.[[Unit]]). - if (!part.unit.is_empty()) - MUST(object->create_data_property_or_throw(vm.names.unit, PrimitiveString::create(vm, part.unit))); - - // e. Perform ! CreateDataPropertyOrThrow(result, ! ToString(n), obj). - MUST(result->create_data_property_or_throw(n, object)); - - // f. Set n to n + 1. - } - - // 8. Return result. - return result; -} - -// 13.4.5 Intl.DurationFormat.prototype.resolvedOptions ( ), https://tc39.es/ecma402/#sec-Intl.DurationFormat.prototype.resolvedOptions +// 13.3.2 Intl.DurationFormat.prototype.resolvedOptions ( ), https://tc39.es/ecma402/#sec-Intl.DurationFormat.prototype.resolvedOptions JS_DEFINE_NATIVE_FUNCTION(DurationFormatPrototype::resolved_options) { auto& realm = *vm.current_realm(); @@ -121,7 +49,7 @@ JS_DEFINE_NATIVE_FUNCTION(DurationFormatPrototype::resolved_options) // 3. Let options be OrdinaryObjectCreate(%Object.prototype%). auto options = Object::create(realm, realm.intrinsics().object_prototype()); - // 4. For each row of Table 23, except the header row, in table order, do + // 4. For each row of Table 21, except the header row, in table order, do auto create_option = [&](PropertyKey const& property, StringView value) { // a. Let p be the Property value of the current row. // b. Let v be the value of df's internal slot whose name is the Internal Slot value of the current row. @@ -174,4 +102,76 @@ JS_DEFINE_NATIVE_FUNCTION(DurationFormatPrototype::resolved_options) return options; } +// 13.3.3 Intl.DurationFormat.prototype.format ( duration ), https://tc39.es/ecma402/#sec-Intl.DurationFormat.prototype.format +// 15.10.1 Intl.DurationFormat.prototype.format ( durationLike ), https://tc39.es/proposal-temporal/#sec-Intl.DurationFormat.prototype.format +JS_DEFINE_NATIVE_FUNCTION(DurationFormatPrototype::format) +{ + // 1. Let df be this value. + // 2. Perform ? RequireInternalSlot(df, [[InitializedDurationFormat]]). + auto duration_format = TRY(typed_this_object(vm)); + + // 3. Let duration be ? ToTemporalDuration(durationLike). + auto duration = TRY(Temporal::to_temporal_duration(vm, vm.argument(0))); + + // 4. Let parts be PartitionDurationFormatPattern(df, duration). + auto parts = partition_duration_format_pattern(vm, duration_format, duration); + + // 5. Let result be a new empty String. + StringBuilder result; + + // 6. For each Record { [[Type]], [[Value]], [[Unit]] } part in parts, do + for (auto const& part : parts) { + // a. Set result to the string-concatenation of result and part.[[Value]]. + result.append(part.value); + } + + // 7. Return result. + return PrimitiveString::create(vm, MUST(result.to_string())); +} + +// 13.3.4 Intl.DurationFormat.prototype.formatToParts ( duration ), https://tc39.es/ecma402/#sec-Intl.DurationFormat.prototype.formatToParts +// 15.10.2 Intl.DurationFormat.prototype.formatToParts ( durationLike ), https://tc39.es/proposal-temporal/#sec-Intl.DurationFormat.prototype.formatToParts +JS_DEFINE_NATIVE_FUNCTION(DurationFormatPrototype::format_to_parts) +{ + auto& realm = *vm.current_realm(); + + // 1. Let df be this value. + // 2. Perform ? RequireInternalSlot(df, [[InitializedDurationFormat]]). + auto duration_format = TRY(typed_this_object(vm)); + + // 3. Let duration be ? ToTemporalDuration(durationLike). + auto duration = TRY(Temporal::to_temporal_duration(vm, vm.argument(0))); + + // 4. Let parts be PartitionDurationFormatPattern(df, duration). + auto parts = partition_duration_format_pattern(vm, duration_format, duration); + + // 5. Let result be ! ArrayCreate(0). + auto result = MUST(Array::create(realm, 0)); + + // 6. Let n be 0. + // 7. For each Record { [[Type]], [[Value]], [[Unit]] } part in parts, do + for (auto [n, part] : enumerate(parts)) { + // a. Let obj be OrdinaryObjectCreate(%Object.prototype%). + auto object = Object::create(realm, realm.intrinsics().object_prototype()); + + // b. Perform ! CreateDataPropertyOrThrow(obj, "type", part.[[Type]]). + MUST(object->create_data_property_or_throw(vm.names.type, PrimitiveString::create(vm, part.type))); + + // c. Perform ! CreateDataPropertyOrThrow(obj, "value", part.[[Value]]). + MUST(object->create_data_property_or_throw(vm.names.value, PrimitiveString::create(vm, move(part.value)))); + + // d. If part.[[Unit]] is not empty, perform ! CreateDataPropertyOrThrow(obj, "unit", part.[[Unit]]). + if (!part.unit.is_empty()) + MUST(object->create_data_property_or_throw(vm.names.unit, PrimitiveString::create(vm, part.unit))); + + // e. Perform ! CreateDataPropertyOrThrow(result, ! ToString(n), obj). + MUST(result->create_data_property_or_throw(n, object)); + + // f. Set n to n + 1. + } + + // 8. Return result. + return result; +} + } diff --git a/Libraries/LibJS/Runtime/Intl/DurationFormatPrototype.h b/Libraries/LibJS/Runtime/Intl/DurationFormatPrototype.h index 48247af5ecd..81f5d2d077c 100644 --- a/Libraries/LibJS/Runtime/Intl/DurationFormatPrototype.h +++ b/Libraries/LibJS/Runtime/Intl/DurationFormatPrototype.h @@ -22,9 +22,9 @@ public: private: explicit DurationFormatPrototype(Realm&); + JS_DECLARE_NATIVE_FUNCTION(resolved_options); JS_DECLARE_NATIVE_FUNCTION(format); JS_DECLARE_NATIVE_FUNCTION(format_to_parts); - JS_DECLARE_NATIVE_FUNCTION(resolved_options); }; }