AbstractOperations.h 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. /*
  2. * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
  3. * Copyright (c) 2021-2023, Linus Groh <linusg@serenityos.org>
  4. * Copyright (c) 2024, Tim Flynn <trflynn89@ladybird.org>
  5. *
  6. * SPDX-License-Identifier: BSD-2-Clause
  7. */
  8. #pragma once
  9. #include <AK/Variant.h>
  10. #include <LibCrypto/BigInt/SignedBigInteger.h>
  11. #include <LibCrypto/BigInt/UnsignedBigInteger.h>
  12. #include <LibGC/Ptr.h>
  13. #include <LibJS/Forward.h>
  14. #include <LibJS/Runtime/Completion.h>
  15. #include <LibJS/Runtime/Temporal/ISO8601.h>
  16. #include <LibJS/Runtime/Temporal/ISORecords.h>
  17. #include <LibJS/Runtime/VM.h>
  18. #include <LibJS/Runtime/ValueInlines.h>
  19. #include <math.h>
  20. namespace JS::Temporal {
  21. enum class ArithmeticOperation {
  22. Add,
  23. Subtract,
  24. };
  25. enum class DateType {
  26. Date,
  27. MonthDay,
  28. YearMonth,
  29. };
  30. enum class DurationOperation {
  31. Since,
  32. Until,
  33. };
  34. enum class Overflow {
  35. Constrain,
  36. Reject,
  37. };
  38. enum class ShowCalendar {
  39. Auto,
  40. Always,
  41. Never,
  42. Critical,
  43. };
  44. enum class TimeStyle {
  45. Separated,
  46. Unseparated,
  47. };
  48. // https://tc39.es/proposal-temporal/#sec-temporal-units
  49. enum class Unit {
  50. Year,
  51. Month,
  52. Week,
  53. Day,
  54. Hour,
  55. Minute,
  56. Second,
  57. Millisecond,
  58. Microsecond,
  59. Nanosecond,
  60. };
  61. StringView temporal_unit_to_string(Unit);
  62. // https://tc39.es/proposal-temporal/#sec-temporal-units
  63. enum class UnitCategory {
  64. Date,
  65. Time,
  66. };
  67. // https://tc39.es/proposal-temporal/#sec-temporal-units
  68. enum class UnitGroup {
  69. Date,
  70. Time,
  71. DateTime,
  72. };
  73. // https://tc39.es/proposal-temporal/#table-unsigned-rounding-modes
  74. enum class RoundingMode {
  75. Ceil,
  76. Floor,
  77. Expand,
  78. Trunc,
  79. HalfCeil,
  80. HalfFloor,
  81. HalfExpand,
  82. HalfTrunc,
  83. HalfEven,
  84. };
  85. // https://tc39.es/proposal-temporal/#table-unsigned-rounding-modes
  86. enum class UnsignedRoundingMode {
  87. HalfEven,
  88. HalfInfinity,
  89. HalfZero,
  90. Infinity,
  91. Zero,
  92. };
  93. // https://tc39.es/proposal-temporal/#table-unsigned-rounding-modes
  94. enum class Sign {
  95. Negative,
  96. Positive,
  97. };
  98. struct Auto { };
  99. struct Required { };
  100. struct Unset { };
  101. using Precision = Variant<Auto, u8>;
  102. using RoundingIncrement = Variant<Unset, u64>;
  103. using UnitDefault = Variant<Required, Unset, Auto, Unit>;
  104. using UnitValue = Variant<Unset, Auto, Unit>;
  105. struct SecondsStringPrecision {
  106. struct Minute { };
  107. using Precision = Variant<Minute, Auto, u8>;
  108. Precision precision;
  109. Unit unit;
  110. u8 increment { 0 };
  111. };
  112. struct RelativeTo {
  113. GC::Ptr<PlainDate> plain_relative_to; // [[PlainRelativeTo]]
  114. GC::Ptr<Object> zoned_relative_to; // FIXME: [[ZonedRelativeTo]]
  115. };
  116. struct DifferenceSettings {
  117. Unit smallest_unit;
  118. Unit largest_unit;
  119. RoundingMode rounding_mode;
  120. u64 rounding_increment { 0 };
  121. };
  122. double iso_date_to_epoch_days(double year, double month, double date);
  123. double epoch_days_to_epoch_ms(double day, double time);
  124. ThrowCompletionOr<void> check_iso_days_range(VM&, ISODate const&);
  125. ThrowCompletionOr<Overflow> get_temporal_overflow_option(VM&, Object const& options);
  126. RoundingMode negate_rounding_mode(RoundingMode);
  127. ThrowCompletionOr<ShowCalendar> get_temporal_show_calendar_name_option(VM&, Object const& options);
  128. ThrowCompletionOr<void> validate_temporal_rounding_increment(VM&, u64 increment, u64 dividend, bool inclusive);
  129. ThrowCompletionOr<Precision> get_temporal_fractional_second_digits_option(VM&, Object const& options);
  130. SecondsStringPrecision to_seconds_string_precision_record(UnitValue, Precision);
  131. ThrowCompletionOr<UnitValue> get_temporal_unit_valued_option(VM&, Object const& options, PropertyKey const&, UnitGroup, UnitDefault const&, ReadonlySpan<UnitValue> extra_values = {});
  132. ThrowCompletionOr<RelativeTo> get_temporal_relative_to_option(VM&, Object const& options);
  133. Unit larger_of_two_temporal_units(Unit, Unit);
  134. bool is_calendar_unit(Unit);
  135. UnitCategory temporal_unit_category(Unit);
  136. RoundingIncrement maximum_temporal_duration_rounding_increment(Unit);
  137. Crypto::UnsignedBigInteger const& temporal_unit_length_in_nanoseconds(Unit);
  138. ThrowCompletionOr<bool> is_partial_temporal_object(VM&, Value);
  139. String format_fractional_seconds(u64, Precision);
  140. String format_time_string(u8 hour, u8 minute, u8 second, u64 sub_second_nanoseconds, SecondsStringPrecision::Precision, Optional<TimeStyle> = {});
  141. UnsignedRoundingMode get_unsigned_rounding_mode(RoundingMode, Sign);
  142. double apply_unsigned_rounding_mode(double, double r1, double r2, UnsignedRoundingMode);
  143. Crypto::SignedBigInteger apply_unsigned_rounding_mode(Crypto::SignedDivisionResult const&, Crypto::SignedBigInteger const& r1, Crypto::SignedBigInteger const& r2, UnsignedRoundingMode, Crypto::UnsignedBigInteger const& increment);
  144. double round_number_to_increment(double, u64 increment, RoundingMode);
  145. Crypto::SignedBigInteger round_number_to_increment(Crypto::SignedBigInteger const&, Crypto::UnsignedBigInteger const& increment, RoundingMode);
  146. ThrowCompletionOr<ParsedISODateTime> parse_iso_date_time(VM&, StringView iso_string, ReadonlySpan<Production> allowed_formats);
  147. ThrowCompletionOr<String> parse_temporal_calendar_string(VM&, String const&);
  148. ThrowCompletionOr<GC::Ref<Duration>> parse_temporal_duration_string(VM&, StringView iso_string);
  149. ThrowCompletionOr<TimeZone> parse_temporal_time_zone_string(VM& vm, StringView time_zone_string);
  150. ThrowCompletionOr<String> to_month_code(VM&, Value argument);
  151. ThrowCompletionOr<String> to_offset_string(VM&, Value argument);
  152. CalendarFields iso_date_to_fields(StringView calendar, ISODate const&, DateType);
  153. ThrowCompletionOr<DifferenceSettings> get_difference_settings(VM&, DurationOperation, Object const& options, UnitGroup, ReadonlySpan<Unit> disallowed_units, Unit fallback_smallest_unit, Unit smallest_largest_default_unit);
  154. // 13.38 ToIntegerWithTruncation ( argument ), https://tc39.es/proposal-temporal/#sec-tointegerwithtruncation
  155. template<typename... Args>
  156. ThrowCompletionOr<double> to_integer_with_truncation(VM& vm, Value argument, ErrorType error_type, Args&&... args)
  157. {
  158. // 1. Let number be ? ToNumber(argument).
  159. auto number = TRY(argument.to_number(vm));
  160. // 2. If number is NaN, +∞𝔽 or -∞𝔽, throw a RangeError exception.
  161. if (number.is_nan() || number.is_infinity())
  162. return vm.throw_completion<RangeError>(error_type, forward<Args>(args)...);
  163. // 3. Return truncate(ℝ(number)).
  164. return trunc(number.as_double());
  165. }
  166. // 13.38 ToIntegerWithTruncation ( argument ), https://tc39.es/proposal-temporal/#sec-tointegerwithtruncation
  167. // AD-HOC: We often need to use this AO when we have a parsed StringView. This overload allows callers to avoid creating
  168. // a PrimitiveString for the primary definition.
  169. template<typename... Args>
  170. ThrowCompletionOr<double> to_integer_with_truncation(VM& vm, StringView argument, ErrorType error_type, Args&&... args)
  171. {
  172. // 1. Let number be ? ToNumber(argument).
  173. auto number = string_to_number(argument);
  174. // 2. If number is NaN, +∞𝔽 or -∞𝔽, throw a RangeError exception.
  175. if (isnan(number) || isinf(number))
  176. return vm.throw_completion<RangeError>(error_type, forward<Args>(args)...);
  177. // 3. Return truncate(ℝ(number)).
  178. return trunc(number);
  179. }
  180. // 13.37 ToPositiveIntegerWithTruncation ( argument ), https://tc39.es/proposal-temporal/#sec-topositiveintegerwithtruncation
  181. template<typename... Args>
  182. ThrowCompletionOr<double> to_positive_integer_with_truncation(VM& vm, Value argument, ErrorType error_type, Args&&... args)
  183. {
  184. // 1. Let integer be ? ToIntegerWithTruncation(argument).
  185. auto integer = TRY(to_integer_with_truncation(vm, argument, error_type, args...));
  186. // 2. If integer ≤ 0, throw a RangeError exception.
  187. if (integer <= 0)
  188. return vm.throw_completion<RangeError>(error_type, args...);
  189. // 3. Return integer.
  190. return integer;
  191. }
  192. // 13.39 ToIntegerIfIntegral ( argument ), https://tc39.es/proposal-temporal/#sec-tointegerifintegral
  193. template<typename... Args>
  194. ThrowCompletionOr<double> to_integer_if_integral(VM& vm, Value argument, ErrorType error_type, Args&&... args)
  195. {
  196. // 1. Let number be ? ToNumber(argument).
  197. auto number = TRY(argument.to_number(vm));
  198. // 2. If number is not an integral Number, throw a RangeError exception.
  199. if (!number.is_integral_number())
  200. return vm.throw_completion<RangeError>(error_type, forward<Args>(args)...);
  201. // 3. Return ℝ(number).
  202. return number.as_double();
  203. }
  204. // 14.2 The Year-Week Record Specification Type, https://tc39.es/proposal-temporal/#sec-year-week-record-specification-type
  205. struct YearWeek {
  206. Optional<u8> week;
  207. Optional<i32> year;
  208. };
  209. enum class OptionType {
  210. Boolean,
  211. String,
  212. };
  213. using OptionDefault = Variant<Required, Empty, bool, StringView, double>;
  214. ThrowCompletionOr<GC::Ref<Object>> get_options_object(VM&, Value options);
  215. ThrowCompletionOr<Value> get_option(VM&, Object const& options, PropertyKey const& property, OptionType type, ReadonlySpan<StringView> values, OptionDefault const&);
  216. template<size_t Size>
  217. ThrowCompletionOr<Value> get_option(VM& vm, Object const& options, PropertyKey const& property, OptionType type, StringView const (&values)[Size], OptionDefault const& default_)
  218. {
  219. return get_option(vm, options, property, type, ReadonlySpan<StringView> { values }, default_);
  220. }
  221. ThrowCompletionOr<RoundingMode> get_rounding_mode_option(VM&, Object const& options, RoundingMode fallback);
  222. ThrowCompletionOr<u64> get_rounding_increment_option(VM&, Object const& options);
  223. Crypto::SignedBigInteger get_utc_epoch_nanoseconds(ISODateTime const&);
  224. }