AbstractOperations.h 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  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 Overflow {
  31. Constrain,
  32. Reject,
  33. };
  34. enum class ShowCalendar {
  35. Auto,
  36. Always,
  37. Never,
  38. Critical,
  39. };
  40. enum class TimeStyle {
  41. Separated,
  42. Unseparated,
  43. };
  44. // https://tc39.es/proposal-temporal/#sec-temporal-units
  45. enum class Unit {
  46. Year,
  47. Month,
  48. Week,
  49. Day,
  50. Hour,
  51. Minute,
  52. Second,
  53. Millisecond,
  54. Microsecond,
  55. Nanosecond,
  56. };
  57. StringView temporal_unit_to_string(Unit);
  58. // https://tc39.es/proposal-temporal/#sec-temporal-units
  59. enum class UnitCategory {
  60. Date,
  61. Time,
  62. };
  63. // https://tc39.es/proposal-temporal/#sec-temporal-units
  64. enum class UnitGroup {
  65. Date,
  66. Time,
  67. DateTime,
  68. };
  69. // https://tc39.es/proposal-temporal/#table-unsigned-rounding-modes
  70. enum class RoundingMode {
  71. Ceil,
  72. Floor,
  73. Expand,
  74. Trunc,
  75. HalfCeil,
  76. HalfFloor,
  77. HalfExpand,
  78. HalfTrunc,
  79. HalfEven,
  80. };
  81. // https://tc39.es/proposal-temporal/#table-unsigned-rounding-modes
  82. enum class UnsignedRoundingMode {
  83. HalfEven,
  84. HalfInfinity,
  85. HalfZero,
  86. Infinity,
  87. Zero,
  88. };
  89. // https://tc39.es/proposal-temporal/#table-unsigned-rounding-modes
  90. enum class Sign {
  91. Negative,
  92. Positive,
  93. };
  94. struct Auto { };
  95. struct Required { };
  96. struct Unset { };
  97. using Precision = Variant<Auto, u8>;
  98. using RoundingIncrement = Variant<Unset, u64>;
  99. using UnitDefault = Variant<Required, Unset, Auto, Unit>;
  100. using UnitValue = Variant<Unset, Auto, Unit>;
  101. struct SecondsStringPrecision {
  102. struct Minute { };
  103. using Precision = Variant<Minute, Auto, u8>;
  104. Precision precision;
  105. Unit unit;
  106. u8 increment { 0 };
  107. };
  108. struct RelativeTo {
  109. // FIXME: Make these objects represent their actual types when we re-implement them.
  110. GC::Ptr<JS::Object> plain_relative_to; // [[PlainRelativeTo]]
  111. GC::Ptr<JS::Object> zoned_relative_to; // [[ZonedRelativeTo]]
  112. };
  113. // 13.31 ISO String Time Zone Parse Records, https://tc39.es/proposal-temporal/#sec-temporal-iso-string-time-zone-parse-records
  114. struct ParsedISOTimeZone {
  115. bool z_designator { false };
  116. Optional<String> offset_string;
  117. Optional<String> time_zone_annotation;
  118. };
  119. // 13.32 ISO Date-Time Parse Records, https://tc39.es/proposal-temporal/#sec-temporal-iso-date-time-parse-records
  120. struct ParsedISODateTime {
  121. struct StartOfDay { };
  122. Optional<i32> year { 0 };
  123. u8 month { 0 };
  124. u8 day { 0 };
  125. Variant<StartOfDay, Time> time;
  126. ParsedISOTimeZone time_zone;
  127. Optional<String> calendar;
  128. };
  129. double iso_date_to_epoch_days(double year, double month, double date);
  130. double epoch_days_to_epoch_ms(double day, double time);
  131. ThrowCompletionOr<Overflow> get_temporal_overflow_option(VM&, Object const& options);
  132. ThrowCompletionOr<ShowCalendar> get_temporal_show_calendar_name_option(VM&, Object const& options);
  133. ThrowCompletionOr<void> validate_temporal_rounding_increment(VM&, u64 increment, u64 dividend, bool inclusive);
  134. ThrowCompletionOr<Precision> get_temporal_fractional_second_digits_option(VM&, Object const& options);
  135. SecondsStringPrecision to_seconds_string_precision_record(UnitValue, Precision);
  136. ThrowCompletionOr<UnitValue> get_temporal_unit_valued_option(VM&, Object const& options, PropertyKey const&, UnitGroup, UnitDefault const&, ReadonlySpan<UnitValue> extra_values = {});
  137. ThrowCompletionOr<RelativeTo> get_temporal_relative_to_option(VM&, Object const& options);
  138. Unit larger_of_two_temporal_units(Unit, Unit);
  139. bool is_calendar_unit(Unit);
  140. UnitCategory temporal_unit_category(Unit);
  141. RoundingIncrement maximum_temporal_duration_rounding_increment(Unit);
  142. Crypto::UnsignedBigInteger const& temporal_unit_length_in_nanoseconds(Unit);
  143. ThrowCompletionOr<bool> is_partial_temporal_object(VM&, Value);
  144. String format_fractional_seconds(u64, Precision);
  145. String format_time_string(u8 hour, u8 minute, u8 second, u16 sub_second_nanoseconds, SecondsStringPrecision::Precision, Optional<TimeStyle> = {});
  146. UnsignedRoundingMode get_unsigned_rounding_mode(RoundingMode, Sign);
  147. double apply_unsigned_rounding_mode(double, double r1, double r2, UnsignedRoundingMode);
  148. Crypto::SignedBigInteger apply_unsigned_rounding_mode(Crypto::SignedDivisionResult const&, Crypto::SignedBigInteger const& r1, Crypto::SignedBigInteger const& r2, UnsignedRoundingMode, Crypto::UnsignedBigInteger const& increment);
  149. double round_number_to_increment(double, u64 increment, RoundingMode);
  150. Crypto::SignedBigInteger round_number_to_increment(Crypto::SignedBigInteger const&, Crypto::UnsignedBigInteger const& increment, RoundingMode);
  151. ThrowCompletionOr<ParsedISODateTime> parse_iso_date_time(VM&, StringView iso_string, ReadonlySpan<Production> allowed_formats);
  152. ThrowCompletionOr<String> parse_temporal_calendar_string(VM&, String const&);
  153. ThrowCompletionOr<GC::Ref<Duration>> parse_temporal_duration_string(VM&, StringView iso_string);
  154. ThrowCompletionOr<TimeZone> parse_temporal_time_zone_string(VM& vm, StringView time_zone_string);
  155. ThrowCompletionOr<String> to_month_code(VM&, Value argument);
  156. ThrowCompletionOr<String> to_offset_string(VM&, Value argument);
  157. CalendarFields iso_date_to_fields(StringView calendar, ISODate const&, DateType);
  158. // 13.38 ToIntegerWithTruncation ( argument ), https://tc39.es/proposal-temporal/#sec-tointegerwithtruncation
  159. template<typename... Args>
  160. ThrowCompletionOr<double> to_integer_with_truncation(VM& vm, Value argument, ErrorType error_type, Args&&... args)
  161. {
  162. // 1. Let number be ? ToNumber(argument).
  163. auto number = TRY(argument.to_number(vm));
  164. // 2. If number is NaN, +∞𝔽 or -∞𝔽, throw a RangeError exception.
  165. if (number.is_nan() || number.is_infinity())
  166. return vm.throw_completion<RangeError>(error_type, forward<Args>(args)...);
  167. // 3. Return truncate(ℝ(number)).
  168. return trunc(number.as_double());
  169. }
  170. // 13.38 ToIntegerWithTruncation ( argument ), https://tc39.es/proposal-temporal/#sec-tointegerwithtruncation
  171. // AD-HOC: We often need to use this AO when we have a parsed StringView. This overload allows callers to avoid creating
  172. // a PrimitiveString for the primary definition.
  173. template<typename... Args>
  174. ThrowCompletionOr<double> to_integer_with_truncation(VM& vm, StringView argument, ErrorType error_type, Args&&... args)
  175. {
  176. // 1. Let number be ? ToNumber(argument).
  177. auto number = string_to_number(argument);
  178. // 2. If number is NaN, +∞𝔽 or -∞𝔽, throw a RangeError exception.
  179. if (isnan(number) || isinf(number))
  180. return vm.throw_completion<RangeError>(error_type, forward<Args>(args)...);
  181. // 3. Return truncate(ℝ(number)).
  182. return trunc(number);
  183. }
  184. // 13.37 ToPositiveIntegerWithTruncation ( argument ), https://tc39.es/proposal-temporal/#sec-topositiveintegerwithtruncation
  185. template<typename... Args>
  186. ThrowCompletionOr<double> to_positive_integer_with_truncation(VM& vm, Value argument, ErrorType error_type, Args&&... args)
  187. {
  188. // 1. Let integer be ? ToIntegerWithTruncation(argument).
  189. auto integer = TRY(to_integer_with_truncation(vm, argument, error_type, args...));
  190. // 2. If integer ≤ 0, throw a RangeError exception.
  191. if (integer <= 0)
  192. return vm.throw_completion<RangeError>(error_type, args...);
  193. // 3. Return integer.
  194. return integer;
  195. }
  196. // 13.39 ToIntegerIfIntegral ( argument ), https://tc39.es/proposal-temporal/#sec-tointegerifintegral
  197. template<typename... Args>
  198. ThrowCompletionOr<double> to_integer_if_integral(VM& vm, Value argument, ErrorType error_type, Args&&... args)
  199. {
  200. // 1. Let number be ? ToNumber(argument).
  201. auto number = TRY(argument.to_number(vm));
  202. // 2. If number is not an integral Number, throw a RangeError exception.
  203. if (!number.is_integral_number())
  204. return vm.throw_completion<RangeError>(error_type, forward<Args>(args)...);
  205. // 3. Return ℝ(number).
  206. return number.as_double();
  207. }
  208. // 14.2 The Year-Week Record Specification Type, https://tc39.es/proposal-temporal/#sec-year-week-record-specification-type
  209. struct YearWeek {
  210. Optional<u8> week;
  211. Optional<i32> year;
  212. };
  213. enum class OptionType {
  214. Boolean,
  215. String,
  216. };
  217. using OptionDefault = Variant<Required, Empty, bool, StringView, double>;
  218. ThrowCompletionOr<GC::Ref<Object>> get_options_object(VM&, Value options);
  219. ThrowCompletionOr<Value> get_option(VM&, Object const& options, PropertyKey const& property, OptionType type, ReadonlySpan<StringView> values, OptionDefault const&);
  220. template<size_t Size>
  221. ThrowCompletionOr<Value> get_option(VM& vm, Object const& options, PropertyKey const& property, OptionType type, StringView const (&values)[Size], OptionDefault const& default_)
  222. {
  223. return get_option(vm, options, property, type, ReadonlySpan<StringView> { values }, default_);
  224. }
  225. ThrowCompletionOr<RoundingMode> get_rounding_mode_option(VM&, Object const& options, RoundingMode fallback);
  226. ThrowCompletionOr<u64> get_rounding_increment_option(VM&, Object const& options);
  227. Crypto::SignedBigInteger get_utc_epoch_nanoseconds(ISODateTime const&);
  228. }