AbstractOperations.h 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  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/PlainTime.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. // FIXME: Make these objects represent their actual types when we re-implement them.
  114. GC::Ptr<JS::Object> plain_relative_to; // [[PlainRelativeTo]]
  115. GC::Ptr<JS::Object> zoned_relative_to; // [[ZonedRelativeTo]]
  116. };
  117. // 13.31 ISO String Time Zone Parse Records, https://tc39.es/proposal-temporal/#sec-temporal-iso-string-time-zone-parse-records
  118. struct ParsedISOTimeZone {
  119. bool z_designator { false };
  120. Optional<String> offset_string;
  121. Optional<String> time_zone_annotation;
  122. };
  123. // 13.32 ISO Date-Time Parse Records, https://tc39.es/proposal-temporal/#sec-temporal-iso-date-time-parse-records
  124. struct ParsedISODateTime {
  125. struct StartOfDay { };
  126. Optional<i32> year { 0 };
  127. u8 month { 0 };
  128. u8 day { 0 };
  129. Variant<StartOfDay, Time> time;
  130. ParsedISOTimeZone time_zone;
  131. Optional<String> calendar;
  132. };
  133. struct DifferenceSettings {
  134. Unit smallest_unit;
  135. Unit largest_unit;
  136. RoundingMode rounding_mode;
  137. u64 rounding_increment { 0 };
  138. };
  139. double iso_date_to_epoch_days(double year, double month, double date);
  140. double epoch_days_to_epoch_ms(double day, double time);
  141. ThrowCompletionOr<void> check_iso_days_range(VM&, ISODate const&);
  142. ThrowCompletionOr<Overflow> get_temporal_overflow_option(VM&, Object const& options);
  143. RoundingMode negate_rounding_mode(RoundingMode);
  144. ThrowCompletionOr<ShowCalendar> get_temporal_show_calendar_name_option(VM&, Object const& options);
  145. ThrowCompletionOr<void> validate_temporal_rounding_increment(VM&, u64 increment, u64 dividend, bool inclusive);
  146. ThrowCompletionOr<Precision> get_temporal_fractional_second_digits_option(VM&, Object const& options);
  147. SecondsStringPrecision to_seconds_string_precision_record(UnitValue, Precision);
  148. ThrowCompletionOr<UnitValue> get_temporal_unit_valued_option(VM&, Object const& options, PropertyKey const&, UnitGroup, UnitDefault const&, ReadonlySpan<UnitValue> extra_values = {});
  149. ThrowCompletionOr<RelativeTo> get_temporal_relative_to_option(VM&, Object const& options);
  150. Unit larger_of_two_temporal_units(Unit, Unit);
  151. bool is_calendar_unit(Unit);
  152. UnitCategory temporal_unit_category(Unit);
  153. RoundingIncrement maximum_temporal_duration_rounding_increment(Unit);
  154. Crypto::UnsignedBigInteger const& temporal_unit_length_in_nanoseconds(Unit);
  155. ThrowCompletionOr<bool> is_partial_temporal_object(VM&, Value);
  156. String format_fractional_seconds(u64, Precision);
  157. String format_time_string(u8 hour, u8 minute, u8 second, u16 sub_second_nanoseconds, SecondsStringPrecision::Precision, Optional<TimeStyle> = {});
  158. UnsignedRoundingMode get_unsigned_rounding_mode(RoundingMode, Sign);
  159. double apply_unsigned_rounding_mode(double, double r1, double r2, UnsignedRoundingMode);
  160. Crypto::SignedBigInteger apply_unsigned_rounding_mode(Crypto::SignedDivisionResult const&, Crypto::SignedBigInteger const& r1, Crypto::SignedBigInteger const& r2, UnsignedRoundingMode, Crypto::UnsignedBigInteger const& increment);
  161. double round_number_to_increment(double, u64 increment, RoundingMode);
  162. Crypto::SignedBigInteger round_number_to_increment(Crypto::SignedBigInteger const&, Crypto::UnsignedBigInteger const& increment, RoundingMode);
  163. ThrowCompletionOr<ParsedISODateTime> parse_iso_date_time(VM&, StringView iso_string, ReadonlySpan<Production> allowed_formats);
  164. ThrowCompletionOr<String> parse_temporal_calendar_string(VM&, String const&);
  165. ThrowCompletionOr<GC::Ref<Duration>> parse_temporal_duration_string(VM&, StringView iso_string);
  166. ThrowCompletionOr<TimeZone> parse_temporal_time_zone_string(VM& vm, StringView time_zone_string);
  167. ThrowCompletionOr<String> to_month_code(VM&, Value argument);
  168. ThrowCompletionOr<String> to_offset_string(VM&, Value argument);
  169. CalendarFields iso_date_to_fields(StringView calendar, ISODate const&, DateType);
  170. ThrowCompletionOr<DifferenceSettings> get_difference_settings(VM&, DurationOperation, Object const& options, UnitGroup, ReadonlySpan<Unit> disallowed_units, Unit fallback_smallest_unit, Unit smallest_largest_default_unit);
  171. // 13.38 ToIntegerWithTruncation ( argument ), https://tc39.es/proposal-temporal/#sec-tointegerwithtruncation
  172. template<typename... Args>
  173. ThrowCompletionOr<double> to_integer_with_truncation(VM& vm, Value argument, ErrorType error_type, Args&&... args)
  174. {
  175. // 1. Let number be ? ToNumber(argument).
  176. auto number = TRY(argument.to_number(vm));
  177. // 2. If number is NaN, +∞𝔽 or -∞𝔽, throw a RangeError exception.
  178. if (number.is_nan() || number.is_infinity())
  179. return vm.throw_completion<RangeError>(error_type, forward<Args>(args)...);
  180. // 3. Return truncate(ℝ(number)).
  181. return trunc(number.as_double());
  182. }
  183. // 13.38 ToIntegerWithTruncation ( argument ), https://tc39.es/proposal-temporal/#sec-tointegerwithtruncation
  184. // AD-HOC: We often need to use this AO when we have a parsed StringView. This overload allows callers to avoid creating
  185. // a PrimitiveString for the primary definition.
  186. template<typename... Args>
  187. ThrowCompletionOr<double> to_integer_with_truncation(VM& vm, StringView argument, ErrorType error_type, Args&&... args)
  188. {
  189. // 1. Let number be ? ToNumber(argument).
  190. auto number = string_to_number(argument);
  191. // 2. If number is NaN, +∞𝔽 or -∞𝔽, throw a RangeError exception.
  192. if (isnan(number) || isinf(number))
  193. return vm.throw_completion<RangeError>(error_type, forward<Args>(args)...);
  194. // 3. Return truncate(ℝ(number)).
  195. return trunc(number);
  196. }
  197. // 13.37 ToPositiveIntegerWithTruncation ( argument ), https://tc39.es/proposal-temporal/#sec-topositiveintegerwithtruncation
  198. template<typename... Args>
  199. ThrowCompletionOr<double> to_positive_integer_with_truncation(VM& vm, Value argument, ErrorType error_type, Args&&... args)
  200. {
  201. // 1. Let integer be ? ToIntegerWithTruncation(argument).
  202. auto integer = TRY(to_integer_with_truncation(vm, argument, error_type, args...));
  203. // 2. If integer ≤ 0, throw a RangeError exception.
  204. if (integer <= 0)
  205. return vm.throw_completion<RangeError>(error_type, args...);
  206. // 3. Return integer.
  207. return integer;
  208. }
  209. // 13.39 ToIntegerIfIntegral ( argument ), https://tc39.es/proposal-temporal/#sec-tointegerifintegral
  210. template<typename... Args>
  211. ThrowCompletionOr<double> to_integer_if_integral(VM& vm, Value argument, ErrorType error_type, Args&&... args)
  212. {
  213. // 1. Let number be ? ToNumber(argument).
  214. auto number = TRY(argument.to_number(vm));
  215. // 2. If number is not an integral Number, throw a RangeError exception.
  216. if (!number.is_integral_number())
  217. return vm.throw_completion<RangeError>(error_type, forward<Args>(args)...);
  218. // 3. Return ℝ(number).
  219. return number.as_double();
  220. }
  221. // 14.2 The Year-Week Record Specification Type, https://tc39.es/proposal-temporal/#sec-year-week-record-specification-type
  222. struct YearWeek {
  223. Optional<u8> week;
  224. Optional<i32> year;
  225. };
  226. enum class OptionType {
  227. Boolean,
  228. String,
  229. };
  230. using OptionDefault = Variant<Required, Empty, bool, StringView, double>;
  231. ThrowCompletionOr<GC::Ref<Object>> get_options_object(VM&, Value options);
  232. ThrowCompletionOr<Value> get_option(VM&, Object const& options, PropertyKey const& property, OptionType type, ReadonlySpan<StringView> values, OptionDefault const&);
  233. template<size_t Size>
  234. ThrowCompletionOr<Value> get_option(VM& vm, Object const& options, PropertyKey const& property, OptionType type, StringView const (&values)[Size], OptionDefault const& default_)
  235. {
  236. return get_option(vm, options, property, type, ReadonlySpan<StringView> { values }, default_);
  237. }
  238. ThrowCompletionOr<RoundingMode> get_rounding_mode_option(VM&, Object const& options, RoundingMode fallback);
  239. ThrowCompletionOr<u64> get_rounding_increment_option(VM&, Object const& options);
  240. Crypto::SignedBigInteger get_utc_epoch_nanoseconds(ISODateTime const&);
  241. }