ISO8601.cpp 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339
  1. /*
  2. * Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/CharacterTypes.h>
  7. #include <LibJS/Runtime/Temporal/ISO8601.h>
  8. namespace JS::Temporal {
  9. namespace Detail {
  10. // https://tc39.es/proposal-temporal/#prod-DecimalDigits
  11. bool ISO8601Parser::parse_decimal_digits()
  12. {
  13. // DecimalDigits[Sep] ::
  14. // DecimalDigit
  15. // DecimalDigits[?Sep] DecimalDigit
  16. // [+Sep] DecimalDigits[+Sep] NumericLiteralSeparator DecimalDigit
  17. // NOTE: Temporal exclusively uses the variant without a separator ([~Sep])
  18. if (!parse_decimal_digit())
  19. return false;
  20. while (parse_decimal_digit())
  21. ;
  22. return true;
  23. }
  24. // https://tc39.es/proposal-temporal/#prod-DecimalDigit
  25. bool ISO8601Parser::parse_decimal_digit()
  26. {
  27. // DecimalDigit : one of
  28. // 0 1 2 3 4 5 6 7 8 9
  29. if (m_state.lexer.next_is(is_ascii_digit)) {
  30. m_state.lexer.consume();
  31. return true;
  32. }
  33. return false;
  34. }
  35. // https://tc39.es/proposal-temporal/#prod-NonZeroDigit
  36. bool ISO8601Parser::parse_non_zero_digit()
  37. {
  38. // NonZeroDigit : one of
  39. // 1 2 3 4 5 6 7 8 9
  40. if (m_state.lexer.next_is(is_ascii_digit) && !m_state.lexer.next_is('0')) {
  41. m_state.lexer.consume();
  42. return true;
  43. }
  44. return false;
  45. }
  46. // https://tc39.es/proposal-temporal/#prod-ASCIISign
  47. bool ISO8601Parser::parse_ascii_sign()
  48. {
  49. // ASCIISign : one of
  50. // + -
  51. return m_state.lexer.consume_specific('+')
  52. || m_state.lexer.consume_specific('-');
  53. }
  54. // https://tc39.es/proposal-temporal/#prod-Sign
  55. bool ISO8601Parser::parse_sign()
  56. {
  57. // Sign :
  58. // ASCIISign
  59. // U+2212
  60. StateTransaction transaction { *this };
  61. auto success = parse_ascii_sign()
  62. || m_state.lexer.consume_specific("\xE2\x88\x92"sv);
  63. if (!success)
  64. return false;
  65. m_state.parse_result.sign = transaction.parsed_string_view();
  66. transaction.commit();
  67. return true;
  68. }
  69. // https://tc39.es/proposal-temporal/#prod-Hour
  70. bool ISO8601Parser::parse_hour()
  71. {
  72. // Hour :
  73. // 0 DecimalDigit
  74. // 1 DecimalDigit
  75. // 20
  76. // 21
  77. // 22
  78. // 23
  79. StateTransaction transaction { *this };
  80. if (m_state.lexer.consume_specific('0') || m_state.lexer.consume_specific('1')) {
  81. if (!parse_decimal_digit())
  82. return false;
  83. } else {
  84. auto success = m_state.lexer.consume_specific("20"sv)
  85. || m_state.lexer.consume_specific("21"sv)
  86. || m_state.lexer.consume_specific("22"sv)
  87. || m_state.lexer.consume_specific("23"sv);
  88. if (!success)
  89. return false;
  90. }
  91. transaction.commit();
  92. return true;
  93. }
  94. // https://tc39.es/proposal-temporal/#prod-MinuteSecond
  95. bool ISO8601Parser::parse_minute_second()
  96. {
  97. // MinuteSecond :
  98. // 0 DecimalDigit
  99. // 1 DecimalDigit
  100. // 2 DecimalDigit
  101. // 3 DecimalDigit
  102. // 4 DecimalDigit
  103. // 5 DecimalDigit
  104. StateTransaction transaction { *this };
  105. auto success = m_state.lexer.consume_specific('0')
  106. || m_state.lexer.consume_specific('1')
  107. || m_state.lexer.consume_specific('2')
  108. || m_state.lexer.consume_specific('3')
  109. || m_state.lexer.consume_specific('4')
  110. || m_state.lexer.consume_specific('5');
  111. if (!success)
  112. return false;
  113. if (!parse_decimal_digit())
  114. return false;
  115. transaction.commit();
  116. return true;
  117. }
  118. // https://tc39.es/proposal-temporal/#prod-DecimalSeparator
  119. bool ISO8601Parser::parse_decimal_separator()
  120. {
  121. // DecimalSeparator : one of
  122. // . ,
  123. return m_state.lexer.consume_specific('.')
  124. || m_state.lexer.consume_specific(',');
  125. }
  126. // https://tc39.es/proposal-temporal/#prod-DaysDesignator
  127. bool ISO8601Parser::parse_days_designator()
  128. {
  129. // DaysDesignator : one of
  130. // D d
  131. return m_state.lexer.consume_specific('D')
  132. || m_state.lexer.consume_specific('d');
  133. }
  134. // https://tc39.es/proposal-temporal/#prod-HoursDesignator
  135. bool ISO8601Parser::parse_hours_designator()
  136. {
  137. // HoursDesignator : one of
  138. // H h
  139. return m_state.lexer.consume_specific('H')
  140. || m_state.lexer.consume_specific('h');
  141. }
  142. // https://tc39.es/proposal-temporal/#prod-MinutesDesignator
  143. bool ISO8601Parser::parse_minutes_designator()
  144. {
  145. // MinutesDesignator : one of
  146. // M m
  147. return m_state.lexer.consume_specific('M')
  148. || m_state.lexer.consume_specific('m');
  149. }
  150. // https://tc39.es/proposal-temporal/#prod-MonthsDesignator
  151. bool ISO8601Parser::parse_months_designator()
  152. {
  153. // MonthsDesignator : one of
  154. // M m
  155. return m_state.lexer.consume_specific('M')
  156. || m_state.lexer.consume_specific('m');
  157. }
  158. // https://tc39.es/proposal-temporal/#prod-DurationDesignator
  159. bool ISO8601Parser::parse_duration_designator()
  160. {
  161. // DurationDesignator : one of
  162. // P p
  163. return m_state.lexer.consume_specific('P')
  164. || m_state.lexer.consume_specific('p');
  165. }
  166. // https://tc39.es/proposal-temporal/#prod-SecondsDesignator
  167. bool ISO8601Parser::parse_seconds_designator()
  168. {
  169. // SecondsDesignator : one of
  170. // S s
  171. return m_state.lexer.consume_specific('S')
  172. || m_state.lexer.consume_specific('s');
  173. }
  174. // https://tc39.es/proposal-temporal/#prod-DateTimeSeparator
  175. bool ISO8601Parser::parse_date_time_separator()
  176. {
  177. // DateTimeSeparator :
  178. // <SP>
  179. // T
  180. // t
  181. return m_state.lexer.consume_specific(' ')
  182. || m_state.lexer.consume_specific('T')
  183. || m_state.lexer.consume_specific('t');
  184. }
  185. // https://tc39.es/proposal-temporal/#prod-TimeDesignator
  186. bool ISO8601Parser::parse_time_designator()
  187. {
  188. // TimeDesignator : one of
  189. // T t
  190. return m_state.lexer.consume_specific('T')
  191. || m_state.lexer.consume_specific('t');
  192. }
  193. // https://tc39.es/proposal-temporal/#prod-WeeksDesignator
  194. bool ISO8601Parser::parse_weeks_designator()
  195. {
  196. // WeeksDesignator : one of
  197. // W w
  198. return m_state.lexer.consume_specific('W')
  199. || m_state.lexer.consume_specific('w');
  200. }
  201. // https://tc39.es/proposal-temporal/#prod-YearsDesignator
  202. bool ISO8601Parser::parse_years_designator()
  203. {
  204. // YearsDesignator : one of
  205. // Y y
  206. return m_state.lexer.consume_specific('Y')
  207. || m_state.lexer.consume_specific('y');
  208. }
  209. // https://tc39.es/proposal-temporal/#prod-UTCDesignator
  210. bool ISO8601Parser::parse_utc_designator()
  211. {
  212. // UTCDesignator : one of
  213. // Z z
  214. StateTransaction transaction { *this };
  215. auto success = m_state.lexer.consume_specific('Z')
  216. || m_state.lexer.consume_specific('z');
  217. if (!success)
  218. return false;
  219. m_state.parse_result.utc_designator = transaction.parsed_string_view();
  220. transaction.commit();
  221. return true;
  222. }
  223. // https://tc39.es/proposal-temporal/#prod-DateYear
  224. bool ISO8601Parser::parse_date_year()
  225. {
  226. // DateFourDigitYear :
  227. // DecimalDigit DecimalDigit DecimalDigit DecimalDigit
  228. // DateExtendedYear :
  229. // Sign DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit
  230. // DateYear :
  231. // DateFourDigitYear
  232. // DateExtendedYear
  233. StateTransaction transaction { *this };
  234. if (parse_sign()) {
  235. for (size_t i = 0; i < 6; ++i) {
  236. if (!parse_decimal_digit())
  237. return false;
  238. }
  239. } else {
  240. for (size_t i = 0; i < 4; ++i) {
  241. if (!parse_decimal_digit())
  242. return false;
  243. }
  244. }
  245. m_state.parse_result.date_year = transaction.parsed_string_view();
  246. transaction.commit();
  247. return true;
  248. }
  249. // https://tc39.es/proposal-temporal/#prod-DateMonth
  250. bool ISO8601Parser::parse_date_month()
  251. {
  252. // DateMonth :
  253. // 0 NonZeroDigit
  254. // 10
  255. // 11
  256. // 12
  257. StateTransaction transaction { *this };
  258. if (m_state.lexer.consume_specific('0')) {
  259. if (!parse_non_zero_digit())
  260. return false;
  261. } else {
  262. auto success = m_state.lexer.consume_specific("10"sv)
  263. || m_state.lexer.consume_specific("11"sv)
  264. || m_state.lexer.consume_specific("12"sv);
  265. if (!success)
  266. return false;
  267. }
  268. m_state.parse_result.date_month = transaction.parsed_string_view();
  269. transaction.commit();
  270. return true;
  271. }
  272. // https://tc39.es/proposal-temporal/#prod-DateDay
  273. bool ISO8601Parser::parse_date_day()
  274. {
  275. // DateDay :
  276. // 0 NonZeroDigit
  277. // 1 DecimalDigit
  278. // 2 DecimalDigit
  279. // 30
  280. // 31
  281. StateTransaction transaction { *this };
  282. if (m_state.lexer.consume_specific('0')) {
  283. if (!parse_non_zero_digit())
  284. return false;
  285. } else if (m_state.lexer.consume_specific('1') || m_state.lexer.consume_specific('2')) {
  286. if (!parse_decimal_digit())
  287. return false;
  288. } else {
  289. auto success = m_state.lexer.consume_specific("30"sv)
  290. || m_state.lexer.consume_specific("31"sv);
  291. if (!success)
  292. return false;
  293. }
  294. m_state.parse_result.date_day = transaction.parsed_string_view();
  295. transaction.commit();
  296. return true;
  297. }
  298. // https://tc39.es/proposal-temporal/#prod-DateSpecYearMonth
  299. bool ISO8601Parser::parse_date_spec_year_month()
  300. {
  301. // DateSpecYearMonth :
  302. // DateYear -[opt] DateMonth
  303. StateTransaction transaction { *this };
  304. if (!parse_date_year())
  305. return false;
  306. m_state.lexer.consume_specific('-');
  307. if (!parse_date_month())
  308. return false;
  309. transaction.commit();
  310. return true;
  311. }
  312. // https://tc39.es/proposal-temporal/#prod-DateSpecMonthDay
  313. bool ISO8601Parser::parse_date_spec_month_day()
  314. {
  315. // TwoDashes :
  316. // --
  317. // DateSpecMonthDay :
  318. // TwoDashes[opt] DateMonth -[opt] DateDay
  319. StateTransaction transaction { *this };
  320. m_state.lexer.consume_specific("--"sv);
  321. if (!parse_date_month())
  322. return false;
  323. m_state.lexer.consume_specific('-');
  324. if (!parse_date_day())
  325. return false;
  326. transaction.commit();
  327. return true;
  328. }
  329. // https://tc39.es/proposal-temporal/#prod-Date
  330. bool ISO8601Parser::parse_date()
  331. {
  332. // Date :
  333. // DateYear - DateMonth - DateDay
  334. // DateYear DateMonth DateDay
  335. StateTransaction transaction { *this };
  336. if (!parse_date_year())
  337. return false;
  338. auto with_dashes = m_state.lexer.consume_specific('-');
  339. if (!parse_date_month())
  340. return false;
  341. if (with_dashes && !m_state.lexer.consume_specific('-'))
  342. return false;
  343. if (!parse_date_day())
  344. return false;
  345. transaction.commit();
  346. return true;
  347. }
  348. // https://tc39.es/proposal-temporal/#prod-TimeHour
  349. bool ISO8601Parser::parse_time_hour()
  350. {
  351. // TimeHour :
  352. // Hour
  353. StateTransaction transaction { *this };
  354. if (!parse_hour())
  355. return false;
  356. m_state.parse_result.time_hour = transaction.parsed_string_view();
  357. transaction.commit();
  358. return true;
  359. }
  360. // https://tc39.es/proposal-temporal/#prod-TimeMinute
  361. bool ISO8601Parser::parse_time_minute()
  362. {
  363. // TimeMinute :
  364. // MinuteSecond
  365. StateTransaction transaction { *this };
  366. if (!parse_minute_second())
  367. return false;
  368. m_state.parse_result.time_minute = transaction.parsed_string_view();
  369. transaction.commit();
  370. return true;
  371. }
  372. // https://tc39.es/proposal-temporal/#prod-TimeSecond
  373. bool ISO8601Parser::parse_time_second()
  374. {
  375. // TimeSecond :
  376. // MinuteSecond
  377. // 60
  378. StateTransaction transaction { *this };
  379. auto success = parse_minute_second()
  380. || m_state.lexer.consume_specific("60"sv);
  381. if (!success)
  382. return false;
  383. m_state.parse_result.time_second = transaction.parsed_string_view();
  384. transaction.commit();
  385. return true;
  386. }
  387. // https://tc39.es/proposal-temporal/#prod-FractionalPart
  388. bool ISO8601Parser::parse_fractional_part()
  389. {
  390. // FractionalPart :
  391. // DecimalDigit DecimalDigit[opt] DecimalDigit[opt] DecimalDigit[opt] DecimalDigit[opt] DecimalDigit[opt] DecimalDigit[opt] DecimalDigit[opt] DecimalDigit[opt]
  392. if (!parse_decimal_digit())
  393. return false;
  394. for (size_t i = 0; i < 8; ++i) {
  395. if (!parse_decimal_digit())
  396. break;
  397. }
  398. return true;
  399. }
  400. // https://tc39.es/proposal-temporal/#prod-Fraction
  401. bool ISO8601Parser::parse_fraction()
  402. {
  403. // Fraction :
  404. // DecimalSeparator FractionalPart
  405. StateTransaction transaction { *this };
  406. if (!parse_decimal_separator())
  407. return false;
  408. if (!parse_fractional_part())
  409. return false;
  410. transaction.commit();
  411. return true;
  412. }
  413. // https://tc39.es/proposal-temporal/#prod-TimeFraction
  414. bool ISO8601Parser::parse_time_fraction()
  415. {
  416. // TimeFraction :
  417. // Fraction
  418. StateTransaction transaction { *this };
  419. if (!parse_fraction())
  420. return false;
  421. m_state.parse_result.time_fraction = transaction.parsed_string_view();
  422. transaction.commit();
  423. return true;
  424. }
  425. // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetSign
  426. bool ISO8601Parser::parse_time_zone_utc_offset_sign()
  427. {
  428. // TimeZoneUTCOffsetSign :
  429. // Sign
  430. StateTransaction transaction { *this };
  431. if (!parse_sign())
  432. return false;
  433. m_state.parse_result.time_zone_utc_offset_sign = transaction.parsed_string_view();
  434. transaction.commit();
  435. return true;
  436. }
  437. // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetHour
  438. bool ISO8601Parser::parse_time_zone_utc_offset_hour()
  439. {
  440. // TimeZoneUTCOffsetHour :
  441. // Hour
  442. StateTransaction transaction { *this };
  443. if (!parse_hour())
  444. return false;
  445. m_state.parse_result.time_zone_utc_offset_hour = transaction.parsed_string_view();
  446. transaction.commit();
  447. return true;
  448. }
  449. // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetMinute
  450. bool ISO8601Parser::parse_time_zone_utc_offset_minute()
  451. {
  452. // TimeZoneUTCOffsetMinute :
  453. // MinuteSecond
  454. StateTransaction transaction { *this };
  455. if (!parse_minute_second())
  456. return false;
  457. m_state.parse_result.time_zone_utc_offset_minute = transaction.parsed_string_view();
  458. transaction.commit();
  459. return true;
  460. }
  461. // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetSecond
  462. bool ISO8601Parser::parse_time_zone_utc_offset_second()
  463. {
  464. // TimeZoneUTCOffsetSecond :
  465. // MinuteSecond
  466. StateTransaction transaction { *this };
  467. if (!parse_minute_second())
  468. return false;
  469. m_state.parse_result.time_zone_utc_offset_second = transaction.parsed_string_view();
  470. transaction.commit();
  471. return true;
  472. }
  473. // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetFractionalPart
  474. bool ISO8601Parser::parse_time_zone_utc_offset_fractional_part()
  475. {
  476. // TimeZoneUTCOffsetFractionalPart :
  477. // FractionalPart
  478. StateTransaction transaction { *this };
  479. if (!parse_fractional_part())
  480. return false;
  481. m_state.parse_result.time_zone_utc_offset_fractional_part = transaction.parsed_string_view();
  482. transaction.commit();
  483. return true;
  484. }
  485. // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetFraction
  486. bool ISO8601Parser::parse_time_zone_utc_offset_fraction()
  487. {
  488. // TimeZoneUTCOffsetFraction :
  489. // DecimalSeparator TimeZoneUTCOffsetFractionalPart
  490. StateTransaction transaction { *this };
  491. if (!parse_decimal_separator())
  492. return false;
  493. if (!parse_time_zone_utc_offset_fractional_part())
  494. return false;
  495. transaction.commit();
  496. return true;
  497. }
  498. // https://tc39.es/proposal-temporal/#prod-TimeZoneNumericUTCOffset
  499. bool ISO8601Parser::parse_time_zone_numeric_utc_offset()
  500. {
  501. // TimeZoneNumericUTCOffset :
  502. // TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour
  503. // TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour : TimeZoneUTCOffsetMinute
  504. // TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour TimeZoneUTCOffsetMinute
  505. // TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour : TimeZoneUTCOffsetMinute : TimeZoneUTCOffsetSecond TimeZoneUTCOffsetFraction[opt]
  506. // TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour TimeZoneUTCOffsetMinute TimeZoneUTCOffsetSecond TimeZoneUTCOffsetFraction[opt]
  507. StateTransaction transaction { *this };
  508. if (!parse_time_zone_utc_offset_sign())
  509. return false;
  510. if (!parse_time_zone_utc_offset_hour())
  511. return false;
  512. if (m_state.lexer.consume_specific(':')) {
  513. if (!parse_time_zone_utc_offset_minute())
  514. return false;
  515. if (m_state.lexer.consume_specific(':')) {
  516. if (!parse_time_zone_utc_offset_second())
  517. return false;
  518. (void)parse_time_zone_utc_offset_fraction();
  519. }
  520. } else if (parse_time_zone_utc_offset_minute()) {
  521. if (parse_time_zone_utc_offset_second())
  522. (void)parse_time_zone_utc_offset_fraction();
  523. }
  524. transaction.commit();
  525. return true;
  526. }
  527. // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffset
  528. bool ISO8601Parser::parse_time_zone_utc_offset()
  529. {
  530. // TimeZoneUTCOffset :
  531. // TimeZoneNumericUTCOffset
  532. // UTCDesignator
  533. return parse_time_zone_numeric_utc_offset()
  534. || parse_utc_designator();
  535. }
  536. // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetName
  537. bool ISO8601Parser::parse_time_zone_utc_offset_name()
  538. {
  539. // TimeZoneUTCOffsetName :
  540. // Sign Hour
  541. // Sign Hour : MinuteSecond
  542. // Sign Hour MinuteSecond
  543. // Sign Hour : MinuteSecond : MinuteSecond Fraction[opt]
  544. // Sign Hour MinuteSecond MinuteSecond Fraction[opt]
  545. StateTransaction transaction { *this };
  546. if (!parse_sign())
  547. return false;
  548. if (!parse_hour())
  549. return false;
  550. if (m_state.lexer.consume_specific(':')) {
  551. if (!parse_minute_second())
  552. return false;
  553. if (m_state.lexer.consume_specific(':')) {
  554. if (!parse_minute_second())
  555. return false;
  556. (void)parse_fraction();
  557. }
  558. } else if (parse_minute_second()) {
  559. if (parse_minute_second())
  560. (void)parse_fraction();
  561. }
  562. transaction.commit();
  563. return true;
  564. }
  565. // https://tc39.es/proposal-temporal/#prod-TimeZoneIANAName
  566. bool ISO8601Parser::parse_time_zone_iana_name()
  567. {
  568. // TZLeadingChar :
  569. // Alpha
  570. // .
  571. // _
  572. // TZChar :
  573. // Alpha
  574. // .
  575. // -
  576. // _
  577. // TimeZoneIANANameComponent :
  578. // TZLeadingChar TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] TZChar[opt] but not one of . or ..
  579. // TimeZoneIANANameTail :
  580. // TimeZoneIANANameComponent
  581. // TimeZoneIANANameComponent / TimeZoneIANANameTail
  582. // TimeZoneIANAName :
  583. // TimeZoneIANANameTail
  584. StateTransaction transaction { *this };
  585. // TODO: Implement the full production. Currently, anything other than "UTC" would get rejected as unknown anyway.
  586. auto success = (m_state.lexer.consume_specific('U') || m_state.lexer.consume_specific('u'))
  587. && (m_state.lexer.consume_specific('T') || m_state.lexer.consume_specific('t'))
  588. && (m_state.lexer.consume_specific('C') || m_state.lexer.consume_specific('c'));
  589. if (!success)
  590. return false;
  591. m_state.parse_result.time_zone_iana_name = transaction.parsed_string_view();
  592. transaction.commit();
  593. return true;
  594. }
  595. // https://tc39.es/proposal-temporal/#prod-TimeZoneBracketedName
  596. bool ISO8601Parser::parse_time_zone_bracketed_name()
  597. {
  598. // TimeZoneBracketedName :
  599. // TimeZoneIANAName
  600. // Etc/GMT ASCIISign Hour
  601. // TimeZoneUTCOffsetName
  602. StateTransaction transaction { *this };
  603. if (parse_time_zone_iana_name()) {
  604. // no-op.
  605. } else if (m_state.lexer.consume_specific("Etc/GMT"sv)) {
  606. if (!parse_ascii_sign())
  607. return false;
  608. if (!parse_hour())
  609. return false;
  610. } else if (!parse_time_zone_utc_offset_name()) {
  611. return false;
  612. }
  613. transaction.commit();
  614. return true;
  615. }
  616. // https://tc39.es/proposal-temporal/#prod-TimeZoneBracketedAnnotation
  617. bool ISO8601Parser::parse_time_zone_bracketed_annotation()
  618. {
  619. // TimeZoneBracketedAnnotation :
  620. // [ TimeZoneBracketedName ]
  621. StateTransaction transaction { *this };
  622. if (!m_state.lexer.consume_specific('['))
  623. return false;
  624. if (!parse_time_zone_bracketed_name())
  625. return false;
  626. if (!m_state.lexer.consume_specific(']'))
  627. return false;
  628. transaction.commit();
  629. return true;
  630. }
  631. // https://tc39.es/proposal-temporal/#prod-TimeZoneOffsetRequired
  632. bool ISO8601Parser::parse_time_zone_offset_required()
  633. {
  634. // TimeZoneOffsetRequired :
  635. // TimeZoneUTCOffset TimeZoneBracketedAnnotation[opt]
  636. StateTransaction transaction { *this };
  637. if (!parse_time_zone_utc_offset())
  638. return false;
  639. (void)parse_time_zone_bracketed_annotation();
  640. transaction.commit();
  641. return true;
  642. }
  643. // https://tc39.es/proposal-temporal/#prod-TimeZoneNameRequired
  644. bool ISO8601Parser::parse_time_zone_name_required()
  645. {
  646. // TimeZoneNameRequired :
  647. // TimeZoneUTCOffset[opt] TimeZoneBracketedAnnotation
  648. StateTransaction transaction { *this };
  649. (void)parse_time_zone_utc_offset();
  650. if (!parse_time_zone_bracketed_annotation())
  651. return false;
  652. transaction.commit();
  653. return true;
  654. }
  655. // https://tc39.es/proposal-temporal/#prod-TimeZone
  656. bool ISO8601Parser::parse_time_zone()
  657. {
  658. // TimeZone :
  659. // TimeZoneOffsetRequired
  660. // TimeZoneNameRequired
  661. return parse_time_zone_offset_required()
  662. || parse_time_zone_name_required();
  663. }
  664. // https://tc39.es/proposal-temporal/#prod-CalendarName
  665. bool ISO8601Parser::parse_calendar_name()
  666. {
  667. // CalChar :
  668. // Alpha
  669. // DecimalDigit
  670. // CalendarNameComponent :
  671. // CalChar CalChar CalChar CalChar[opt] CalChar[opt] CalChar[opt] CalChar[opt] CalChar[opt]
  672. // CalendarNameTail :
  673. // CalendarNameComponent
  674. // CalendarNameComponent - CalendarNameTail
  675. // CalendarName :
  676. // CalendarNameTail
  677. auto parse_calendar_name_component = [&] {
  678. for (size_t i = 0; i < 8; ++i) {
  679. if (!m_state.lexer.next_is(is_ascii_alphanumeric))
  680. return i > 2;
  681. m_state.lexer.consume();
  682. }
  683. return true;
  684. };
  685. StateTransaction transaction { *this };
  686. do {
  687. if (!parse_calendar_name_component())
  688. return false;
  689. } while (m_state.lexer.consume_specific('-'));
  690. m_state.parse_result.calendar_name = transaction.parsed_string_view();
  691. transaction.commit();
  692. return true;
  693. }
  694. // https://tc39.es/proposal-temporal/#prod-Calendar
  695. bool ISO8601Parser::parse_calendar()
  696. {
  697. // Calendar :
  698. // [u-ca= CalendarName ]
  699. StateTransaction transaction { *this };
  700. if (!m_state.lexer.consume_specific("[u-ca="sv))
  701. return false;
  702. if (!parse_calendar_name())
  703. return false;
  704. if (!m_state.lexer.consume_specific(']'))
  705. return false;
  706. transaction.commit();
  707. return true;
  708. }
  709. // https://tc39.es/proposal-temporal/#prod-TimeSpec
  710. bool ISO8601Parser::parse_time_spec()
  711. {
  712. // TimeSpec :
  713. // TimeHour
  714. // TimeHour : TimeMinute
  715. // TimeHour TimeMinute
  716. // TimeHour : TimeMinute : TimeSecond TimeFraction[opt]
  717. // TimeHour TimeMinute TimeSecond TimeFraction[opt]
  718. StateTransaction transaction { *this };
  719. if (!parse_time_hour())
  720. return false;
  721. if (m_state.lexer.consume_specific(':')) {
  722. if (!parse_time_minute())
  723. return false;
  724. if (m_state.lexer.consume_specific(':')) {
  725. if (!parse_time_second())
  726. return false;
  727. (void)parse_time_fraction();
  728. }
  729. } else if (parse_time_minute()) {
  730. if (parse_time_second())
  731. (void)parse_time_fraction();
  732. }
  733. transaction.commit();
  734. return true;
  735. }
  736. // https://tc39.es/proposal-temporal/#prod-TimeSpecSeparator
  737. bool ISO8601Parser::parse_time_spec_separator()
  738. {
  739. // TimeSpecSeparator :
  740. // DateTimeSeparator TimeSpec
  741. StateTransaction transaction { *this };
  742. if (!parse_date_time_separator())
  743. return false;
  744. if (!parse_time_spec())
  745. return false;
  746. transaction.commit();
  747. return true;
  748. }
  749. // https://tc39.es/proposal-temporal/#prod-DateTime
  750. bool ISO8601Parser::parse_date_time()
  751. {
  752. // DateTime :
  753. // Date TimeSpecSeparator[opt] TimeZone[opt]
  754. if (!parse_date())
  755. return false;
  756. (void)parse_time_spec_separator();
  757. (void)parse_time_zone();
  758. return true;
  759. }
  760. // https://tc39.es/proposal-temporal/#prod-CalendarTime
  761. bool ISO8601Parser::parse_calendar_time()
  762. {
  763. // CalendarTime :
  764. // TimeDesignator[opt] TimeSpec TimeZone[opt] Calendar[opt]
  765. StateTransaction transaction { *this };
  766. (void)parse_time_designator();
  767. if (!parse_time_spec())
  768. return false;
  769. (void)parse_time_zone();
  770. (void)parse_calendar();
  771. transaction.commit();
  772. return true;
  773. }
  774. // https://tc39.es/proposal-temporal/#prod-CalendarDateTime
  775. bool ISO8601Parser::parse_calendar_date_time()
  776. {
  777. // CalendarDateTime :
  778. // DateTime Calendar[opt]
  779. if (!parse_date_time())
  780. return false;
  781. (void)parse_calendar();
  782. return true;
  783. }
  784. // https://tc39.es/proposal-temporal/#prod-CalendarDateTimeTimeRequired
  785. bool ISO8601Parser::parse_calendar_date_time_time_required()
  786. {
  787. // CalendarDateTimeTimeRequired :
  788. // Date TimeSpecSeparator TimeZone[opt] Calendar[opt]
  789. StateTransaction transaction { *this };
  790. if (!parse_date())
  791. return false;
  792. if (!parse_time_spec_separator())
  793. return false;
  794. (void)parse_time_zone();
  795. (void)parse_calendar();
  796. transaction.commit();
  797. return true;
  798. }
  799. // https://tc39.es/proposal-temporal/#prod-DurationWholeSeconds
  800. bool ISO8601Parser::parse_duration_whole_seconds()
  801. {
  802. // DurationWholeSeconds :
  803. // DecimalDigits[~Sep]
  804. StateTransaction transaction { *this };
  805. if (!parse_decimal_digits())
  806. return false;
  807. m_state.parse_result.duration_whole_seconds = transaction.parsed_string_view();
  808. transaction.commit();
  809. return true;
  810. }
  811. // https://tc39.es/proposal-temporal/#prod-DurationSecondsFraction
  812. bool ISO8601Parser::parse_duration_seconds_fraction()
  813. {
  814. // DurationSecondsFraction :
  815. // TimeFraction
  816. StateTransaction transaction { *this };
  817. if (!parse_time_fraction())
  818. return false;
  819. m_state.parse_result.duration_seconds_fraction = transaction.parsed_string_view();
  820. transaction.commit();
  821. return true;
  822. }
  823. // https://tc39.es/proposal-temporal/#prod-DurationSecondsPart
  824. bool ISO8601Parser::parse_duration_seconds_part()
  825. {
  826. // DurationSecondsPart :
  827. // DurationWholeSeconds DurationSecondsFraction[opt] SecondsDesignator
  828. StateTransaction transaction { *this };
  829. if (!parse_duration_whole_seconds())
  830. return false;
  831. (void)parse_duration_seconds_fraction();
  832. if (!parse_seconds_designator())
  833. return false;
  834. transaction.commit();
  835. return true;
  836. }
  837. // https://tc39.es/proposal-temporal/#prod-DurationWholeMinutes
  838. bool ISO8601Parser::parse_duration_whole_minutes()
  839. {
  840. // DurationWholeMinutes :
  841. // DecimalDigits[~Sep]
  842. StateTransaction transaction { *this };
  843. if (!parse_decimal_digits())
  844. return false;
  845. m_state.parse_result.duration_whole_minutes = transaction.parsed_string_view();
  846. transaction.commit();
  847. return true;
  848. }
  849. // https://tc39.es/proposal-temporal/#prod-DurationMinutesFraction
  850. bool ISO8601Parser::parse_duration_minutes_fraction()
  851. {
  852. // DurationMinutesFraction :
  853. // TimeFraction
  854. StateTransaction transaction { *this };
  855. if (!parse_time_fraction())
  856. return false;
  857. m_state.parse_result.duration_minutes_fraction = transaction.parsed_string_view();
  858. transaction.commit();
  859. return true;
  860. }
  861. // https://tc39.es/proposal-temporal/#prod-DurationMinutesPart
  862. bool ISO8601Parser::parse_duration_minutes_part()
  863. {
  864. // DurationMinutesPart :
  865. // DurationWholeMinutes DurationMinutesFraction[opt] MinutesDesignator DurationSecondsPart[opt]
  866. StateTransaction transaction { *this };
  867. if (!parse_duration_whole_minutes())
  868. return false;
  869. (void)parse_duration_minutes_fraction();
  870. if (!parse_minutes_designator())
  871. return false;
  872. (void)parse_duration_seconds_part();
  873. transaction.commit();
  874. return true;
  875. }
  876. // https://tc39.es/proposal-temporal/#prod-DurationWholeHours
  877. bool ISO8601Parser::parse_duration_whole_hours()
  878. {
  879. // DurationWholeHours :
  880. // DecimalDigits[~Sep]
  881. StateTransaction transaction { *this };
  882. if (!parse_decimal_digits())
  883. return false;
  884. m_state.parse_result.duration_whole_hours = transaction.parsed_string_view();
  885. transaction.commit();
  886. return true;
  887. }
  888. // https://tc39.es/proposal-temporal/#prod-DurationHoursFraction
  889. bool ISO8601Parser::parse_duration_hours_fraction()
  890. {
  891. // DurationHoursFraction :
  892. // TimeFraction
  893. StateTransaction transaction { *this };
  894. if (!parse_time_fraction())
  895. return false;
  896. m_state.parse_result.duration_hours_fraction = transaction.parsed_string_view();
  897. transaction.commit();
  898. return true;
  899. }
  900. // https://tc39.es/proposal-temporal/#prod-DurationHoursPart
  901. bool ISO8601Parser::parse_duration_hours_part()
  902. {
  903. // DurationHoursPart :
  904. // DurationWholeHours DurationHoursFraction[opt] HoursDesignator DurationMinutesPart
  905. // DurationWholeHours DurationHoursFraction[opt] HoursDesignator DurationSecondsPart[opt]
  906. StateTransaction transaction { *this };
  907. if (!parse_duration_whole_hours())
  908. return false;
  909. (void)parse_duration_hours_fraction();
  910. if (!parse_hours_designator())
  911. return false;
  912. (void)(parse_duration_minutes_part()
  913. || parse_duration_seconds_part());
  914. transaction.commit();
  915. return true;
  916. }
  917. // https://tc39.es/proposal-temporal/#prod-DurationTime
  918. bool ISO8601Parser::parse_duration_time()
  919. {
  920. // DurationTime :
  921. // TimeDesignator DurationHoursPart
  922. // TimeDesignator DurationMinutesPart
  923. // TimeDesignator DurationSecondsPart
  924. StateTransaction transaction { *this };
  925. if (!parse_time_designator())
  926. return false;
  927. auto success = parse_duration_hours_part()
  928. || parse_duration_minutes_part()
  929. || parse_duration_seconds_part();
  930. if (!success)
  931. return false;
  932. transaction.commit();
  933. return true;
  934. }
  935. // https://tc39.es/proposal-temporal/#prod-DurationDays
  936. bool ISO8601Parser::parse_duration_days()
  937. {
  938. // DurationDays :
  939. // DecimalDigits[~Sep]
  940. StateTransaction transaction { *this };
  941. if (!parse_decimal_digits())
  942. return false;
  943. m_state.parse_result.duration_days = transaction.parsed_string_view();
  944. transaction.commit();
  945. return true;
  946. }
  947. // https://tc39.es/proposal-temporal/#prod-DurationDaysPart
  948. bool ISO8601Parser::parse_duration_days_part()
  949. {
  950. // DurationDaysPart :
  951. // DurationDays DaysDesignator
  952. StateTransaction transaction { *this };
  953. if (!parse_duration_days())
  954. return false;
  955. if (!parse_days_designator())
  956. return false;
  957. transaction.commit();
  958. return true;
  959. }
  960. // https://tc39.es/proposal-temporal/#prod-DurationWeeks
  961. bool ISO8601Parser::parse_duration_weeks()
  962. {
  963. // DurationWeeks :
  964. // DecimalDigits[~Sep]
  965. StateTransaction transaction { *this };
  966. if (!parse_decimal_digits())
  967. return false;
  968. m_state.parse_result.duration_weeks = transaction.parsed_string_view();
  969. transaction.commit();
  970. return true;
  971. }
  972. // https://tc39.es/proposal-temporal/#prod-DurationWeeksPart
  973. bool ISO8601Parser::parse_duration_weeks_part()
  974. {
  975. // DurationWeeksPart :
  976. // DurationWeeks WeeksDesignator DurationDaysPart[opt]
  977. StateTransaction transaction { *this };
  978. if (!parse_duration_weeks())
  979. return false;
  980. if (!parse_weeks_designator())
  981. return false;
  982. (void)parse_duration_days_part();
  983. transaction.commit();
  984. return true;
  985. }
  986. // https://tc39.es/proposal-temporal/#prod-DurationMonths
  987. bool ISO8601Parser::parse_duration_months()
  988. {
  989. // DurationMonths :
  990. // DecimalDigits[~Sep]
  991. StateTransaction transaction { *this };
  992. if (!parse_decimal_digits())
  993. return false;
  994. m_state.parse_result.duration_months = transaction.parsed_string_view();
  995. transaction.commit();
  996. return true;
  997. }
  998. // https://tc39.es/proposal-temporal/#prod-DurationMonthsPart
  999. bool ISO8601Parser::parse_duration_months_part()
  1000. {
  1001. // DurationMonthsPart :
  1002. // DurationMonths MonthsDesignator DurationWeeksPart
  1003. // DurationMonths MonthsDesignator DurationDaysPart[opt]
  1004. StateTransaction transaction { *this };
  1005. if (!parse_duration_months())
  1006. return false;
  1007. if (!parse_months_designator())
  1008. return false;
  1009. (void)(parse_duration_weeks_part()
  1010. || parse_duration_days_part());
  1011. transaction.commit();
  1012. return true;
  1013. }
  1014. // https://tc39.es/proposal-temporal/#prod-DurationYears
  1015. bool ISO8601Parser::parse_duration_years()
  1016. {
  1017. // DurationYears :
  1018. // DecimalDigits[~Sep]
  1019. StateTransaction transaction { *this };
  1020. if (!parse_decimal_digits())
  1021. return false;
  1022. m_state.parse_result.duration_years = transaction.parsed_string_view();
  1023. transaction.commit();
  1024. return true;
  1025. }
  1026. // https://tc39.es/proposal-temporal/#prod-DurationYearsPart
  1027. bool ISO8601Parser::parse_duration_years_part()
  1028. {
  1029. // DurationYearsPart :
  1030. // DurationYears YearsDesignator DurationMonthsPart
  1031. // DurationYears YearsDesignator DurationWeeksPart
  1032. // DurationYears YearsDesignator DurationDaysPart[opt]
  1033. StateTransaction transaction { *this };
  1034. if (!parse_duration_years())
  1035. return false;
  1036. if (!parse_years_designator())
  1037. return false;
  1038. (void)(parse_duration_months_part()
  1039. || parse_duration_weeks_part()
  1040. || parse_duration_days_part());
  1041. transaction.commit();
  1042. return true;
  1043. }
  1044. // https://tc39.es/proposal-temporal/#prod-DurationDate
  1045. bool ISO8601Parser::parse_duration_date()
  1046. {
  1047. // DurationDate :
  1048. // DurationYearsPart DurationTime[opt]
  1049. // DurationMonthsPart DurationTime[opt]
  1050. // DurationWeeksPart DurationTime[opt]
  1051. // DurationDaysPart DurationTime[opt]
  1052. auto success = parse_duration_years_part()
  1053. || parse_duration_months_part()
  1054. || parse_duration_weeks_part()
  1055. || parse_duration_days_part();
  1056. if (!success)
  1057. return false;
  1058. (void)parse_duration_time();
  1059. return true;
  1060. }
  1061. // https://tc39.es/proposal-temporal/#prod-Duration
  1062. bool ISO8601Parser::parse_duration()
  1063. {
  1064. // Duration :
  1065. // Sign[opt] DurationDesignator DurationDate
  1066. // Sign[opt] DurationDesignator DurationTime
  1067. StateTransaction transaction { *this };
  1068. (void)parse_sign();
  1069. if (!parse_duration_designator())
  1070. return false;
  1071. auto success = parse_duration_date()
  1072. || parse_duration_time();
  1073. if (!success)
  1074. return false;
  1075. transaction.commit();
  1076. return true;
  1077. }
  1078. // https://tc39.es/proposal-temporal/#prod-TemporalInstantString
  1079. bool ISO8601Parser::parse_temporal_instant_string()
  1080. {
  1081. // TemporalInstantString :
  1082. // Date TimeSpecSeparator[opt] TimeZoneOffsetRequired
  1083. StateTransaction transaction { *this };
  1084. if (!parse_date())
  1085. return false;
  1086. (void)parse_time_spec_separator();
  1087. if (!parse_time_zone_offset_required())
  1088. return false;
  1089. transaction.commit();
  1090. return true;
  1091. }
  1092. // https://tc39.es/proposal-temporal/#prod-TemporalDateString
  1093. bool ISO8601Parser::parse_temporal_date_string()
  1094. {
  1095. // TemporalDateString :
  1096. // CalendarDateTime
  1097. return parse_calendar_date_time();
  1098. }
  1099. // https://tc39.es/proposal-temporal/#prod-TemporalDateTimeString
  1100. bool ISO8601Parser::parse_temporal_date_time_string()
  1101. {
  1102. // TemporalDateTimeString :
  1103. // CalendarDateTime
  1104. return parse_calendar_date_time();
  1105. }
  1106. // https://tc39.es/proposal-temporal/#prod-TemporalDurationString
  1107. bool ISO8601Parser::parse_temporal_duration_string()
  1108. {
  1109. // TemporalDurationString :
  1110. // Duration
  1111. return parse_duration();
  1112. }
  1113. // https://tc39.es/proposal-temporal/#prod-TemporalMonthDayString
  1114. bool ISO8601Parser::parse_temporal_month_day_string()
  1115. {
  1116. // TemporalMonthDayString :
  1117. // DateSpecMonthDay
  1118. // CalendarDateTime
  1119. // NOTE: Reverse order here because `DateSpecMonthDay` can be a subset of `CalendarDateTime`,
  1120. // so we'd not attempt to parse that but may not exhaust the input string.
  1121. return parse_calendar_date_time()
  1122. || parse_date_spec_month_day();
  1123. }
  1124. // https://tc39.es/proposal-temporal/#prod-TemporalTimeString
  1125. bool ISO8601Parser::parse_temporal_time_string()
  1126. {
  1127. // TemporalTimeString :
  1128. // CalendarTime
  1129. // CalendarDateTimeTimeRequired
  1130. // NOTE: Reverse order here because `Time` can be a subset of `CalendarDateTimeTimeRequired`,
  1131. // so we'd not attempt to parse that but may not exhaust the input string.
  1132. return parse_calendar_date_time_time_required()
  1133. || parse_calendar_time();
  1134. }
  1135. // https://tc39.es/proposal-temporal/#prod-TemporalTimeZoneIdentifier
  1136. bool ISO8601Parser::parse_temporal_time_zone_identifier()
  1137. {
  1138. // TemporalTimeZoneIdentifier :
  1139. // TimeZoneNumericUTCOffset
  1140. // TimeZoneIANAName
  1141. return parse_time_zone_numeric_utc_offset()
  1142. || parse_time_zone_iana_name();
  1143. }
  1144. // https://tc39.es/proposal-temporal/#prod-TemporalTimeZoneString
  1145. bool ISO8601Parser::parse_temporal_time_zone_string()
  1146. {
  1147. // TemporalTimeZoneString :
  1148. // TemporalTimeZoneIdentifier
  1149. // Date TimeSpecSeparator[opt] TimeZone Calendar[opt]
  1150. StateTransaction transaction { *this };
  1151. if (!parse_temporal_time_zone_identifier()) {
  1152. if (!parse_date())
  1153. return false;
  1154. (void)parse_time_spec_separator();
  1155. if (!parse_time_zone())
  1156. return false;
  1157. (void)parse_calendar();
  1158. }
  1159. transaction.commit();
  1160. return true;
  1161. }
  1162. // https://tc39.es/proposal-temporal/#prod-TemporalYearMonthString
  1163. bool ISO8601Parser::parse_temporal_year_month_string()
  1164. {
  1165. // TemporalYearMonthString :
  1166. // DateSpecYearMonth
  1167. // CalendarDateTime
  1168. // NOTE: Reverse order here because `DateSpecYearMonth` can be a subset of `CalendarDateTime`,
  1169. // so we'd not attempt to parse that but may not exhaust the input string.
  1170. return parse_calendar_date_time()
  1171. || parse_date_spec_year_month();
  1172. }
  1173. // https://tc39.es/proposal-temporal/#prod-TemporalZonedDateTimeString
  1174. bool ISO8601Parser::parse_temporal_zoned_date_time_string()
  1175. {
  1176. // TemporalZonedDateTimeString :
  1177. // Date TimeSpecSeparator[opt] TimeZoneNameRequired Calendar[opt]
  1178. StateTransaction transaction { *this };
  1179. if (!parse_date())
  1180. return false;
  1181. (void)parse_time_spec_separator();
  1182. if (!parse_time_zone_name_required())
  1183. return false;
  1184. (void)parse_calendar();
  1185. transaction.commit();
  1186. return true;
  1187. }
  1188. // https://tc39.es/proposal-temporal/#prod-TemporalCalendarString
  1189. bool ISO8601Parser::parse_temporal_calendar_string()
  1190. {
  1191. // TemporalCalendarString :
  1192. // CalendarName
  1193. // TemporalInstantString
  1194. // CalendarDateTime
  1195. // CalendarTime
  1196. // DateSpecYearMonth
  1197. // DateSpecMonthDay
  1198. return parse_calendar_name()
  1199. || parse_temporal_instant_string()
  1200. || parse_calendar_date_time()
  1201. || parse_date_spec_year_month()
  1202. || parse_date_spec_month_day()
  1203. || parse_calendar_time();
  1204. }
  1205. // https://tc39.es/proposal-temporal/#prod-TemporalRelativeToString
  1206. bool ISO8601Parser::parse_temporal_relative_to_string()
  1207. {
  1208. // TemporalRelativeToString :
  1209. // TemporalDateTimeString
  1210. return parse_temporal_date_time_string();
  1211. }
  1212. }
  1213. #define JS_ENUMERATE_ISO8601_PRODUCTION_PARSERS \
  1214. __JS_ENUMERATE(TemporalInstantString, parse_temporal_instant_string) \
  1215. __JS_ENUMERATE(TemporalDateString, parse_temporal_date_string) \
  1216. __JS_ENUMERATE(TemporalDateTimeString, parse_temporal_date_time_string) \
  1217. __JS_ENUMERATE(TemporalDurationString, parse_temporal_duration_string) \
  1218. __JS_ENUMERATE(TemporalMonthDayString, parse_temporal_month_day_string) \
  1219. __JS_ENUMERATE(TemporalTimeString, parse_temporal_time_string) \
  1220. __JS_ENUMERATE(TemporalTimeZoneString, parse_temporal_time_zone_string) \
  1221. __JS_ENUMERATE(TemporalYearMonthString, parse_temporal_year_month_string) \
  1222. __JS_ENUMERATE(TemporalZonedDateTimeString, parse_temporal_zoned_date_time_string) \
  1223. __JS_ENUMERATE(TemporalCalendarString, parse_temporal_calendar_string) \
  1224. __JS_ENUMERATE(TemporalRelativeToString, parse_temporal_relative_to_string)
  1225. Optional<ParseResult> parse_iso8601(Production production, StringView input)
  1226. {
  1227. auto parser = Detail::ISO8601Parser { input };
  1228. switch (production) {
  1229. #define __JS_ENUMERATE(ProductionName, parse_production) \
  1230. case Production::ProductionName: \
  1231. if (!parser.parse_production()) \
  1232. return {}; \
  1233. break;
  1234. JS_ENUMERATE_ISO8601_PRODUCTION_PARSERS
  1235. #undef __JS_ENUMERATE
  1236. default:
  1237. VERIFY_NOT_REACHED();
  1238. }
  1239. // If we parsed successfully but didn't reach the end, the string doesn't match the given production.
  1240. if (!parser.lexer().is_eof())
  1241. return {};
  1242. return parser.parse_result();
  1243. }
  1244. }