ISO8601.cpp 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341
  1. /*
  2. * Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org>
  3. * Copyright (c) 2024, Tim Flynn <trflynn89@ladybird.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <AK/CharacterTypes.h>
  8. #include <AK/GenericLexer.h>
  9. #include <LibJS/Runtime/Temporal/DateEquations.h>
  10. #include <LibJS/Runtime/Temporal/ISO8601.h>
  11. #include <LibJS/Runtime/Value.h>
  12. namespace JS::Temporal {
  13. enum class Extended {
  14. No,
  15. Yes,
  16. };
  17. enum class Separator {
  18. No,
  19. Yes,
  20. };
  21. enum class TimeRequired {
  22. No,
  23. Yes,
  24. };
  25. enum class ZDesignator {
  26. No,
  27. Yes,
  28. };
  29. enum class Zoned {
  30. No,
  31. Yes,
  32. };
  33. // 13.30.1 Static Semantics: IsValidMonthDay, https://tc39.es/proposal-temporal/#sec-temporal-iso8601grammar-static-semantics-isvalidmonthday
  34. static bool is_valid_month_day(ParseResult const& result)
  35. {
  36. // 1. If DateDay is "31" and DateMonth is "02", "04", "06", "09", "11", return false.
  37. if (result.date_day == "31"sv && result.date_month->is_one_of("02"sv, "04"sv, "06"sv, "09"sv, "11"sv))
  38. return false;
  39. // 2. If DateMonth is "02" and DateDay is "30", return false.
  40. if (result.date_month == "02"sv && result.date_day == "30"sv)
  41. return false;
  42. // 3. Return true.
  43. return true;
  44. }
  45. // 13.30.2 Static Semantics: IsValidDate, https://tc39.es/proposal-temporal/#sec-temporal-iso8601grammar-static-semantics-isvaliddate
  46. static bool is_valid_date(ParseResult const& result)
  47. {
  48. // 1. If IsValidMonthDay of DateSpec is false, return false.
  49. if (!is_valid_month_day(result))
  50. return false;
  51. // 2. Let year be ℝ(StringToNumber(CodePointsToString(DateYear))).
  52. auto year = string_to_number(*result.date_year);
  53. // 3. If DateMonth is "02" and DateDay is "29" and MathematicalInLeapYear(EpochTimeForYear(year)) = 0, return false.
  54. if (result.date_month == "02"sv && result.date_day == "29"sv && mathematical_in_leap_year(epoch_time_for_year(year)) == 0)
  55. return false;
  56. // 4. Return true.
  57. return true;
  58. }
  59. // 13.30 ISO 8601 grammar, https://tc39.es/proposal-temporal/#sec-temporal-iso8601grammar
  60. class ISO8601Parser {
  61. public:
  62. explicit ISO8601Parser(StringView input)
  63. : m_input(input)
  64. , m_state({
  65. .lexer = GenericLexer { input },
  66. .parse_result = {},
  67. })
  68. {
  69. }
  70. [[nodiscard]] GenericLexer const& lexer() const { return m_state.lexer; }
  71. [[nodiscard]] ParseResult const& parse_result() const { return m_state.parse_result; }
  72. // https://tc39.es/proposal-temporal/#prod-TemporalDateTimeString
  73. [[nodiscard]] bool parse_temporal_date_time_string()
  74. {
  75. // TemporalDateTimeString[Zoned] :::
  76. // AnnotatedDateTime[?Zoned, ~TimeRequired]
  77. return parse_annotated_date_time(Zoned::No, TimeRequired::No);
  78. }
  79. // https://tc39.es/proposal-temporal/#prod-TemporalDateTimeString
  80. [[nodiscard]] bool parse_temporal_zoned_date_time_string()
  81. {
  82. // TemporalDateTimeString[Zoned] :::
  83. // AnnotatedDateTime[?Zoned, ~TimeRequired]
  84. return parse_annotated_date_time(Zoned::Yes, TimeRequired::No);
  85. }
  86. // https://tc39.es/proposal-temporal/#prod-TemporalDurationString
  87. [[nodiscard]] bool parse_temporal_duration_string()
  88. {
  89. // TemporalDurationString :::
  90. // Duration
  91. return parse_duration();
  92. }
  93. // https://tc39.es/proposal-temporal/#prod-TemporalInstantString
  94. [[nodiscard]] bool parse_temporal_instant_string()
  95. {
  96. // TemporalInstantString :::
  97. // Date DateTimeSeparator Time DateTimeUTCOffset[+Z] TimeZoneAnnotation[opt] Annotations[opt]
  98. if (!parse_date())
  99. return false;
  100. if (!parse_date_time_separator())
  101. return false;
  102. if (!parse_time())
  103. return false;
  104. if (!parse_date_time_utc_offset(ZDesignator::Yes))
  105. return false;
  106. (void)parse_time_zone_annotation();
  107. (void)parse_annotations();
  108. return true;
  109. }
  110. // https://tc39.es/proposal-temporal/#prod-TemporalMonthDayString
  111. [[nodiscard]] bool parse_temporal_month_day_string()
  112. {
  113. // TemporalMonthDayString :::
  114. // AnnotatedMonthDay
  115. // AnnotatedDateTime[~Zoned, ~TimeRequired]
  116. // NOTE: Reverse order here because `AnnotatedMonthDay` can be a subset of `AnnotatedDateTime`.
  117. return parse_annotated_date_time(Zoned::No, TimeRequired::No) || parse_annotated_month_day();
  118. }
  119. // https://tc39.es/proposal-temporal/#prod-TemporalTimeString
  120. [[nodiscard]] bool parse_temporal_time_string()
  121. {
  122. // TemporalTimeString :::
  123. // AnnotatedTime
  124. // AnnotatedDateTime[~Zoned, +TimeRequired]
  125. // NOTE: Reverse order here because `AnnotatedTime` can be a subset of `AnnotatedDateTime`.
  126. return parse_annotated_date_time(Zoned::No, TimeRequired::Yes) || parse_annotated_time();
  127. }
  128. // https://tc39.es/proposal-temporal/#prod-TemporalYearMonthString
  129. [[nodiscard]] bool parse_temporal_year_month_string()
  130. {
  131. // TemporalYearMonthString :::
  132. // AnnotatedYearMonth
  133. // AnnotatedDateTime[~Zoned, ~TimeRequired]
  134. // NOTE: Reverse order here because `AnnotatedYearMonth` can be a subset of `AnnotatedDateTime`.
  135. return parse_annotated_date_time(Zoned::No, TimeRequired::No) || parse_annotated_year_month();
  136. }
  137. // https://tc39.es/proposal-temporal/#prod-AnnotatedDateTime
  138. [[nodiscard]] bool parse_annotated_date_time(Zoned zoned, TimeRequired time_required)
  139. {
  140. // AnnotatedDateTime[Zoned, TimeRequired] :::
  141. // [~Zoned] DateTime[~Z, ?TimeRequired] TimeZoneAnnotation[opt] Annotations[opt]
  142. // [+Zoned] DateTime[+Z, ?TimeRequired] TimeZoneAnnotation Annotations[opt]
  143. if (!parse_date_time(zoned == Zoned::Yes ? ZDesignator::Yes : ZDesignator::No, time_required))
  144. return false;
  145. if (!parse_time_zone_annotation()) {
  146. if (zoned == Zoned::Yes)
  147. return false;
  148. }
  149. (void)parse_annotations();
  150. return true;
  151. }
  152. // https://tc39.es/proposal-temporal/#prod-AnnotatedMonthDay
  153. [[nodiscard]] bool parse_annotated_month_day()
  154. {
  155. // AnnotatedMonthDay :::
  156. // DateSpecMonthDay TimeZoneAnnotation[opt] Annotations[opt]
  157. if (!parse_date_spec_month_day())
  158. return false;
  159. (void)parse_time_zone_annotation();
  160. (void)parse_annotations();
  161. return true;
  162. }
  163. // https://tc39.es/proposal-temporal/#prod-AnnotatedTime
  164. [[nodiscard]] bool parse_annotated_time()
  165. {
  166. // AnnotatedTime :::
  167. // TimeDesignator Time DateTimeUTCOffset[~Z][opt] TimeZoneAnnotation[opt] Annotations[opt]
  168. // Time DateTimeUTCOffset[~Z][opt] TimeZoneAnnotation[opt] Annotations[opt]
  169. (void)parse_time_designator();
  170. if (!parse_time())
  171. return false;
  172. (void)parse_date_time_utc_offset(ZDesignator::No);
  173. (void)parse_time_zone_annotation();
  174. (void)parse_annotations();
  175. return true;
  176. }
  177. // https://tc39.es/proposal-temporal/#prod-AnnotatedYearMonth
  178. [[nodiscard]] bool parse_annotated_year_month()
  179. {
  180. // AnnotatedYearMonth :::
  181. // DateSpecYearMonth TimeZoneAnnotation[opt] Annotations[opt]
  182. if (!parse_date_spec_year_month())
  183. return false;
  184. (void)parse_time_zone_annotation();
  185. (void)parse_annotations();
  186. return true;
  187. }
  188. // https://tc39.es/proposal-temporal/#prod-DateTime
  189. [[nodiscard]] bool parse_date_time(ZDesignator z_designator, TimeRequired time_required)
  190. {
  191. StateTransaction transaction { *this };
  192. // DateTime[Z, TimeRequired] :::
  193. // [~TimeRequired] Date
  194. // Date DateTimeSeparator Time DateTimeUTCOffset[?Z][opt]
  195. if (!parse_date())
  196. return false;
  197. if (parse_date_time_separator()) {
  198. if (!parse_time())
  199. return false;
  200. (void)parse_date_time_utc_offset(z_designator);
  201. } else if (time_required == TimeRequired::Yes) {
  202. return false;
  203. }
  204. transaction.commit();
  205. return true;
  206. }
  207. // https://tc39.es/proposal-temporal/#prod-Date
  208. [[nodiscard]] bool parse_date()
  209. {
  210. // Date :::
  211. // DateSpec[+Extended]
  212. // DateSpec[~Extended]
  213. return parse_date_spec(Extended::Yes) || parse_date_spec(Extended::No);
  214. }
  215. // https://tc39.es/proposal-temporal/#prod-DateSpec
  216. [[nodiscard]] bool parse_date_spec(Extended extended)
  217. {
  218. StateTransaction transaction { *this };
  219. // DateSpec[Extended] :::
  220. // DateYear DateSeparator[?Extended] DateMonth DateSeparator[?Extended] DateDay
  221. if (!parse_date_year())
  222. return false;
  223. if (!parse_date_separator(extended))
  224. return false;
  225. if (!parse_date_month())
  226. return false;
  227. if (!parse_date_separator(extended))
  228. return false;
  229. if (!parse_date_day())
  230. return false;
  231. // It is a Syntax Error if IsValidDate of DateSpec is false.
  232. if (!is_valid_date(m_state.parse_result))
  233. return false;
  234. transaction.commit();
  235. return true;
  236. }
  237. // https://tc39.es/proposal-temporal/#prod-DateSpecMonthDay
  238. [[nodiscard]] bool parse_date_spec_month_day()
  239. {
  240. StateTransaction transaction { *this };
  241. // DateSpecMonthDay :::
  242. // --[opt] DateMonth DateSeparator[+Extended] DateDay
  243. // --[opt] DateMonth DateSeparator[~Extended] DateDay
  244. (void)m_state.lexer.consume_specific("--"sv);
  245. if (!parse_date_month())
  246. return false;
  247. if (!parse_date_separator(Extended::Yes) && !parse_date_separator(Extended::No))
  248. return false;
  249. if (!parse_date_day())
  250. return false;
  251. // It is a Syntax Error if IsValidMonthDay of DateSpecMonthDay is false.
  252. if (!is_valid_month_day(m_state.parse_result))
  253. return false;
  254. transaction.commit();
  255. return true;
  256. }
  257. // https://tc39.es/proposal-temporal/#prod-DateSpecYearMonth
  258. [[nodiscard]] bool parse_date_spec_year_month()
  259. {
  260. StateTransaction transaction { *this };
  261. // DateSpecYearMonth :::
  262. // DateYear DateSeparator[+Extended] DateMonth
  263. // DateYear DateSeparator[~Extended] DateMonth
  264. if (!parse_date_year())
  265. return false;
  266. if (!parse_date_separator(Extended::Yes) && !parse_date_separator(Extended::No))
  267. return false;
  268. if (!parse_date_month())
  269. return false;
  270. transaction.commit();
  271. return true;
  272. }
  273. // https://tc39.es/proposal-temporal/#prod-DateYear
  274. [[nodiscard]] bool parse_date_year()
  275. {
  276. StateTransaction transaction { *this };
  277. // DateYear :::
  278. // DecimalDigit DecimalDigit DecimalDigit DecimalDigit
  279. // ASCIISign DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit
  280. size_t digit_count = parse_ascii_sign() ? 6 : 4;
  281. for (size_t i = 0; i < digit_count; ++i) {
  282. if (!parse_decimal_digit())
  283. return false;
  284. }
  285. // It is a Syntax Error if DateYear is "-000000".
  286. if (transaction.parsed_string_view() == "-000000"sv)
  287. return false;
  288. m_state.parse_result.date_year = transaction.parsed_string_view();
  289. transaction.commit();
  290. return true;
  291. }
  292. // https://tc39.es/proposal-temporal/#prod-DateMonth
  293. [[nodiscard]] bool parse_date_month()
  294. {
  295. StateTransaction transaction { *this };
  296. // DateMonth :::
  297. // 0 NonZeroDigit
  298. // 10
  299. // 11
  300. // 12
  301. if (m_state.lexer.consume_specific('0')) {
  302. if (!parse_non_zero_digit())
  303. return false;
  304. } else {
  305. auto success = m_state.lexer.consume_specific("10"sv) || m_state.lexer.consume_specific("11"sv) || m_state.lexer.consume_specific("12"sv);
  306. if (!success)
  307. return false;
  308. }
  309. m_state.parse_result.date_month = transaction.parsed_string_view();
  310. transaction.commit();
  311. return true;
  312. }
  313. // https://tc39.es/proposal-temporal/#prod-DateDay
  314. [[nodiscard]] bool parse_date_day()
  315. {
  316. StateTransaction transaction { *this };
  317. // DateDay :::
  318. // 0 NonZeroDigit
  319. // 1 DecimalDigit
  320. // 2 DecimalDigit
  321. // 30
  322. // 31
  323. if (m_state.lexer.consume_specific('0')) {
  324. if (!parse_non_zero_digit())
  325. return false;
  326. } else if (m_state.lexer.consume_specific('1') || m_state.lexer.consume_specific('2')) {
  327. if (!parse_decimal_digit())
  328. return false;
  329. } else {
  330. auto success = m_state.lexer.consume_specific("30"sv) || m_state.lexer.consume_specific("31"sv);
  331. if (!success)
  332. return false;
  333. }
  334. m_state.parse_result.date_day = transaction.parsed_string_view();
  335. transaction.commit();
  336. return true;
  337. }
  338. // https://tc39.es/proposal-temporal/#prod-DateTimeUTCOffset
  339. [[nodiscard]] bool parse_date_time_utc_offset(ZDesignator z_designator)
  340. {
  341. // DateTimeUTCOffset[Z] :::
  342. // [+Z] UTCDesignator
  343. // UTCOffset[+SubMinutePrecision]
  344. if (z_designator == ZDesignator::Yes) {
  345. if (parse_utc_designator())
  346. return true;
  347. }
  348. return parse_utc_offset(SubMinutePrecision::Yes, m_state.parse_result.date_time_offset);
  349. }
  350. // https://tc39.es/proposal-temporal/#prod-Time
  351. [[nodiscard]] bool parse_time()
  352. {
  353. // Time :::
  354. // TimeSpec[+Extended]
  355. // TimeSpec[~Extended]
  356. return parse_time_spec();
  357. }
  358. // https://tc39.es/proposal-temporal/#prod-TimeSpec
  359. [[nodiscard]] bool parse_time_spec()
  360. {
  361. StateTransaction transaction { *this };
  362. auto parse_time_hour = [&]() {
  363. return scoped_parse(m_state.parse_result.time_hour, [&]() { return parse_hour(); });
  364. };
  365. auto parse_time_minute = [&]() {
  366. return scoped_parse(m_state.parse_result.time_minute, [&]() { return parse_minute_second(); });
  367. };
  368. auto parse_time_fraction = [&]() {
  369. return scoped_parse(m_state.parse_result.time_fraction, [&]() { return parse_temporal_decimal_fraction(); });
  370. };
  371. // TimeSpec[Extended] :::
  372. // Hour
  373. // Hour TimeSeparator[?Extended] MinuteSecond
  374. // Hour TimeSeparator[?Extended] MinuteSecond TimeSeparator[?Extended] TimeSecond TemporalDecimalFraction[opt]
  375. if (!parse_time_hour())
  376. return false;
  377. if (parse_time_separator(Extended::Yes)) {
  378. if (!parse_time_minute())
  379. return false;
  380. if (parse_time_separator(Extended::Yes)) {
  381. if (!parse_time_second())
  382. return false;
  383. (void)parse_time_fraction();
  384. }
  385. } else if (parse_time_minute() && parse_time_second()) {
  386. (void)parse_time_fraction();
  387. }
  388. transaction.commit();
  389. return true;
  390. }
  391. // https://tc39.es/proposal-temporal/#prod-TimeSecond
  392. [[nodiscard]] bool parse_time_second()
  393. {
  394. StateTransaction transaction { *this };
  395. // TimeSecond :::
  396. // MinuteSecond
  397. // 60
  398. auto success = parse_minute_second() || m_state.lexer.consume_specific("60"sv);
  399. if (!success)
  400. return false;
  401. m_state.parse_result.time_second = transaction.parsed_string_view();
  402. transaction.commit();
  403. return true;
  404. }
  405. // https://tc39.es/proposal-temporal/#prod-TimeZoneAnnotation
  406. [[nodiscard]] bool parse_time_zone_annotation()
  407. {
  408. StateTransaction transaction { *this };
  409. // TimeZoneAnnotation :::
  410. // [ AnnotationCriticalFlag[opt] TimeZoneIdentifier ]
  411. if (!m_state.lexer.consume_specific('['))
  412. return false;
  413. (void)parse_annotation_critical_flag();
  414. if (!parse_time_zone_identifier())
  415. return false;
  416. if (!m_state.lexer.consume_specific(']'))
  417. return false;
  418. transaction.commit();
  419. return true;
  420. }
  421. // https://tc39.es/proposal-temporal/#prod-TimeZoneIdentifier
  422. [[nodiscard]] bool parse_time_zone_identifier()
  423. {
  424. StateTransaction transaction { *this };
  425. // TimeZoneIdentifier :::
  426. // UTCOffset[~SubMinutePrecision]
  427. // TimeZoneIANAName
  428. auto success = parse_utc_offset(SubMinutePrecision::No, m_state.parse_result.time_zone_offset) || parse_time_zone_iana_name();
  429. if (!success)
  430. return false;
  431. m_state.parse_result.time_zone_identifier = transaction.parsed_string_view();
  432. transaction.commit();
  433. return true;
  434. }
  435. // https://tc39.es/proposal-temporal/#prod-TimeZoneIANAName
  436. [[nodiscard]] bool parse_time_zone_iana_name()
  437. {
  438. StateTransaction transaction { *this };
  439. // TimeZoneIANAName :::
  440. // TimeZoneIANANameComponent
  441. // TimeZoneIANAName / TimeZoneIANANameComponent
  442. if (!parse_time_zone_iana_name_component())
  443. return false;
  444. while (m_state.lexer.consume_specific('/')) {
  445. if (!parse_time_zone_iana_name_component())
  446. return false;
  447. }
  448. m_state.parse_result.time_zone_iana_name = transaction.parsed_string_view();
  449. transaction.commit();
  450. return true;
  451. }
  452. // https://tc39.es/proposal-temporal/#prod-TimeZoneIANANameComponent
  453. [[nodiscard]] bool parse_time_zone_iana_name_component()
  454. {
  455. // TimeZoneIANANameComponent :::
  456. // TZLeadingChar
  457. // TimeZoneIANANameComponent TZChar
  458. if (!parse_tz_leading_char())
  459. return false;
  460. while (parse_tz_leading_char())
  461. ;
  462. while (parse_tz_char())
  463. ;
  464. return true;
  465. }
  466. // https://tc39.es/proposal-temporal/#prod-TZLeadingChar
  467. [[nodiscard]] bool parse_tz_leading_char()
  468. {
  469. // TZLeadingChar :::
  470. // Alpha
  471. // .
  472. // _
  473. return parse_alpha() || m_state.lexer.consume_specific('.') || m_state.lexer.consume_specific('_');
  474. }
  475. // https://tc39.es/proposal-temporal/#prod-TZChar
  476. [[nodiscard]] bool parse_tz_char()
  477. {
  478. // TZChar :::
  479. // TZLeadingChar
  480. // DecimalDigit
  481. // -
  482. // +
  483. return parse_tz_leading_char() || parse_decimal_digit() || m_state.lexer.consume_specific('.') || m_state.lexer.consume_specific('+');
  484. }
  485. // https://tc39.es/proposal-temporal/#prod-Annotations
  486. [[nodiscard]] bool parse_annotations()
  487. {
  488. // Annotations :::
  489. // Annotation Annotationsopt
  490. if (!parse_annotation())
  491. return false;
  492. while (parse_annotation())
  493. ;
  494. return true;
  495. }
  496. // https://tc39.es/proposal-temporal/#prod-Annotation
  497. [[nodiscard]] bool parse_annotation()
  498. {
  499. StateTransaction transaction { *this };
  500. Optional<StringView> key;
  501. Optional<StringView> value;
  502. // Annotation :::
  503. // [ AnnotationCriticalFlag[opt] AnnotationKey = AnnotationValue ]
  504. if (!m_state.lexer.consume_specific('['))
  505. return false;
  506. auto critical = parse_annotation_critical_flag();
  507. if (!scoped_parse(key, [&]() { return parse_annotation_key(); }))
  508. return false;
  509. if (!m_state.lexer.consume_specific('='))
  510. return false;
  511. if (!scoped_parse(value, [&]() { return parse_annotation_value(); }))
  512. return false;
  513. if (!m_state.lexer.consume_specific(']'))
  514. return false;
  515. m_state.parse_result.annotations.empend(critical, *key, *value);
  516. transaction.commit();
  517. return true;
  518. }
  519. // https://tc39.es/proposal-temporal/#prod-AnnotationKey
  520. [[nodiscard]] bool parse_annotation_key()
  521. {
  522. // AnnotationKey :::
  523. // AKeyLeadingChar
  524. // AnnotationKey AKeyChar
  525. if (!parse_annotation_key_leading_char())
  526. return false;
  527. while (parse_annotation_key_leading_char())
  528. ;
  529. while (parse_annotation_key_char())
  530. ;
  531. return true;
  532. }
  533. // https://tc39.es/proposal-temporal/#prod-AKeyLeadingChar
  534. [[nodiscard]] bool parse_annotation_key_leading_char()
  535. {
  536. // AKeyLeadingChar :::
  537. // LowercaseAlpha
  538. // _
  539. return parse_lowercase_alpha() || m_state.lexer.consume_specific('_');
  540. }
  541. // https://tc39.es/proposal-temporal/#prod-AKeyChar
  542. [[nodiscard]] bool parse_annotation_key_char()
  543. {
  544. // AKeyChar :::
  545. // AKeyLeadingChar
  546. // DecimalDigit
  547. // -
  548. return parse_annotation_key_leading_char() || parse_decimal_digit() || m_state.lexer.consume_specific('-');
  549. }
  550. // https://tc39.es/proposal-temporal/#prod-AnnotationValue
  551. [[nodiscard]] bool parse_annotation_value()
  552. {
  553. // AnnotationValue :::
  554. // AnnotationValueComponent
  555. // AnnotationValueComponent - AnnotationValue
  556. if (!parse_annotation_value_component())
  557. return false;
  558. while (m_state.lexer.consume_specific('-')) {
  559. if (!parse_annotation_value_component())
  560. return false;
  561. }
  562. return true;
  563. }
  564. // https://tc39.es/proposal-temporal/#prod-AnnotationValueComponent
  565. [[nodiscard]] bool parse_annotation_value_component()
  566. {
  567. // AnnotationValueComponent :::
  568. // Alpha AnnotationValueComponent[opt]
  569. // DecimalDigit AnnotationValueComponent[opt]
  570. auto parse_component = [&]() { return parse_alpha() || parse_decimal_digit(); };
  571. if (!parse_component())
  572. return false;
  573. while (parse_component())
  574. ;
  575. return true;
  576. }
  577. // https://tc39.es/proposal-temporal/#prod-UTCOffset
  578. [[nodiscard]] bool parse_utc_offset(SubMinutePrecision sub_minute_precision, Optional<TimeZoneOffset>& result)
  579. {
  580. StateTransaction transaction { *this };
  581. TimeZoneOffset time_zone_offset;
  582. auto parse_utc_sign = [&]() {
  583. return scoped_parse(time_zone_offset.sign, [&]() { return parse_ascii_sign(); });
  584. };
  585. auto parse_utc_hours = [&]() {
  586. return scoped_parse(time_zone_offset.hours, [&]() { return parse_hour(); });
  587. };
  588. auto parse_utc_minutes = [&]() {
  589. return scoped_parse(time_zone_offset.minutes, [&]() { return parse_minute_second(); });
  590. };
  591. auto parse_utc_seconds = [&]() {
  592. return scoped_parse(time_zone_offset.seconds, [&]() { return parse_minute_second(); });
  593. };
  594. auto parse_utc_fraction = [&]() {
  595. return scoped_parse(time_zone_offset.fraction, [&]() { return parse_temporal_decimal_fraction(); });
  596. };
  597. // UTCOffset[SubMinutePrecision] :::
  598. // ASCIISign Hour
  599. // ASCIISign Hour TimeSeparator[+Extended] MinuteSecond
  600. // ASCIISign Hour TimeSeparator[~Extended] MinuteSecond
  601. // [+SubMinutePrecision] ASCIISign Hour TimeSeparator[+Extended] MinuteSecond TimeSeparator[+Extended] MinuteSecond TemporalDecimalFraction[opt]
  602. // [+SubMinutePrecision] ASCIISign Hour TimeSeparator[~Extended] MinuteSecond TimeSeparator[~Extended] MinuteSecond TemporalDecimalFraction[opt]
  603. if (!parse_utc_sign())
  604. return false;
  605. if (!parse_utc_hours())
  606. return false;
  607. if (parse_time_separator(Extended::Yes)) {
  608. if (!parse_utc_minutes())
  609. return false;
  610. if (sub_minute_precision == SubMinutePrecision::Yes && parse_time_separator(Extended::Yes)) {
  611. if (!parse_utc_seconds())
  612. return false;
  613. (void)parse_utc_fraction();
  614. }
  615. } else if (parse_utc_minutes()) {
  616. if (sub_minute_precision == SubMinutePrecision::Yes && parse_utc_seconds())
  617. (void)parse_utc_fraction();
  618. }
  619. time_zone_offset.source_text = transaction.parsed_string_view();
  620. result = move(time_zone_offset);
  621. transaction.commit();
  622. return true;
  623. }
  624. // https://tc39.es/ecma262/#prod-Hour
  625. [[nodiscard]] bool parse_hour()
  626. {
  627. // Hour :::
  628. // 0 DecimalDigit
  629. // 1 DecimalDigit
  630. // 20
  631. // 21
  632. // 22
  633. // 23
  634. if (m_state.lexer.consume_specific('0') || m_state.lexer.consume_specific('1')) {
  635. if (!parse_decimal_digit())
  636. return false;
  637. } else {
  638. auto success = m_state.lexer.consume_specific("20"sv)
  639. || m_state.lexer.consume_specific("21"sv)
  640. || m_state.lexer.consume_specific("22"sv)
  641. || m_state.lexer.consume_specific("23"sv);
  642. if (!success)
  643. return false;
  644. }
  645. return true;
  646. }
  647. // https://tc39.es/ecma262/#prod-MinuteSecond
  648. [[nodiscard]] bool parse_minute_second()
  649. {
  650. // MinuteSecond :::
  651. // 0 DecimalDigit
  652. // 1 DecimalDigit
  653. // 2 DecimalDigit
  654. // 3 DecimalDigit
  655. // 4 DecimalDigit
  656. // 5 DecimalDigit
  657. auto success = m_state.lexer.consume_specific('0')
  658. || m_state.lexer.consume_specific('1')
  659. || m_state.lexer.consume_specific('2')
  660. || m_state.lexer.consume_specific('3')
  661. || m_state.lexer.consume_specific('4')
  662. || m_state.lexer.consume_specific('5');
  663. if (!success)
  664. return false;
  665. if (!parse_decimal_digit())
  666. return false;
  667. return true;
  668. }
  669. // https://tc39.es/proposal-temporal/#prod-DurationDate
  670. [[nodiscard]] bool parse_duration_date()
  671. {
  672. // DurationDate :::
  673. // DurationYearsPart DurationTime[opt]
  674. // DurationMonthsPart DurationTime[opt]
  675. // DurationWeeksPart DurationTime[opt]
  676. // DurationDaysPart DurationTime[opt]
  677. auto success = parse_duration_years_part() || parse_duration_months_part() || parse_duration_weeks_part() || parse_duration_days_part();
  678. if (!success)
  679. return false;
  680. (void)parse_duration_time();
  681. return true;
  682. }
  683. // https://tc39.es/proposal-temporal/#prod-Duration
  684. [[nodiscard]] bool parse_duration()
  685. {
  686. StateTransaction transaction { *this };
  687. // Duration :::
  688. // ASCIISign[opt] DurationDesignator DurationDate
  689. // ASCIISign[opt] DurationDesignator DurationTime
  690. (void)scoped_parse(m_state.parse_result.sign, [&]() { return parse_ascii_sign(); });
  691. if (!parse_duration_designator())
  692. return false;
  693. auto success = parse_duration_date() || parse_duration_time();
  694. if (!success)
  695. return false;
  696. transaction.commit();
  697. return true;
  698. }
  699. // https://tc39.es/proposal-temporal/#prod-DurationYearsPart
  700. [[nodiscard]] bool parse_duration_years_part()
  701. {
  702. StateTransaction transaction { *this };
  703. // DurationYearsPart :::
  704. // DecimalDigits[~Sep] YearsDesignator DurationMonthsPart
  705. // DecimalDigits[~Sep] YearsDesignator DurationWeeksPart
  706. // DecimalDigits[~Sep] YearsDesignator DurationDaysPart[opt]
  707. if (!parse_decimal_digits(Separator::No, m_state.parse_result.duration_years))
  708. return false;
  709. if (!parse_years_designator())
  710. return false;
  711. (void)(parse_duration_months_part() || parse_duration_weeks_part() || parse_duration_days_part());
  712. transaction.commit();
  713. return true;
  714. }
  715. // https://tc39.es/proposal-temporal/#prod-DurationMonthsPart
  716. [[nodiscard]] bool parse_duration_months_part()
  717. {
  718. StateTransaction transaction { *this };
  719. // DurationMonthsPart :::
  720. // DecimalDigits[~Sep] MonthsDesignator DurationWeeksPart
  721. // DecimalDigits[~Sep] MonthsDesignator DurationDaysPart[opt]
  722. if (!parse_decimal_digits(Separator::No, m_state.parse_result.duration_months))
  723. return false;
  724. if (!parse_months_designator())
  725. return false;
  726. (void)(parse_duration_weeks_part() || parse_duration_days_part());
  727. transaction.commit();
  728. return true;
  729. }
  730. // https://tc39.es/proposal-temporal/#prod-DurationWeeksPart
  731. [[nodiscard]] bool parse_duration_weeks_part()
  732. {
  733. StateTransaction transaction { *this };
  734. // DurationWeeksPart :::
  735. // DecimalDigits[~Sep] WeeksDesignator DurationDaysPart[opt]
  736. if (!parse_decimal_digits(Separator::No, m_state.parse_result.duration_weeks))
  737. return false;
  738. if (!parse_weeks_designator())
  739. return false;
  740. (void)parse_duration_days_part();
  741. transaction.commit();
  742. return true;
  743. }
  744. // https://tc39.es/proposal-temporal/#prod-DurationDaysPart
  745. [[nodiscard]] bool parse_duration_days_part()
  746. {
  747. StateTransaction transaction { *this };
  748. // DurationDaysPart :::
  749. // DecimalDigits[~Sep] DaysDesignator
  750. if (!parse_decimal_digits(Separator::No, m_state.parse_result.duration_days))
  751. return false;
  752. if (!parse_days_designator())
  753. return false;
  754. transaction.commit();
  755. return true;
  756. }
  757. // https://tc39.es/proposal-temporal/#prod-DurationTime
  758. [[nodiscard]] bool parse_duration_time()
  759. {
  760. StateTransaction transaction { *this };
  761. // DurationTime :::
  762. // TimeDesignator DurationHoursPart
  763. // TimeDesignator DurationMinutesPart
  764. // TimeDesignator DurationSecondsPart
  765. if (!parse_time_designator())
  766. return false;
  767. auto success = parse_duration_hours_part() || parse_duration_minutes_part() || parse_duration_seconds_part();
  768. if (!success)
  769. return false;
  770. transaction.commit();
  771. return true;
  772. }
  773. // https://tc39.es/proposal-temporal/#prod-DurationHoursPart
  774. [[nodiscard]] bool parse_duration_hours_part()
  775. {
  776. StateTransaction transaction { *this };
  777. // DurationHoursPart :::
  778. // DecimalDigits[~Sep] TemporalDecimalFraction HoursDesignator
  779. // DecimalDigits[~Sep] HoursDesignator DurationMinutesPart
  780. // DecimalDigits[~Sep] HoursDesignator DurationSecondsPart[opt]
  781. if (!parse_decimal_digits(Separator::No, m_state.parse_result.duration_hours))
  782. return false;
  783. auto is_fractional = scoped_parse(m_state.parse_result.duration_hours_fraction, [&]() { return parse_temporal_decimal_fraction(); });
  784. if (!parse_hours_designator())
  785. return false;
  786. if (!is_fractional)
  787. (void)(parse_duration_minutes_part() || parse_duration_seconds_part());
  788. transaction.commit();
  789. return true;
  790. }
  791. // https://tc39.es/proposal-temporal/#prod-DurationMinutesPart
  792. [[nodiscard]] bool parse_duration_minutes_part()
  793. {
  794. StateTransaction transaction { *this };
  795. // DurationMinutesPart :::
  796. // DecimalDigits[~Sep] TemporalDecimalFraction MinutesDesignator
  797. // DecimalDigits[~Sep] MinutesDesignator DurationSecondsPart[opt]
  798. if (!parse_decimal_digits(Separator::No, m_state.parse_result.duration_minutes))
  799. return false;
  800. auto is_fractional = scoped_parse(m_state.parse_result.duration_minutes_fraction, [&]() { return parse_temporal_decimal_fraction(); });
  801. if (!parse_minutes_designator())
  802. return false;
  803. if (!is_fractional)
  804. (void)parse_duration_seconds_part();
  805. transaction.commit();
  806. return true;
  807. }
  808. // https://tc39.es/proposal-temporal/#prod-DurationSecondsPart
  809. [[nodiscard]] bool parse_duration_seconds_part()
  810. {
  811. StateTransaction transaction { *this };
  812. // DurationSecondsPart :::
  813. // DecimalDigits[~Sep] TemporalDecimalFraction[opt] SecondsDesignator
  814. if (!parse_decimal_digits(Separator::No, m_state.parse_result.duration_seconds))
  815. return false;
  816. (void)scoped_parse(m_state.parse_result.duration_seconds_fraction, [&]() { return parse_temporal_decimal_fraction(); });
  817. if (!parse_seconds_designator())
  818. return false;
  819. transaction.commit();
  820. return true;
  821. }
  822. // https://tc39.es/ecma262/#prod-TemporalDecimalFraction
  823. [[nodiscard]] bool parse_temporal_decimal_fraction()
  824. {
  825. // TemporalDecimalFraction :::
  826. // TemporalDecimalSeparator DecimalDigit
  827. // TemporalDecimalSeparator DecimalDigit DecimalDigit
  828. // TemporalDecimalSeparator DecimalDigit DecimalDigit DecimalDigit
  829. // TemporalDecimalSeparator DecimalDigit DecimalDigit DecimalDigit DecimalDigit
  830. // TemporalDecimalSeparator DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit
  831. // TemporalDecimalSeparator DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit
  832. // TemporalDecimalSeparator DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit
  833. // TemporalDecimalSeparator DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit
  834. // TemporalDecimalSeparator DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit
  835. if (!parse_temporal_decimal_separator())
  836. return false;
  837. if (!parse_decimal_digit())
  838. return false;
  839. for (size_t i = 0; i < 8; ++i) {
  840. if (!parse_decimal_digit())
  841. break;
  842. }
  843. return true;
  844. }
  845. // https://tc39.es/proposal-temporal/#prod-Alpha
  846. [[nodiscard]] bool parse_alpha()
  847. {
  848. // Alpha ::: one of
  849. // A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z
  850. if (m_state.lexer.next_is(is_ascii_alpha)) {
  851. m_state.lexer.consume();
  852. return true;
  853. }
  854. return false;
  855. }
  856. // https://tc39.es/proposal-temporal/#prod-LowercaseAlpha
  857. [[nodiscard]] bool parse_lowercase_alpha()
  858. {
  859. // LowercaseAlpha ::: one of
  860. // a b c d e f g h i j k l m n o p q r s t u v w x y z
  861. if (m_state.lexer.next_is(is_ascii_lower_alpha)) {
  862. m_state.lexer.consume();
  863. return true;
  864. }
  865. return false;
  866. }
  867. // https://tc39.es/ecma262/#prod-DecimalDigit
  868. [[nodiscard]] bool parse_decimal_digit()
  869. {
  870. // DecimalDigit : one of
  871. // 0 1 2 3 4 5 6 7 8 9
  872. if (m_state.lexer.next_is(is_ascii_digit)) {
  873. m_state.lexer.consume();
  874. return true;
  875. }
  876. return false;
  877. }
  878. // https://tc39.es/ecma262/#prod-DecimalDigits
  879. [[nodiscard]] bool parse_decimal_digits(Separator separator, Optional<StringView>& result)
  880. {
  881. StateTransaction transaction { *this };
  882. // FIXME: Implement [+Sep] if it's ever needed.
  883. VERIFY(separator == Separator::No);
  884. // DecimalDigits[Sep] ::
  885. // DecimalDigit
  886. // DecimalDigits[?Sep] DecimalDigit
  887. // [+Sep] DecimalDigits[+Sep] NumericLiteralSeparator DecimalDigit
  888. if (!parse_decimal_digit())
  889. return {};
  890. while (parse_decimal_digit())
  891. ;
  892. result = transaction.parsed_string_view();
  893. transaction.commit();
  894. return true;
  895. }
  896. // https://tc39.es/ecma262/#prod-NonZeroDigit
  897. [[nodiscard]] bool parse_non_zero_digit()
  898. {
  899. // NonZeroDigit : one of
  900. // 1 2 3 4 5 6 7 8 9
  901. if (m_state.lexer.next_is(is_ascii_digit) && !m_state.lexer.next_is('0')) {
  902. m_state.lexer.consume();
  903. return true;
  904. }
  905. return false;
  906. }
  907. // https://tc39.es/ecma262/#prod-ASCIISign
  908. [[nodiscard]] bool parse_ascii_sign()
  909. {
  910. // ASCIISign : one of
  911. // + -
  912. return m_state.lexer.consume_specific('+') || m_state.lexer.consume_specific('-');
  913. }
  914. // https://tc39.es/proposal-temporal/#prod-DateSeparator
  915. [[nodiscard]] bool parse_date_separator(Extended extended)
  916. {
  917. // DateSeparator[Extended] :::
  918. // [+Extended] -
  919. // [~Extended] [empty]
  920. if (extended == Extended::Yes)
  921. return m_state.lexer.consume_specific('-');
  922. return true;
  923. }
  924. // https://tc39.es/ecma262/#prod-TimeSeparator
  925. [[nodiscard]] bool parse_time_separator(Extended extended)
  926. {
  927. // TimeSeparator[Extended] :::
  928. // [+Extended] :
  929. // [~Extended] [empty]
  930. if (extended == Extended::Yes)
  931. return m_state.lexer.consume_specific(':');
  932. return true;
  933. }
  934. // https://tc39.es/proposal-temporal/#prod-TimeDesignator
  935. [[nodiscard]] bool parse_time_designator()
  936. {
  937. // TimeDesignator : one of
  938. // T t
  939. return m_state.lexer.consume_specific('T') || m_state.lexer.consume_specific('t');
  940. }
  941. // https://tc39.es/proposal-temporal/#prod-DateTimeSeparator
  942. [[nodiscard]] bool parse_date_time_separator()
  943. {
  944. // DateTimeSeparator :::
  945. // <SP>
  946. // T
  947. // t
  948. return m_state.lexer.consume_specific(' ') || m_state.lexer.consume_specific('T') || m_state.lexer.consume_specific('t');
  949. }
  950. // https://tc39.es/ecma262/#prod-TemporalDecimalSeparator
  951. [[nodiscard]] bool parse_temporal_decimal_separator()
  952. {
  953. // TemporalDecimalSeparator ::: one of
  954. // . ,
  955. return m_state.lexer.consume_specific('.') || m_state.lexer.consume_specific(',');
  956. }
  957. // https://tc39.es/proposal-temporal/#prod-DurationDesignator
  958. [[nodiscard]] bool parse_duration_designator()
  959. {
  960. // DurationDesignator : one of
  961. // P p
  962. return m_state.lexer.consume_specific('P') || m_state.lexer.consume_specific('p');
  963. }
  964. // https://tc39.es/proposal-temporal/#prod-YearsDesignator
  965. [[nodiscard]] bool parse_years_designator()
  966. {
  967. // YearsDesignator : one of
  968. // Y y
  969. return m_state.lexer.consume_specific('Y') || m_state.lexer.consume_specific('y');
  970. }
  971. // https://tc39.es/proposal-temporal/#prod-MonthsDesignator
  972. [[nodiscard]] bool parse_months_designator()
  973. {
  974. // MonthsDesignator : one of
  975. // M m
  976. return m_state.lexer.consume_specific('M') || m_state.lexer.consume_specific('m');
  977. }
  978. // https://tc39.es/proposal-temporal/#prod-WeeksDesignator
  979. [[nodiscard]] bool parse_weeks_designator()
  980. {
  981. // WeeksDesignator : one of
  982. // W w
  983. return m_state.lexer.consume_specific('W') || m_state.lexer.consume_specific('w');
  984. }
  985. // https://tc39.es/proposal-temporal/#prod-DaysDesignator
  986. [[nodiscard]] bool parse_days_designator()
  987. {
  988. // DaysDesignator : one of
  989. // D d
  990. return m_state.lexer.consume_specific('D') || m_state.lexer.consume_specific('d');
  991. }
  992. // https://tc39.es/proposal-temporal/#prod-HoursDesignator
  993. [[nodiscard]] bool parse_hours_designator()
  994. {
  995. // HoursDesignator : one of
  996. // H h
  997. return m_state.lexer.consume_specific('H') || m_state.lexer.consume_specific('h');
  998. }
  999. // https://tc39.es/proposal-temporal/#prod-MinutesDesignator
  1000. [[nodiscard]] bool parse_minutes_designator()
  1001. {
  1002. // MinutesDesignator : one of
  1003. // M m
  1004. return m_state.lexer.consume_specific('M') || m_state.lexer.consume_specific('m');
  1005. }
  1006. // https://tc39.es/proposal-temporal/#prod-SecondsDesignator
  1007. [[nodiscard]] bool parse_seconds_designator()
  1008. {
  1009. // SecondsDesignator : one of
  1010. // S s
  1011. return m_state.lexer.consume_specific('S') || m_state.lexer.consume_specific('s');
  1012. }
  1013. // https://tc39.es/proposal-temporal/#prod-UTCDesignator
  1014. [[nodiscard]] bool parse_utc_designator()
  1015. {
  1016. StateTransaction transaction { *this };
  1017. // UTCDesignator : one of
  1018. // Z z
  1019. auto success = m_state.lexer.consume_specific('Z') || m_state.lexer.consume_specific('z');
  1020. if (!success)
  1021. return false;
  1022. m_state.parse_result.utc_designator = transaction.parsed_string_view();
  1023. transaction.commit();
  1024. return true;
  1025. }
  1026. // https://tc39.es/proposal-temporal/#prod-AnnotationCriticalFlag
  1027. [[nodiscard]] bool parse_annotation_critical_flag()
  1028. {
  1029. // AnnotationCriticalFlag :::
  1030. // !
  1031. return m_state.lexer.consume_specific('!');
  1032. }
  1033. private:
  1034. template<typename Parser, typename T>
  1035. [[nodiscard]] bool scoped_parse(Optional<T>& storage, Parser&& parser)
  1036. {
  1037. StateTransaction transaction { *this };
  1038. if (!parser())
  1039. return false;
  1040. if constexpr (IsSame<T, char>)
  1041. storage = transaction.parsed_string_view()[0];
  1042. else
  1043. storage = transaction.parsed_string_view();
  1044. transaction.commit();
  1045. return true;
  1046. }
  1047. struct State {
  1048. GenericLexer lexer;
  1049. ParseResult parse_result;
  1050. };
  1051. struct StateTransaction {
  1052. explicit StateTransaction(ISO8601Parser& parser)
  1053. : m_parser(parser)
  1054. , m_saved_state(parser.m_state)
  1055. , m_start_index(parser.m_state.lexer.tell())
  1056. {
  1057. }
  1058. ~StateTransaction()
  1059. {
  1060. if (!m_commit)
  1061. m_parser.m_state = move(m_saved_state);
  1062. }
  1063. void commit() { m_commit = true; }
  1064. StringView parsed_string_view() const
  1065. {
  1066. return m_parser.m_input.substring_view(m_start_index, m_parser.m_state.lexer.tell() - m_start_index);
  1067. }
  1068. private:
  1069. ISO8601Parser& m_parser;
  1070. State m_saved_state;
  1071. size_t m_start_index { 0 };
  1072. bool m_commit { false };
  1073. };
  1074. StringView m_input;
  1075. State m_state;
  1076. };
  1077. #define JS_ENUMERATE_ISO8601_PRODUCTION_PARSERS \
  1078. __JS_ENUMERATE(AnnotationValue, parse_annotation_value) \
  1079. __JS_ENUMERATE(DateMonth, parse_date_month) \
  1080. __JS_ENUMERATE(TemporalDateTimeString, parse_temporal_date_time_string) \
  1081. __JS_ENUMERATE(TemporalDurationString, parse_temporal_duration_string) \
  1082. __JS_ENUMERATE(TemporalInstantString, parse_temporal_instant_string) \
  1083. __JS_ENUMERATE(TemporalMonthDayString, parse_temporal_month_day_string) \
  1084. __JS_ENUMERATE(TemporalTimeString, parse_temporal_time_string) \
  1085. __JS_ENUMERATE(TemporalYearMonthString, parse_temporal_year_month_string) \
  1086. __JS_ENUMERATE(TemporalZonedDateTimeString, parse_temporal_zoned_date_time_string) \
  1087. __JS_ENUMERATE(TimeZoneIdentifier, parse_time_zone_identifier)
  1088. Optional<ParseResult> parse_iso8601(Production production, StringView input)
  1089. {
  1090. ISO8601Parser parser { input };
  1091. switch (production) {
  1092. #define __JS_ENUMERATE(ProductionName, parse_production) \
  1093. case Production::ProductionName: \
  1094. if (!parser.parse_production()) \
  1095. return {}; \
  1096. break;
  1097. JS_ENUMERATE_ISO8601_PRODUCTION_PARSERS
  1098. #undef __JS_ENUMERATE
  1099. default:
  1100. VERIFY_NOT_REACHED();
  1101. }
  1102. // If we parsed successfully but didn't reach the end, the string doesn't match the given production.
  1103. if (!parser.lexer().is_eof())
  1104. return {};
  1105. return parser.parse_result();
  1106. }
  1107. Optional<TimeZoneOffset> parse_utc_offset(StringView input, SubMinutePrecision sub_minute_precision)
  1108. {
  1109. ISO8601Parser parser { input };
  1110. Optional<TimeZoneOffset> utc_offset;
  1111. if (!parser.parse_utc_offset(sub_minute_precision, utc_offset))
  1112. return {};
  1113. // If we parsed successfully but didn't reach the end, the string doesn't match the given production.
  1114. if (!parser.lexer().is_eof())
  1115. return {};
  1116. return utc_offset;
  1117. }
  1118. }