ladybird/Libraries/LibJS/Runtime/Temporal/AbstractOperations.h
2025-06-30 10:50:36 -06:00

246 lines
8.6 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
* Copyright (c) 2021-2023, Linus Groh <linusg@serenityos.org>
* Copyright (c) 2024-2025, Tim Flynn <trflynn89@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Variant.h>
#include <LibCrypto/BigInt/SignedBigInteger.h>
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
#include <LibGC/Ptr.h>
#include <LibJS/Forward.h>
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Completion.h>
#include <LibJS/Runtime/Temporal/ISO8601.h>
#include <LibJS/Runtime/Temporal/ISORecords.h>
#include <LibJS/Runtime/VM.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <math.h>
namespace JS::Temporal {
enum class ArithmeticOperation {
Add,
Subtract,
};
enum class DateType {
Date,
MonthDay,
YearMonth,
};
enum class Direction {
Next,
Previous,
};
enum class Disambiguation {
Compatible,
Earlier,
Later,
Reject,
};
enum class DurationOperation {
Since,
Until,
};
enum class OffsetOption {
Prefer,
Use,
Ignore,
Reject,
};
enum class Overflow {
Constrain,
Reject,
};
enum class ShowCalendar {
Auto,
Always,
Never,
Critical,
};
enum class ShowOffset {
Auto,
Never,
};
enum class ShowTimeZoneName {
Auto,
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,
};
JS_API 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 UnsignedRoundingMode {
HalfEven,
HalfInfinity,
HalfZero,
Infinity,
Zero,
};
// https://tc39.es/proposal-temporal/#table-unsigned-rounding-modes
enum class Sign {
Negative,
Positive,
};
struct Auto { };
struct Unset { };
using Precision = Variant<Auto, u8>;
using RoundingIncrement = Variant<Unset, u64>;
using UnitDefault = Variant<Required, Unset, Auto, Unit>;
using UnitValue = Variant<Unset, Auto, Unit>;
struct SecondsStringPrecision {
struct Minute { };
using Precision = Variant<Minute, Auto, u8>;
Precision precision;
Unit unit;
u8 increment { 0 };
};
struct RelativeTo {
GC::Ptr<PlainDate> plain_relative_to; // [[PlainRelativeTo]]
GC::Ptr<ZonedDateTime> zoned_relative_to; // [[ZonedRelativeTo]]
};
struct DifferenceSettings {
Unit smallest_unit;
Unit largest_unit;
RoundingMode rounding_mode;
u64 rounding_increment { 0 };
};
JS_API double iso_date_to_epoch_days(double year, double month, double date);
JS_API double epoch_days_to_epoch_ms(double day, double time);
JS_API ThrowCompletionOr<void> check_iso_days_range(VM&, ISODate);
JS_API ThrowCompletionOr<Overflow> get_temporal_overflow_option(VM&, Object const& options);
JS_API ThrowCompletionOr<Disambiguation> get_temporal_disambiguation_option(VM&, Object const& options);
JS_API RoundingMode negate_rounding_mode(RoundingMode);
JS_API ThrowCompletionOr<OffsetOption> get_temporal_offset_option(VM&, Object const& options, OffsetOption fallback);
JS_API ThrowCompletionOr<ShowTimeZoneName> get_temporal_show_time_zone_name_option(VM&, Object const& options);
JS_API ThrowCompletionOr<ShowOffset> get_temporal_show_offset_option(VM&, Object const& options);
JS_API ThrowCompletionOr<ShowCalendar> get_temporal_show_calendar_name_option(VM&, Object const& options);
JS_API ThrowCompletionOr<Direction> get_direction_option(VM&, Object const& options);
JS_API ThrowCompletionOr<void> validate_temporal_rounding_increment(VM&, u64 increment, u64 dividend, bool inclusive);
JS_API ThrowCompletionOr<Precision> get_temporal_fractional_second_digits_option(VM&, Object const& options);
JS_API SecondsStringPrecision to_seconds_string_precision_record(UnitValue, Precision);
JS_API ThrowCompletionOr<UnitValue> get_temporal_unit_valued_option(VM&, Object const& options, PropertyKey const&, UnitGroup, UnitDefault const&, ReadonlySpan<UnitValue> extra_values = {});
JS_API ThrowCompletionOr<RelativeTo> get_temporal_relative_to_option(VM&, Object const& options);
JS_API Unit larger_of_two_temporal_units(Unit, Unit);
JS_API bool is_calendar_unit(Unit);
JS_API UnitCategory temporal_unit_category(Unit);
JS_API RoundingIncrement maximum_temporal_duration_rounding_increment(Unit);
JS_API Crypto::UnsignedBigInteger const& temporal_unit_length_in_nanoseconds(Unit);
JS_API ThrowCompletionOr<bool> is_partial_temporal_object(VM&, Value);
JS_API String format_fractional_seconds(u64, Precision);
JS_API String format_time_string(u8 hour, u8 minute, u8 second, u64 sub_second_nanoseconds, SecondsStringPrecision::Precision, Optional<TimeStyle> = {});
JS_API UnsignedRoundingMode get_unsigned_rounding_mode(RoundingMode, Sign);
JS_API double apply_unsigned_rounding_mode(double, double r1, double r2, UnsignedRoundingMode);
JS_API Crypto::SignedBigInteger apply_unsigned_rounding_mode(Crypto::SignedDivisionResult const&, Crypto::SignedBigInteger r1, Crypto::SignedBigInteger r2, UnsignedRoundingMode, Crypto::UnsignedBigInteger const& increment);
JS_API double round_number_to_increment(double, u64 increment, RoundingMode);
JS_API Crypto::SignedBigInteger round_number_to_increment(Crypto::SignedBigInteger const&, Crypto::UnsignedBigInteger const& increment, RoundingMode);
JS_API Crypto::SignedBigInteger round_number_to_increment_as_if_positive(Crypto::SignedBigInteger const&, Crypto::UnsignedBigInteger const& increment, RoundingMode);
JS_API ThrowCompletionOr<ParsedISODateTime> parse_iso_date_time(VM&, StringView iso_string, ReadonlySpan<Production> allowed_formats);
JS_API ThrowCompletionOr<String> parse_temporal_calendar_string(VM&, String const&);
JS_API ThrowCompletionOr<GC::Ref<Duration>> parse_temporal_duration_string(VM&, StringView iso_string);
JS_API ThrowCompletionOr<TimeZone> parse_temporal_time_zone_string(VM&, StringView time_zone_string);
JS_API ThrowCompletionOr<String> to_month_code(VM&, Value argument);
JS_API ThrowCompletionOr<String> to_offset_string(VM&, Value argument);
JS_API CalendarFields iso_date_to_fields(StringView calendar, ISODate, DateType);
JS_API ThrowCompletionOr<DifferenceSettings> get_difference_settings(VM&, DurationOperation, Object const& options, UnitGroup, ReadonlySpan<Unit> disallowed_units, Unit fallback_smallest_unit, Unit smallest_largest_default_unit);
// 13.38 ToIntegerWithTruncation ( argument ), https://tc39.es/proposal-temporal/#sec-tointegerwithtruncation
template<typename... Args>
ThrowCompletionOr<double> 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<RangeError>(error_type, forward<Args>(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<typename... Args>
ThrowCompletionOr<double> 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<RangeError>(error_type, forward<Args>(args)...);
// 3. Return truncate((number)).
return trunc(number);
}
// 13.37 ToPositiveIntegerWithTruncation ( argument ), https://tc39.es/proposal-temporal/#sec-topositiveintegerwithtruncation
template<typename... Args>
ThrowCompletionOr<double> 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<RangeError>(error_type, args...);
// 3. Return integer.
return integer;
}
}