From 227379a1daa5e63f7cc51f5a6360ec93049279f4 Mon Sep 17 00:00:00 2001 From: Linus Groh Date: Thu, 26 Jan 2023 14:37:52 +0000 Subject: [PATCH] LibJS: Port prepare_temporal_fields() and calendar_fields() to String --- .../Runtime/Temporal/AbstractOperations.cpp | 9 ++--- .../Runtime/Temporal/AbstractOperations.h | 2 +- .../LibJS/Runtime/Temporal/Calendar.cpp | 34 ++++++++++++++----- .../LibJS/Runtime/Temporal/Calendar.h | 4 +-- .../LibJS/Runtime/Temporal/PlainTime.cpp | 9 ++++- .../LibJS/Runtime/Temporal/ZonedDateTime.cpp | 4 +-- .../Temporal/ZonedDateTimePrototype.cpp | 4 +-- 7 files changed, 45 insertions(+), 21 deletions(-) diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp index 8482aacbe6..2a93a47c23 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.cpp @@ -1740,7 +1740,7 @@ ThrowCompletionOr to_positive_integer_with_truncation(VM& vm, Value argu } // 13.43 PrepareTemporalFields ( fields, fieldNames, requiredFields ), https://tc39.es/proposal-temporal/#sec-temporal-preparetemporalfields -ThrowCompletionOr prepare_temporal_fields(VM& vm, Object const& fields, Vector const& field_names, Variant> const& required_fields) +ThrowCompletionOr prepare_temporal_fields(VM& vm, Object const& fields, Vector const& field_names, Variant> const& required_fields) { auto& realm = *vm.current_realm(); @@ -1754,7 +1754,7 @@ ThrowCompletionOr prepare_temporal_fields(VM& vm, Object const& fields, // 3. For each value property of fieldNames, do for (auto& property : field_names) { // a. Let value be ? Get(fields, property). - auto value = TRY(fields.get(property)); + auto value = TRY(fields.get(property.to_deprecated_string())); // b. If value is not undefined, then if (!value.is_undefined()) { @@ -1783,7 +1783,7 @@ ThrowCompletionOr prepare_temporal_fields(VM& vm, Object const& fields, } // iii. Perform ! CreateDataPropertyOrThrow(result, property, value). - MUST(result->create_data_property_or_throw(property, value)); + MUST(result->create_data_property_or_throw(property.to_deprecated_string(), value)); } // c. Else if requiredFields is a List, then else if (required_fields.has>()) { @@ -1800,13 +1800,14 @@ ThrowCompletionOr prepare_temporal_fields(VM& vm, Object const& fields, } // iii. Perform ! CreateDataPropertyOrThrow(result, property, value). - MUST(result->create_data_property_or_throw(property, value)); + MUST(result->create_data_property_or_throw(property.to_deprecated_string(), value)); } } // 4. If requiredFields is partial and any is false, then if (required_fields.has() && !any) { // a. Throw a TypeError exception. + // FIXME: Add & use String::join() return vm.throw_completion(ErrorType::TemporalObjectMustHaveOneOf, DeprecatedString::join(", "sv, field_names)); } diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.h b/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.h index 4a439844d3..f64a544fc1 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.h +++ b/Userland/Libraries/LibJS/Runtime/Temporal/AbstractOperations.h @@ -175,7 +175,7 @@ ThrowCompletionOr parse_temporal_time_string(VM&, StringView iso_s ThrowCompletionOr parse_temporal_time_zone_string(VM&, StringView iso_string); ThrowCompletionOr parse_temporal_year_month_string(VM&, StringView iso_string); ThrowCompletionOr to_positive_integer_with_truncation(VM&, Value argument); -ThrowCompletionOr prepare_temporal_fields(VM&, Object const& fields, Vector const& field_names, Variant> const& required_fields); +ThrowCompletionOr prepare_temporal_fields(VM&, Object const& fields, Vector const& field_names, Variant> const& required_fields); ThrowCompletionOr get_difference_settings(VM&, DifferenceOperation, Value options_value, UnitGroup unit_group, Vector const& disallowed_units, TemporalUnitDefault const& fallback_smallest_unit, StringView smallest_largest_default_unit); template diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp index a2d38d25a4..41e04c6c99 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2021, Idan Horowitz - * Copyright (c) 2021-2022, Linus Groh + * Copyright (c) 2021-2023, Linus Groh * * SPDX-License-Identifier: BSD-2-Clause */ @@ -103,7 +103,7 @@ Calendar* get_iso8601_calendar(VM& vm) } // 12.2.4 CalendarFields ( calendar, fieldNames ), https://tc39.es/proposal-temporal/#sec-temporal-calendarfields -ThrowCompletionOr> calendar_fields(VM& vm, Object& calendar, Vector const& field_names) +ThrowCompletionOr> calendar_fields(VM& vm, Object& calendar, Vector const& field_names) { auto& realm = *vm.current_realm(); @@ -112,9 +112,10 @@ ThrowCompletionOr> calendar_fields(VM& vm, Object& cale // 2. If fields is undefined, return fieldNames. if (!fields) { - Vector result; + Vector result; + TRY_OR_THROW_OOM(vm, result.try_ensure_capacity(field_names.size())); for (auto& value : field_names) - result.append(value); + result.unchecked_append(TRY_OR_THROW_OOM(vm, String::from_utf8(value))); return result; } @@ -124,9 +125,10 @@ ThrowCompletionOr> calendar_fields(VM& vm, Object& cale // 4. Return ? IterableToListOfType(fieldsArray, « String »). auto list = TRY(iterable_to_list_of_type(vm, fields_array, { OptionType::String })); - Vector result; + Vector result; + TRY_OR_THROW_OOM(vm, result.try_ensure_capacity(list.size())); for (auto& value : list) - result.append(TRY(value.as_string().deprecated_string())); + result.unchecked_append(TRY(value.as_string().utf8_string())); return result; } @@ -818,7 +820,12 @@ ThrowCompletionOr iso_date_from_fields(VM& vm, Object const& fiel // 1. Assert: Type(fields) is Object. // 2. Set fields to ? PrepareTemporalFields(fields, « "day", "month", "monthCode", "year" », « "year", "day" »). - auto* prepared_fields = TRY(prepare_temporal_fields(vm, fields, { "day", "month", "monthCode", "year" }, Vector { "year"sv, "day"sv })); + auto* prepared_fields = TRY(prepare_temporal_fields(vm, fields, + { String::from_utf8_short_string("day"sv), + TRY_OR_THROW_OOM(vm, String::from_utf8("month"sv)), + TRY_OR_THROW_OOM(vm, String::from_utf8("monthCode"sv)), + TRY_OR_THROW_OOM(vm, String::from_utf8("year"sv)) }, + Vector { "year"sv, "day"sv })); // 3. Let overflow be ? ToTemporalOverflow(options). auto overflow = TRY(to_temporal_overflow(vm, &options)); @@ -848,7 +855,11 @@ ThrowCompletionOr iso_year_month_from_fields(VM& vm, Object const& // 1. Assert: Type(fields) is Object. // 2. Set fields to ? PrepareTemporalFields(fields, « "month", "monthCode", "year" », « "year" »). - auto* prepared_fields = TRY(prepare_temporal_fields(vm, fields, { "month"sv, "monthCode"sv, "year"sv }, Vector { "year"sv })); + auto* prepared_fields = TRY(prepare_temporal_fields(vm, fields, + { TRY_OR_THROW_OOM(vm, String::from_utf8("month"sv)), + TRY_OR_THROW_OOM(vm, String::from_utf8("monthCode"sv)), + TRY_OR_THROW_OOM(vm, String::from_utf8("year"sv)) }, + Vector { "year"sv })); // 3. Let overflow be ? ToTemporalOverflow(options). auto overflow = TRY(to_temporal_overflow(vm, &options)); @@ -875,7 +886,12 @@ ThrowCompletionOr iso_month_day_from_fields(VM& vm, Object const& f // 1. Assert: Type(fields) is Object. // 2. Set fields to ? PrepareTemporalFields(fields, « "day", "month", "monthCode", "year" », « "day" »). - auto* prepared_fields = TRY(prepare_temporal_fields(vm, fields, { "day"sv, "month"sv, "monthCode"sv, "year"sv }, Vector { "day"sv })); + auto* prepared_fields = TRY(prepare_temporal_fields(vm, fields, + { String::from_utf8_short_string("day"sv), + TRY_OR_THROW_OOM(vm, String::from_utf8("month"sv)), + TRY_OR_THROW_OOM(vm, String::from_utf8("monthCode"sv)), + TRY_OR_THROW_OOM(vm, String::from_utf8("year"sv)) }, + Vector { "day"sv })); // 3. Let overflow be ? ToTemporalOverflow(options). auto overflow = TRY(to_temporal_overflow(vm, &options)); diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.h b/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.h index 0aab6c8d9b..5377fb6a5e 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.h +++ b/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2021, Idan Horowitz - * Copyright (c) 2021-2022, Linus Groh + * Copyright (c) 2021-2023, Linus Groh * * SPDX-License-Identifier: BSD-2-Clause */ @@ -42,7 +42,7 @@ Span available_calendars(); ThrowCompletionOr create_temporal_calendar(VM&, DeprecatedString const& identifier, FunctionObject const* new_target = nullptr); ThrowCompletionOr get_builtin_calendar(VM&, DeprecatedString const& identifier); Calendar* get_iso8601_calendar(VM&); -ThrowCompletionOr> calendar_fields(VM&, Object& calendar, Vector const& field_names); +ThrowCompletionOr> calendar_fields(VM&, Object& calendar, Vector const& field_names); ThrowCompletionOr calendar_merge_fields(VM&, Object& calendar, Object& fields, Object& additional_fields); ThrowCompletionOr calendar_date_add(VM&, Object& calendar, Value date, Duration&, Object* options = nullptr, FunctionObject* date_add = nullptr); ThrowCompletionOr calendar_date_until(VM&, Object& calendar, Value one, Value two, Object& options, FunctionObject* date_until = nullptr); diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/PlainTime.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/PlainTime.cpp index 5007e374c9..97b9564957 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/PlainTime.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/PlainTime.cpp @@ -343,7 +343,14 @@ ThrowCompletionOr to_temporal_time_record(VM& vm, Object // 1. If completeness is not present, set completeness to complete. // 2. Let partial be ? PrepareTemporalFields(temporalTimeLike, « "hour", "microsecond", "millisecond", "minute", "nanosecond", "second" », partial). - auto* partial = TRY(prepare_temporal_fields(vm, temporal_time_like, { "hour"sv, "microsecond"sv, "millisecond"sv, "minute"sv, "nanosecond"sv, "second"sv }, PrepareTemporalFieldsPartial {})); + auto* partial = TRY(prepare_temporal_fields(vm, temporal_time_like, + { TRY_OR_THROW_OOM(vm, String::from_utf8("hour"sv)), + TRY_OR_THROW_OOM(vm, String::from_utf8("microsecond"sv)), + TRY_OR_THROW_OOM(vm, String::from_utf8("millisecond"sv)), + TRY_OR_THROW_OOM(vm, String::from_utf8("minute"sv)), + TRY_OR_THROW_OOM(vm, String::from_utf8("nanosecond"sv)), + TRY_OR_THROW_OOM(vm, String::from_utf8("second"sv)) }, + PrepareTemporalFieldsPartial {})); TemporalTimeLikeRecord result; // 3. If completeness is complete, then diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTime.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTime.cpp index f7a6c2c6b8..330029dcc7 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTime.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTime.cpp @@ -150,10 +150,10 @@ ThrowCompletionOr to_temporal_zoned_date_time(VM& vm, Value item auto field_names = TRY(calendar_fields(vm, *calendar, { "day"sv, "hour"sv, "microsecond"sv, "millisecond"sv, "minute"sv, "month"sv, "monthCode"sv, "nanosecond"sv, "second"sv, "year"sv })); // d. Append "timeZone" to fieldNames. - field_names.append("timeZone"); + field_names.append(TRY_OR_THROW_OOM(vm, String::from_utf8("timeZone"sv))); // e. Append "offset" to fieldNames. - field_names.append("offset"); + field_names.append(TRY_OR_THROW_OOM(vm, String::from_utf8("offset"sv))); // f. Let fields be ? PrepareTemporalFields(item, fieldNames, « "timeZone" »). auto* fields = TRY(prepare_temporal_fields(vm, item_object, field_names, Vector { "timeZone"sv })); diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTimePrototype.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTimePrototype.cpp index 4cdd03e9f5..79478022e0 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTimePrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/ZonedDateTimePrototype.cpp @@ -767,7 +767,7 @@ JS_DEFINE_NATIVE_FUNCTION(ZonedDateTimePrototype::with) auto field_names = TRY(calendar_fields(vm, calendar, { "day"sv, "hour"sv, "microsecond"sv, "millisecond"sv, "minute"sv, "month"sv, "monthCode"sv, "nanosecond"sv, "second"sv, "year"sv })); // 7. Append "offset" to fieldNames. - field_names.append("offset"sv); + field_names.append(TRY_OR_THROW_OOM(vm, String::from_utf8("offset"sv))); // 8. Let partialZonedDateTime be ? PrepareTemporalFields(temporalZonedDateTimeLike, fieldNames, partial). auto* partial_zoned_date_time = TRY(prepare_temporal_fields(vm, temporal_zoned_date_time_like.as_object(), field_names, PrepareTemporalFieldsPartial {})); @@ -785,7 +785,7 @@ JS_DEFINE_NATIVE_FUNCTION(ZonedDateTimePrototype::with) auto& time_zone = zoned_date_time->time_zone(); // 13. Append "timeZone" to fieldNames. - field_names.append("timeZone"sv); + field_names.append(TRY_OR_THROW_OOM(vm, String::from_utf8("timeZone"sv))); // 14. Let fields be ? PrepareTemporalFields(zonedDateTime, fieldNames, « "timeZone", "offset" »). auto* fields = TRY(prepare_temporal_fields(vm, *zoned_date_time, field_names, Vector { "timeZone"sv, "offset"sv }));