Prechádzať zdrojové kódy

LibJS: Leverage PrepareTemporalFields in ToTemporalTimeRecord

This is an editorial change in the Temporal spec.

See: https://github.com/tc39/proposal-temporal/commit/b5ba981
Linus Groh 3 rokov pred
rodič
commit
e96df3b7a7

+ 0 - 1
Userland/Libraries/LibJS/Runtime/ErrorTypes.h

@@ -245,7 +245,6 @@
     M(TemporalInvalidPlainDateTime, "Invalid plain date time")                                                                          \
     M(TemporalInvalidPlainMonthDay, "Invalid plain month day")                                                                          \
     M(TemporalInvalidPlainTime, "Invalid plain time")                                                                                   \
-    M(TemporalInvalidPlainTimeLikeObject, "Invalid plain time-like object")                                                             \
     M(TemporalInvalidPlainYearMonth, "Invalid plain year month")                                                                        \
     M(TemporalInvalidTime, "Invalid time")                                                                                              \
     M(TemporalInvalidTimeString, "Invalid time string '{}'")                                                                            \

+ 22 - 26
Userland/Libraries/LibJS/Runtime/Temporal/PlainTime.cpp

@@ -336,43 +336,39 @@ ThrowCompletionOr<PlainTime*> create_temporal_time(GlobalObject& global_object,
 }
 
 // 4.5.8 ToTemporalTimeRecord ( temporalTimeLike [ , completeness ] ), https://tc39.es/proposal-temporal/#sec-temporal-totemporaltimerecord
