/* * Copyright (c) 2021, Idan Horowitz * Copyright (c) 2021-2023, Linus Groh * Copyright (c) 2024, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include #include #include #include namespace JS::Temporal { enum class ArithmeticOperation { Add, Subtract, }; enum class DateType { Date, MonthDay, YearMonth, }; enum class DurationOperation { Since, Until, }; enum class Overflow { Constrain, Reject, }; enum class ShowCalendar { Auto, Always, Never, Critical, }; enum class TimeStyle { Separated, Unseparated, }; // https://tc39.es/proposal-temporal/#sec-temporal-units enum class Unit { Year, Month, Week, Day, Hour, Minute, Second, Millisecond, Microsecond, Nanosecond, }; StringView temporal_unit_to_string(Unit); // https://tc39.es/proposal-temporal/#sec-temporal-units enum class UnitCategory { Date, Time, }; // https://tc39.es/proposal-temporal/#sec-temporal-units enum class UnitGroup { Date, Time, DateTime, }; // https://tc39.es/proposal-temporal/#table-unsigned-rounding-modes enum class RoundingMode { Ceil, Floor, Expand, Trunc, HalfCeil, HalfFloor, HalfExpand, HalfTrunc, HalfEven, }; // https://tc39.es/proposal-temporal/#table-unsigned-rounding-modes enum class UnsignedRoundingMode { HalfEven, HalfInfinity, HalfZero, Infinity, Zero, }; // https://tc39.es/proposal-temporal/#table-unsigned-rounding-modes enum class Sign { Negative, Positive, }; struct Auto { }; struct Required { }; struct Unset { }; using Precision = Variant; using RoundingIncrement = Variant; using UnitDefault = Variant; using UnitValue = Variant; struct SecondsStringPrecision { struct Minute { }; using Precision = Variant; Precision precision; Unit unit; u8 increment { 0 }; }; struct RelativeTo { GC::Ptr plain_relative_to; // [[PlainRelativeTo]] GC::Ptr zoned_relative_to; // FIXME: [[ZonedRelativeTo]] }; struct DifferenceSettings { Unit smallest_unit; Unit largest_unit; RoundingMode rounding_mode; u64 rounding_increment { 0 }; }; double iso_date_to_epoch_days(double year, double month, double date); double epoch_days_to_epoch_ms(double day, double time); ThrowCompletionOr check_iso_days_range(VM&, ISODate const&); ThrowCompletionOr get_temporal_overflow_option(VM&, Object const& options); RoundingMode negate_rounding_mode(RoundingMode); ThrowCompletionOr get_temporal_show_calendar_name_option(VM&, Object const& options); ThrowCompletionOr validate_temporal_rounding_increment(VM&, u64 increment, u64 dividend, bool inclusive); ThrowCompletionOr get_temporal_fractional_second_digits_option(VM&, Object const& options); SecondsStringPrecision to_seconds_string_precision_record(UnitValue, Precision); ThrowCompletionOr get_temporal_unit_valued_option(VM&, Object const& options, PropertyKey const&, UnitGroup, UnitDefault const&, ReadonlySpan extra_values = {}); ThrowCompletionOr get_temporal_relative_to_option(VM&, Object const& options); Unit larger_of_two_temporal_units(Unit, Unit); bool is_calendar_unit(Unit); UnitCategory temporal_unit_category(Unit); RoundingIncrement maximum_temporal_duration_rounding_increment(Unit); Crypto::UnsignedBigInteger const& temporal_unit_length_in_nanoseconds(Unit); ThrowCompletionOr is_partial_temporal_object(VM&, Value); String format_fractional_seconds(u64, Precision); String format_time_string(u8 hour, u8 minute, u8 second, u64 sub_second_nanoseconds, SecondsStringPrecision::Precision, Optional = {}); UnsignedRoundingMode get_unsigned_rounding_mode(RoundingMode, Sign); double apply_unsigned_rounding_mode(double, double r1, double r2, UnsignedRoundingMode); Crypto::SignedBigInteger apply_unsigned_rounding_mode(Crypto::SignedDivisionResult const&, Crypto::SignedBigInteger const& r1, Crypto::SignedBigInteger const& r2, UnsignedRoundingMode, Crypto::UnsignedBigInteger const& increment); double round_number_to_increment(double, u64 increment, RoundingMode); Crypto::SignedBigInteger round_number_to_increment(Crypto::SignedBigInteger const&, Crypto::UnsignedBigInteger const& increment, RoundingMode); ThrowCompletionOr parse_iso_date_time(VM&, StringView iso_string, ReadonlySpan allowed_formats); ThrowCompletionOr parse_temporal_calendar_string(VM&, String const&); ThrowCompletionOr> parse_temporal_duration_string(VM&, StringView iso_string); ThrowCompletionOr parse_temporal_time_zone_string(VM& vm, StringView time_zone_string); ThrowCompletionOr to_month_code(VM&, Value argument); ThrowCompletionOr to_offset_string(VM&, Value argument); CalendarFields iso_date_to_fields(StringView calendar, ISODate const&, DateType); ThrowCompletionOr get_difference_settings(VM&, DurationOperation, Object const& options, UnitGroup, ReadonlySpan disallowed_units, Unit fallback_smallest_unit, Unit smallest_largest_default_unit); // 13.38 ToIntegerWithTruncation ( argument ), https://tc39.es/proposal-temporal/#sec-tointegerwithtruncation template ThrowCompletionOr to_integer_with_truncation(VM& vm, Value argument, ErrorType error_type, Args&&... args) { // 1. Let number be ? ToNumber(argument). auto number = TRY(argument.to_number(vm)); // 2. If number is NaN, +∞𝔽 or -∞𝔽, throw a RangeError exception. if (number.is_nan() || number.is_infinity()) return vm.throw_completion(error_type, forward(args)...); // 3. Return truncate(ℝ(number)). return trunc(number.as_double()); } // 13.38 ToIntegerWithTruncation ( argument ), https://tc39.es/proposal-temporal/#sec-tointegerwithtruncation // AD-HOC: We often need to use this AO when we have a parsed StringView. This overload allows callers to avoid creating // a PrimitiveString for the primary definition. template ThrowCompletionOr to_integer_with_truncation(VM& vm, StringView argument, ErrorType error_type, Args&&... args) { // 1. Let number be ? ToNumber(argument). auto number = string_to_number(argument); // 2. If number is NaN, +∞𝔽 or -∞𝔽, throw a RangeError exception. if (isnan(number) || isinf(number)) return vm.throw_completion(error_type, forward(args)...); // 3. Return truncate(ℝ(number)). return trunc(number); } // 13.37 ToPositiveIntegerWithTruncation ( argument ), https://tc39.es/proposal-temporal/#sec-topositiveintegerwithtruncation template ThrowCompletionOr to_positive_integer_with_truncation(VM& vm, Value argument, ErrorType error_type, Args&&... args) { // 1. Let integer be ? ToIntegerWithTruncation(argument). auto integer = TRY(to_integer_with_truncation(vm, argument, error_type, args...)); // 2. If integer ≤ 0, throw a RangeError exception. if (integer <= 0) return vm.throw_completion(error_type, args...); // 3. Return integer. return integer; } // 13.39 ToIntegerIfIntegral ( argument ), https://tc39.es/proposal-temporal/#sec-tointegerifintegral template ThrowCompletionOr to_integer_if_integral(VM& vm, Value argument, ErrorType error_type, Args&&... args) { // 1. Let number be ? ToNumber(argument). auto number = TRY(argument.to_number(vm)); // 2. If number is not an integral Number, throw a RangeError exception. if (!number.is_integral_number()) return vm.throw_completion(error_type, forward(args)...); // 3. Return ℝ(number). return number.as_double(); } // 14.2 The Year-Week Record Specification Type, https://tc39.es/proposal-temporal/#sec-year-week-record-specification-type struct YearWeek { Optional week; Optional year; }; enum class OptionType { Boolean, String, }; using OptionDefault = Variant; ThrowCompletionOr> get_options_object(VM&, Value options); ThrowCompletionOr get_option(VM&, Object const& options, PropertyKey const& property, OptionType type, ReadonlySpan values, OptionDefault const&); template ThrowCompletionOr get_option(VM& vm, Object const& options, PropertyKey const& property, OptionType type, StringView const (&values)[Size], OptionDefault const& default_) { return get_option(vm, options, property, type, ReadonlySpan { values }, default_); } ThrowCompletionOr get_rounding_mode_option(VM&, Object const& options, RoundingMode fallback); ThrowCompletionOr get_rounding_increment_option(VM&, Object const& options); Crypto::SignedBigInteger get_utc_epoch_nanoseconds(ISODateTime const&); }