-ThrowCompletionOr<UnregulatedTemporalTime> to_temporal_time_record(GlobalObject& global_object, Object const& temporal_time_like, ToTemporalTimeRecordCompleteness completeness)
+ThrowCompletionOr<TemporalTimeLikeRecord> to_temporal_time_record(GlobalObject& global_object, Object const& temporal_time_like, ToTemporalTimeRecordCompleteness completeness)
 {
     auto& vm = global_object.vm();
 
     // 1. If completeness is not present, set completeness to complete.
 
-    // 2. Let result be the Record { [[Hour]]: undefined, [[Minute]]: undefined, [[Second]]: undefined, [[Millisecond]]: undefined, [[Microsecond]]: undefined, [[Nanosecond]]: undefined }.
-    auto result = UnregulatedTemporalTime {};
+    // 2. Let partial be ? PrepareTemporalFields(temporalTimeLike, « "hour", "microsecond", "millisecond", "minute", "nanosecond", "second" », partial).
+    auto* partial = TRY(prepare_temporal_fields(global_object, temporal_time_like, { "hour"sv, "microsecond"sv, "millisecond"sv, "minute"sv, "nanosecond"sv, "second"sv }, PrepareTemporalFieldsPartial {}));
 
-    // 3. Let any be false.
-    auto any = false;
+    // 3. Let result be a new TemporalTimeLike Record with each field set to undefined.
+    auto result = TemporalTimeLikeRecord {};
 
-    // 4. For each row of Table 3, except the header row, in table order, do
-    for (auto& [internal_slot, property] : temporal_time_like_properties<UnregulatedTemporalTime, Optional<double>>(vm)) {
-        // a. Let property be the Property value of the current row.
+    // 4. For each row of Table 4, except the header row, in table order, do
+    for (auto& [field, property_name] : temporal_time_like_record_fields<TemporalTimeLikeRecord, Optional<double>>(vm)) {
+        // a. Let field be the Field Name value of the current row.
+        // b. Let propertyName be the Property Name value of the current row.
 
-        // b. Let value be ? Get(temporalTimeLike, property).
-        auto value = TRY(temporal_time_like.get(property));
+        // c. Let valueDesc be OrdinaryGetOwnProperty(partial, propertyName).
+        auto value_descriptor = MUST(partial->Object::internal_get_own_property(property_name));
 
-        // c. If value is not undefined, set any to true.
-        if (!value.is_undefined())
-            any = true;
+        // d. If valueDesc is not undefined, then
+        if (value_descriptor.has_value()) {
+            // i. Assert: valueDesc is a data Property Descriptor.
+            VERIFY(value_descriptor->is_data_descriptor());
 
-        // d. If value is not undefined or completeness is complete, then
-        if (!value.is_undefined() || completeness == ToTemporalTimeRecordCompleteness::Complete) {
-            // i. Set value to ? ToIntegerThrowOnInfinity(value).
-            auto value_number = TRY(to_integer_throw_on_infinity(global_object, value, ErrorType::TemporalPropertyMustBeFinite));
-
-            // ii. Set result's internal slot whose name is the Internal Slot value of the current row to value.
-            result.*internal_slot = value_number;
+            // ii. Set the field of result whose name is field to valueDesc.[[Value]].
+            result.*field = value_descriptor->value->as_double();
+        }
+        // e. Else if completeness is complete, then
+        else if (completeness == ToTemporalTimeRecordCompleteness::Complete) {
+            // i. Set the field of result whose name is field to 0.
+            result.*field = 0;
         }
-    }
-
-    // 5. If any is false, then
-    if (!any) {
-        // a. Throw a TypeError exception.
-        return vm.throw_completion<TypeError>(global_object, ErrorType::TemporalInvalidPlainTimeLikeObject);
     }
 
     // 6. Return result.

+ 14 - 14
Userland/Libraries/LibJS/Runtime/Temporal/PlainTime.h

@@ -54,7 +54,7 @@ struct DaysAndTime {
     u16 nanosecond;
 };
 
-struct UnregulatedTemporalTime {
+struct TemporalTimeLikeRecord {
     Optional<double> hour;
     Optional<double> minute;
     Optional<double> second;
@@ -63,24 +63,24 @@ struct UnregulatedTemporalTime {
     Optional<double> nanosecond;
 };
 
-// Table 3: Properties of a TemporalTimeLike, https://tc39.es/proposal-temporal/#table-temporal-temporaltimelike-properties
+// Table 4: TemporalTimeLike Record Fields, https://tc39.es/proposal-temporal/#table-temporal-temporaltimelike-properties
 
 template<typename StructT, typename ValueT>
-struct TemporalTimeLikeProperty {
-    ValueT StructT::*internal_slot { nullptr };
-    PropertyKey property;
+struct TemporalTimeLikeRecordField {
+    ValueT StructT::*field_name { nullptr };
+    PropertyKey property_name;
 };
 
 template<typename StructT, typename ValueT>
-auto temporal_time_like_properties = [](VM& vm) {
-    using PropertyT = TemporalTimeLikeProperty<StructT, ValueT>;
+auto temporal_time_like_record_fields = [](VM& vm) {
+    using FieldT = TemporalTimeLikeRecordField<StructT, ValueT>;
     return AK::Array {
-        PropertyT { &StructT::hour, vm.names.hour },
-        PropertyT { &StructT::microsecond, vm.names.microsecond },
-        PropertyT { &StructT::millisecond, vm.names.millisecond },
-        PropertyT { &StructT::minute, vm.names.minute },
-        PropertyT { &StructT::nanosecond, vm.names.nanosecond },
-        PropertyT { &StructT::second, vm.names.second },
+        FieldT { &StructT::hour, vm.names.hour },
+        FieldT { &StructT::microsecond, vm.names.microsecond },
+        FieldT { &StructT::millisecond, vm.names.millisecond },
+        FieldT { &StructT::minute, vm.names.minute },
+        FieldT { &StructT::nanosecond, vm.names.nanosecond },
+        FieldT { &StructT::second, vm.names.second },
     };
 };
 
@@ -96,7 +96,7 @@ bool is_valid_time(double hour, double minute, double second, double millisecond
 DaysAndTime balance_time(double hour, double minute, double second, double millisecond, double microsecond, double nanosecond);
 TemporalTime constrain_time(double hour, double minute, double second, double millisecond, double microsecond, double nanosecond);
 ThrowCompletionOr<PlainTime*> create_temporal_time(GlobalObject&, u8 hour, u8 minute, u8 second, u16 millisecond, u16 microsecond, u16 nanosecond, FunctionObject const* new_target = nullptr);
-ThrowCompletionOr<UnregulatedTemporalTime> to_temporal_time_record(GlobalObject&, Object const& temporal_time_like, ToTemporalTimeRecordCompleteness = ToTemporalTimeRecordCompleteness::Complete);
+ThrowCompletionOr<TemporalTimeLikeRecord> to_temporal_time_record(GlobalObject&, Object const& temporal_time_like, ToTemporalTimeRecordCompleteness = ToTemporalTimeRecordCompleteness::Complete);
 String temporal_time_to_string(u8 hour, u8 minute, u8 second, u16 millisecond, u16 microsecond, u16 nanosecond, Variant<StringView, u8> const& precision);
 i8 compare_temporal_time(u8 hour1, u8 minute1, u8 second1, u16 millisecond1, u16 microsecond1, u16 nanosecond1, u8 hour2, u8 minute2, u8 second2, u16 millisecond2, u16 microsecond2, u16 nanosecond2);
 DaysAndTime add_time(u8 hour, u8 minute, u8 second, u16 millisecond, u16 microsecond, u16 nanosecond, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds);

+ 8 - 2
Userland/Libraries/LibJS/Tests/builtins/Temporal/PlainTime/PlainTime.prototype.with.js

@@ -92,10 +92,16 @@ describe("errors", () => {
     test("argument is an invalid plain time-like object", () => {
         expect(() => {
             new Temporal.PlainTime().with({});
-        }).toThrowWithMessage(TypeError, "Invalid plain time-like object");
+        }).toThrowWithMessage(
+            TypeError,
+            "Object must have at least one of the following properties: hour, microsecond, millisecond, minute, nanosecond, second"
+        );
         expect(() => {
             new Temporal.PlainTime().with({ foo: 1, bar: 2 });
-        }).toThrowWithMessage(TypeError, "Invalid plain time-like object");
+        }).toThrowWithMessage(
+            TypeError,
+            "Object must have at least one of the following properties: hour, microsecond, millisecond, minute, nanosecond, second"
+        );
     });
 
     test("error when coercing property to number", () => {

+ 8 - 2
Userland/Libraries/LibJS/Tests/builtins/Temporal/ZonedDateTime/ZonedDateTime.prototype.withPlainTime.js

@@ -118,10 +118,16 @@ describe("errors", () => {
     test("invalid plain time-like object", () => {
         expect(() => {
             new Temporal.ZonedDateTime(1n, {}).withPlainTime({});
-        }).toThrowWithMessage(TypeError, "Invalid plain time-like object");
+        }).toThrowWithMessage(
+            TypeError,
+            "Object must have at least one of the following properties: hour, microsecond, millisecond, minute, nanosecond, second"
+        );
 
         expect(() => {
             new Temporal.ZonedDateTime(1n, {}).withPlainTime({ foo: 1, bar: 2 });
-        }).toThrowWithMessage(TypeError, "Invalid plain time-like object");
+        }).toThrowWithMessage(
+            TypeError,
+            "Object must have at least one of the following properties: hour, microsecond, millisecond, minute, nanosecond, second"
+        );
     });
 });