ISO8601.cpp 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327
  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-DurationTimeDesignator
  186. bool ISO8601Parser::parse_duration_time_designator()
  187. {
  188. // DurationTimeDesignator : 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-TimeFractionalPart
  401. bool ISO8601Parser::parse_time_fractional_part()
  402. {
  403. // TimeFractionalPart :
  404. // FractionalPart
  405. StateTransaction transaction { *this };
  406. if (!parse_fractional_part())
  407. return false;
  408. m_state.parse_result.time_fractional_part = transaction.parsed_string_view();
  409. transaction.commit();
  410. return true;
  411. }
  412. // https://tc39.es/proposal-temporal/#prod-Fraction
  413. bool ISO8601Parser::parse_fraction()
  414. {
  415. // Fraction :
  416. // DecimalSeparator TimeFractionalPart
  417. StateTransaction transaction { *this };
  418. if (!parse_decimal_separator())
  419. return false;
  420. if (!parse_time_fractional_part())
  421. return false;
  422. transaction.commit();
  423. return true;
  424. }
  425. // https://tc39.es/proposal-temporal/#prod-TimeFraction
  426. bool ISO8601Parser::parse_time_fraction()
  427. {
  428. // TimeFraction :
  429. // Fraction
  430. return parse_fraction();
  431. }
  432. // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetSign
  433. bool ISO8601Parser::parse_time_zone_utc_offset_sign()
  434. {
  435. // TimeZoneUTCOffsetSign :
  436. // Sign
  437. StateTransaction transaction { *this };
  438. if (!parse_sign())
  439. return false;
  440. m_state.parse_result.time_zone_utc_offset_sign = transaction.parsed_string_view();
  441. transaction.commit();
  442. return true;
  443. }
  444. // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetHour
  445. bool ISO8601Parser::parse_time_zone_utc_offset_hour()
  446. {
  447. // TimeZoneUTCOffsetHour :
  448. // Hour
  449. StateTransaction transaction { *this };
  450. if (!parse_hour())
  451. return false;
  452. m_state.parse_result.time_zone_utc_offset_hour = transaction.parsed_string_view();
  453. transaction.commit();
  454. return true;
  455. }
  456. // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetMinute
  457. bool ISO8601Parser::parse_time_zone_utc_offset_minute()
  458. {
  459. // TimeZoneUTCOffsetMinute :
  460. // MinuteSecond
  461. StateTransaction transaction { *this };
  462. if (!parse_minute_second())
  463. return false;
  464. m_state.parse_result.time_zone_utc_offset_minute = transaction.parsed_string_view();
  465. transaction.commit();
  466. return true;
  467. }
  468. // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetSecond
  469. bool ISO8601Parser::parse_time_zone_utc_offset_second()
  470. {
  471. // TimeZoneUTCOffsetSecond :
  472. // MinuteSecond
  473. StateTransaction transaction { *this };
  474. if (!parse_minute_second())
  475. return false;
  476. m_state.parse_result.time_zone_utc_offset_second = transaction.parsed_string_view();
  477. transaction.commit();
  478. return true;
  479. }
  480. // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetFractionalPart
  481. bool ISO8601Parser::parse_time_zone_utc_offset_fractional_part()
  482. {
  483. // TimeZoneUTCOffsetFractionalPart :
  484. // FractionalPart
  485. StateTransaction transaction { *this };
  486. if (!parse_fractional_part())
  487. return false;
  488. m_state.parse_result.time_zone_utc_offset_fractional_part = transaction.parsed_string_view();
  489. transaction.commit();
  490. return true;
  491. }
  492. // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetFraction
  493. bool ISO8601Parser::parse_time_zone_utc_offset_fraction()
  494. {
  495. // TimeZoneUTCOffsetFraction :
  496. // DecimalSeparator TimeZoneUTCOffsetFractionalPart
  497. StateTransaction transaction { *this };
  498. if (!parse_decimal_separator())
  499. return false;
  500. if (!parse_time_zone_utc_offset_fractional_part())
  501. return false;
  502. transaction.commit();
  503. return true;
  504. }
  505. // https://tc39.es/proposal-temporal/#prod-TimeZoneNumericUTCOffset
  506. bool ISO8601Parser::parse_time_zone_numeric_utc_offset()
  507. {
  508. // TimeZoneNumericUTCOffset :
  509. // TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour
  510. // TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour : TimeZoneUTCOffsetMinute
  511. // TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour TimeZoneUTCOffsetMinute
  512. // TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour : TimeZoneUTCOffsetMinute : TimeZoneUTCOffsetSecond TimeZoneUTCOffsetFraction[opt]
  513. // TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour TimeZoneUTCOffsetMinute TimeZoneUTCOffsetSecond TimeZoneUTCOffsetFraction[opt]
  514. StateTransaction transaction { *this };
  515. if (!parse_time_zone_utc_offset_sign())
  516. return false;
  517. if (!parse_time_zone_utc_offset_hour())
  518. return false;
  519. if (m_state.lexer.consume_specific(':')) {
  520. if (!parse_time_zone_utc_offset_minute())
  521. return false;
  522. if (m_state.lexer.consume_specific(':')) {
  523. if (!parse_time_zone_utc_offset_second())
  524. return false;
  525. (void)parse_time_zone_utc_offset_fraction();
  526. }
  527. } else if (parse_time_zone_utc_offset_minute()) {
  528. if (parse_time_zone_utc_offset_second())
  529. (void)parse_time_zone_utc_offset_fraction();
  530. }
  531. transaction.commit();
  532. return true;
  533. }
  534. // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffset
  535. bool ISO8601Parser::parse_time_zone_utc_offset()
  536. {
  537. // TimeZoneUTCOffset :
  538. // TimeZoneNumericUTCOffset
  539. // UTCDesignator
  540. return parse_time_zone_numeric_utc_offset()
  541. || parse_utc_designator();
  542. }
  543. // https://tc39.es/proposal-temporal/#prod-TimeZoneUTCOffsetName
  544. bool ISO8601Parser::parse_time_zone_utc_offset_name()
  545. {
  546. // TimeZoneUTCOffsetName :
  547. // Sign Hour
  548. // Sign Hour : MinuteSecond
  549. // Sign Hour MinuteSecond
  550. // Sign Hour : MinuteSecond : MinuteSecond Fraction[opt]
  551. // Sign Hour MinuteSecond MinuteSecond Fraction[opt]
  552. StateTransaction transaction { *this };
  553. if (!parse_sign())
  554. return false;
  555. if (!parse_hour())
  556. return false;
  557. if (m_state.lexer.consume_specific(':')) {
  558. if (!parse_minute_second())
  559. return false;
  560. if (m_state.lexer.consume_specific(':')) {
  561. if (!parse_minute_second())
  562. return false;
  563. (void)parse_fraction();
  564. }
  565. } else if (parse_minute_second()) {
  566. if (parse_minute_second())
  567. (void)parse_fraction();
  568. }
  569. transaction.commit();
  570. return true;
  571. }
  572. // https://tc39.es/proposal-temporal/#prod-TimeZoneIANAName
  573. bool ISO8601Parser::parse_time_zone_iana_name()
  574. {
  575. // TZLeadingChar :
  576. // Alpha
  577. // .
  578. // _
  579. // TZChar :
  580. // Alpha
  581. // .
  582. // -
  583. // _
  584. // TimeZoneIANANameComponent :
  585. // 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 ..
  586. // TimeZoneIANANameTail :
  587. // TimeZoneIANANameComponent
  588. // TimeZoneIANANameComponent / TimeZoneIANANameTail
  589. // TimeZoneIANAName :
  590. // TimeZoneIANANameTail
  591. StateTransaction transaction { *this };
  592. // TODO: Implement the full production. Currently, anything other than "UTC" would get rejected as unknown anyway.
  593. auto success = (m_state.lexer.consume_specific('U') || m_state.lexer.consume_specific('u'))
  594. && (m_state.lexer.consume_specific('T') || m_state.lexer.consume_specific('t'))
  595. && (m_state.lexer.consume_specific('C') || m_state.lexer.consume_specific('c'));
  596. if (!success)
  597. return false;
  598. m_state.parse_result.time_zone_iana_name = transaction.parsed_string_view();
  599. transaction.commit();
  600. return true;
  601. }
  602. // https://tc39.es/proposal-temporal/#prod-TimeZoneBracketedName
  603. bool ISO8601Parser::parse_time_zone_bracketed_name()
  604. {
  605. // TimeZoneBracketedName :
  606. // TimeZoneIANAName
  607. // Etc/GMT ASCIISign Hour
  608. // TimeZoneUTCOffsetName
  609. StateTransaction transaction { *this };
  610. if (parse_time_zone_iana_name()) {
  611. // no-op.
  612. } else if (m_state.lexer.consume_specific("Etc/GMT"sv)) {
  613. if (!parse_ascii_sign())
  614. return false;
  615. if (!parse_hour())
  616. return false;
  617. } else if (!parse_time_zone_utc_offset_name()) {
  618. return false;
  619. }
  620. transaction.commit();
  621. return true;
  622. }
  623. // https://tc39.es/proposal-temporal/#prod-TimeZoneBracketedAnnotation
  624. bool ISO8601Parser::parse_time_zone_bracketed_annotation()
  625. {
  626. // TimeZoneBracketedAnnotation :
  627. // [ TimeZoneBracketedName ]
  628. StateTransaction transaction { *this };
  629. if (!m_state.lexer.consume_specific('['))
  630. return false;
  631. if (!parse_time_zone_bracketed_name())
  632. return false;
  633. if (!m_state.lexer.consume_specific(']'))
  634. return false;
  635. transaction.commit();
  636. return true;
  637. }
  638. // https://tc39.es/proposal-temporal/#prod-TimeZoneOffsetRequired
  639. bool ISO8601Parser::parse_time_zone_offset_required()
  640. {
  641. // TimeZoneOffsetRequired :
  642. // TimeZoneUTCOffset TimeZoneBracketedAnnotation[opt]
  643. StateTransaction transaction { *this };
  644. if (!parse_time_zone_utc_offset())
  645. return false;
  646. (void)parse_time_zone_bracketed_annotation();
  647. transaction.commit();
  648. return true;
  649. }
  650. // https://tc39.es/proposal-temporal/#prod-TimeZoneNameRequired
  651. bool ISO8601Parser::parse_time_zone_name_required()
  652. {
  653. // TimeZoneNameRequired :
  654. // TimeZoneUTCOffset[opt] TimeZoneBracketedAnnotation
  655. StateTransaction transaction { *this };
  656. (void)parse_time_zone_utc_offset();
  657. if (!parse_time_zone_bracketed_annotation())
  658. return false;
  659. transaction.commit();
  660. return true;
  661. }
  662. // https://tc39.es/proposal-temporal/#prod-TimeZone
  663. bool ISO8601Parser::parse_time_zone()
  664. {
  665. // TimeZone :
  666. // TimeZoneOffsetRequired
  667. // TimeZoneNameRequired
  668. return parse_time_zone_offset_required()
  669. || parse_time_zone_name_required();
  670. }
  671. // https://tc39.es/proposal-temporal/#prod-CalendarName
  672. bool ISO8601Parser::parse_calendar_name()
  673. {
  674. // CalChar :
  675. // Alpha
  676. // DecimalDigit
  677. // CalendarNameComponent :
  678. // CalChar CalChar CalChar CalChar[opt] CalChar[opt] CalChar[opt] CalChar[opt] CalChar[opt]
  679. // CalendarNameTail :
  680. // CalendarNameComponent
  681. // CalendarNameComponent - CalendarNameTail
  682. // CalendarName :
  683. // CalendarNameTail
  684. auto parse_calendar_name_component = [&] {
  685. for (size_t i = 0; i < 8; ++i) {
  686. if (!m_state.lexer.next_is(is_ascii_alphanumeric))
  687. return i > 2;
  688. m_state.lexer.consume();
  689. }
  690. return true;
  691. };
  692. StateTransaction transaction { *this };
  693. do {
  694. if (!parse_calendar_name_component())
  695. return false;
  696. } while (m_state.lexer.consume_specific('-'));
  697. m_state.parse_result.calendar_name = transaction.parsed_string_view();
  698. transaction.commit();
  699. return true;
  700. }
  701. // https://tc39.es/proposal-temporal/#prod-Calendar
  702. bool ISO8601Parser::parse_calendar()
  703. {
  704. // Calendar :
  705. // [u-ca= CalendarName ]
  706. StateTransaction transaction { *this };
  707. if (!m_state.lexer.consume_specific("[u-ca="sv))
  708. return false;
  709. if (!parse_calendar_name())
  710. return false;
  711. if (!m_state.lexer.consume_specific(']'))
  712. return false;
  713. transaction.commit();
  714. return true;
  715. }
  716. // https://tc39.es/proposal-temporal/#prod-TimeSpec
  717. bool ISO8601Parser::parse_time_spec()
  718. {
  719. // TimeSpec :
  720. // TimeHour
  721. // TimeHour : TimeMinute
  722. // TimeHour TimeMinute
  723. // TimeHour : TimeMinute : TimeSecond TimeFraction[opt]
  724. // TimeHour TimeMinute TimeSecond TimeFraction[opt]
  725. StateTransaction transaction { *this };
  726. if (!parse_time_hour())
  727. return false;
  728. if (m_state.lexer.consume_specific(':')) {
  729. if (!parse_time_minute())
  730. return false;
  731. if (m_state.lexer.consume_specific(':')) {
  732. if (!parse_time_second())
  733. return false;
  734. (void)parse_time_fraction();
  735. }
  736. } else if (parse_time_minute()) {
  737. if (parse_time_second())
  738. (void)parse_time_fraction();
  739. }
  740. transaction.commit();
  741. return true;
  742. }
  743. // https://tc39.es/proposal-temporal/#prod-Time
  744. bool ISO8601Parser::parse_time()
  745. {
  746. // Time :
  747. // TimeSpec TimeZone[opt]
  748. if (!parse_time_spec())
  749. return false;
  750. (void)parse_time_zone();
  751. return true;
  752. }
  753. // https://tc39.es/proposal-temporal/#prod-TimeSpecSeparator
  754. bool ISO8601Parser::parse_time_spec_separator()
  755. {
  756. // TimeSpecSeparator :
  757. // DateTimeSeparator TimeSpec
  758. StateTransaction transaction { *this };
  759. if (!parse_date_time_separator())
  760. return false;
  761. if (!parse_time_spec())
  762. return false;
  763. transaction.commit();
  764. return true;
  765. }
  766. // https://tc39.es/proposal-temporal/#prod-DateTime
  767. bool ISO8601Parser::parse_date_time()
  768. {
  769. // DateTime :
  770. // Date TimeSpecSeparator[opt] TimeZone[opt]
  771. if (!parse_date())
  772. return false;
  773. (void)parse_time_spec_separator();
  774. (void)parse_time_zone();
  775. return true;
  776. }
  777. // https://tc39.es/proposal-temporal/#prod-CalendarDateTime
  778. bool ISO8601Parser::parse_calendar_date_time()
  779. {
  780. // CalendarDateTime :
  781. // DateTime Calendar[opt]
  782. if (!parse_date_time())
  783. return false;
  784. (void)parse_calendar();
  785. return true;
  786. }
  787. // https://tc39.es/proposal-temporal/#prod-DurationWholeSeconds
  788. bool ISO8601Parser::parse_duration_whole_seconds()
  789. {
  790. // DurationWholeSeconds :
  791. // DecimalDigits[~Sep]
  792. StateTransaction transaction { *this };
  793. if (!parse_decimal_digits())
  794. return false;
  795. m_state.parse_result.duration_whole_seconds = transaction.parsed_string_view();
  796. transaction.commit();
  797. return true;
  798. }
  799. // https://tc39.es/proposal-temporal/#prod-DurationSecondsFraction
  800. bool ISO8601Parser::parse_duration_seconds_fraction()
  801. {
  802. // DurationSecondsFraction :
  803. // TimeFraction
  804. StateTransaction transaction { *this };
  805. if (!parse_time_fraction())
  806. return false;
  807. m_state.parse_result.duration_seconds_fraction = transaction.parsed_string_view();
  808. transaction.commit();
  809. return true;
  810. }
  811. // https://tc39.es/proposal-temporal/#prod-DurationSecondsPart
  812. bool ISO8601Parser::parse_duration_seconds_part()
  813. {
  814. // DurationSecondsPart :
  815. // DurationWholeSeconds DurationSecondsFraction[opt] SecondsDesignator
  816. StateTransaction transaction { *this };
  817. if (!parse_duration_whole_seconds())
  818. return false;
  819. (void)parse_duration_seconds_fraction();
  820. if (!parse_seconds_designator())
  821. return false;
  822. transaction.commit();
  823. return true;
  824. }
  825. // https://tc39.es/proposal-temporal/#prod-DurationWholeMinutes
  826. bool ISO8601Parser::parse_duration_whole_minutes()
  827. {
  828. // DurationWholeMinutes :
  829. // DecimalDigits[~Sep]
  830. StateTransaction transaction { *this };
  831. if (!parse_decimal_digits())
  832. return false;
  833. m_state.parse_result.duration_whole_minutes = transaction.parsed_string_view();
  834. transaction.commit();
  835. return true;
  836. }
  837. // https://tc39.es/proposal-temporal/#prod-DurationMinutesFraction
  838. bool ISO8601Parser::parse_duration_minutes_fraction()
  839. {
  840. // DurationMinutesFraction :
  841. // TimeFraction
  842. StateTransaction transaction { *this };
  843. if (!parse_time_fraction())
  844. return false;
  845. m_state.parse_result.duration_minutes_fraction = transaction.parsed_string_view();
  846. transaction.commit();
  847. return true;
  848. }
  849. // https://tc39.es/proposal-temporal/#prod-DurationMinutesPart
  850. bool ISO8601Parser::parse_duration_minutes_part()
  851. {
  852. // DurationMinutesPart :
  853. // DurationWholeMinutes DurationMinutesFraction[opt] MinutesDesignator DurationSecondsPart[opt]
  854. StateTransaction transaction { *this };
  855. if (!parse_duration_whole_minutes())
  856. return false;
  857. (void)parse_duration_minutes_fraction();
  858. if (!parse_minutes_designator())
  859. return false;
  860. (void)parse_duration_seconds_part();
  861. transaction.commit();
  862. return true;
  863. }
  864. // https://tc39.es/proposal-temporal/#prod-DurationWholeHours
  865. bool ISO8601Parser::parse_duration_whole_hours()
  866. {
  867. // DurationWholeHours :
  868. // DecimalDigits[~Sep]
  869. StateTransaction transaction { *this };
  870. if (!parse_decimal_digits())
  871. return false;
  872. m_state.parse_result.duration_whole_hours = transaction.parsed_string_view();
  873. transaction.commit();
  874. return true;
  875. }
  876. // https://tc39.es/proposal-temporal/#prod-DurationHoursFraction
  877. bool ISO8601Parser::parse_duration_hours_fraction()
  878. {
  879. // DurationHoursFraction :
  880. // TimeFraction
  881. StateTransaction transaction { *this };
  882. if (!parse_time_fraction())
  883. return false;
  884. m_state.parse_result.duration_hours_fraction = transaction.parsed_string_view();
  885. transaction.commit();
  886. return true;
  887. }
  888. // https://tc39.es/proposal-temporal/#prod-DurationHoursPart
  889. bool ISO8601Parser::parse_duration_hours_part()
  890. {
  891. // DurationHoursPart :
  892. // DurationWholeHours DurationHoursFraction[opt] HoursDesignator DurationMinutesPart
  893. // DurationWholeHours DurationHoursFraction[opt] HoursDesignator DurationSecondsPart[opt]
  894. StateTransaction transaction { *this };
  895. if (!parse_duration_whole_hours())
  896. return false;
  897. (void)parse_duration_hours_fraction();
  898. if (!parse_hours_designator())
  899. return false;
  900. (void)(parse_duration_minutes_part()
  901. || parse_duration_seconds_part());
  902. transaction.commit();
  903. return true;
  904. }
  905. // https://tc39.es/proposal-temporal/#prod-DurationTime
  906. bool ISO8601Parser::parse_duration_time()
  907. {
  908. // DurationTime :
  909. // DurationTimeDesignator DurationHoursPart
  910. // DurationTimeDesignator DurationMinutesPart
  911. // DurationTimeDesignator DurationSecondsPart
  912. StateTransaction transaction { *this };
  913. if (!parse_duration_time_designator())
  914. return false;
  915. auto success = parse_duration_hours_part()
  916. || parse_duration_minutes_part()
  917. || parse_duration_seconds_part();
  918. if (!success)
  919. return false;
  920. transaction.commit();
  921. return true;
  922. }
  923. // https://tc39.es/proposal-temporal/#prod-DurationDays
  924. bool ISO8601Parser::parse_duration_days()
  925. {
  926. // DurationDays :
  927. // DecimalDigits[~Sep]
  928. StateTransaction transaction { *this };
  929. if (!parse_decimal_digits())
  930. return false;
  931. m_state.parse_result.duration_days = transaction.parsed_string_view();
  932. transaction.commit();
  933. return true;
  934. }
  935. // https://tc39.es/proposal-temporal/#prod-DurationDaysPart
  936. bool ISO8601Parser::parse_duration_days_part()
  937. {
  938. // DurationDaysPart :
  939. // DurationDays DaysDesignator
  940. StateTransaction transaction { *this };
  941. if (!parse_duration_days())
  942. return false;
  943. if (!parse_days_designator())
  944. return false;
  945. transaction.commit();
  946. return true;
  947. }
  948. // https://tc39.es/proposal-temporal/#prod-DurationWeeks
  949. bool ISO8601Parser::parse_duration_weeks()
  950. {
  951. // DurationWeeks :
  952. // DecimalDigits[~Sep]
  953. StateTransaction transaction { *this };
  954. if (!parse_decimal_digits())
  955. return false;
  956. m_state.parse_result.duration_weeks = transaction.parsed_string_view();
  957. transaction.commit();
  958. return true;
  959. }
  960. // https://tc39.es/proposal-temporal/#prod-DurationWeeksPart
  961. bool ISO8601Parser::parse_duration_weeks_part()
  962. {
  963. // DurationWeeksPart :
  964. // DurationWeeks WeeksDesignator DurationDaysPart[opt]
  965. StateTransaction transaction { *this };
  966. if (!parse_duration_weeks())
  967. return false;
  968. if (!parse_weeks_designator())
  969. return false;
  970. (void)parse_duration_days_part();
  971. transaction.commit();
  972. return true;
  973. }
  974. // https://tc39.es/proposal-temporal/#prod-DurationMonths
  975. bool ISO8601Parser::parse_duration_months()
  976. {
  977. // DurationMonths :
  978. // DecimalDigits[~Sep]
  979. StateTransaction transaction { *this };
  980. if (!parse_decimal_digits())
  981. return false;
  982. m_state.parse_result.duration_months = transaction.parsed_string_view();
  983. transaction.commit();
  984. return true;
  985. }
  986. // https://tc39.es/proposal-temporal/#prod-DurationMonthsPart
  987. bool ISO8601Parser::parse_duration_months_part()
  988. {
  989. // DurationMonthsPart :
  990. // DurationMonths MonthsDesignator DurationWeeksPart
  991. // DurationMonths MonthsDesignator DurationDaysPart[opt]
  992. StateTransaction transaction { *this };
  993. if (!parse_duration_months())
  994. return false;
  995. if (!parse_months_designator())
  996. return false;
  997. (void)(parse_duration_weeks_part()
  998. || parse_duration_days_part());
  999. transaction.commit();
  1000. return true;
  1001. }
  1002. // https://tc39.es/proposal-temporal/#prod-DurationYears
  1003. bool ISO8601Parser::parse_duration_years()
  1004. {
  1005. // DurationYears :
  1006. // DecimalDigits[~Sep]
  1007. StateTransaction transaction { *this };
  1008. if (!parse_decimal_digits())
  1009. return false;
  1010. m_state.parse_result.duration_years = transaction.parsed_string_view();
  1011. transaction.commit();
  1012. return true;
  1013. }
  1014. // https://tc39.es/proposal-temporal/#prod-DurationYearsPart
  1015. bool ISO8601Parser::parse_duration_years_part()
  1016. {
  1017. // DurationYearsPart :
  1018. // DurationYears YearsDesignator DurationMonthsPart
  1019. // DurationYears YearsDesignator DurationWeeksPart
  1020. // DurationYears YearsDesignator DurationDaysPart[opt]
  1021. StateTransaction transaction { *this };
  1022. if (!parse_duration_years())
  1023. return false;
  1024. if (!parse_years_designator())
  1025. return false;
  1026. (void)(parse_duration_months_part()
  1027. || parse_duration_weeks_part()
  1028. || parse_duration_days_part());
  1029. transaction.commit();
  1030. return true;
  1031. }
  1032. // https://tc39.es/proposal-temporal/#prod-DurationDate
  1033. bool ISO8601Parser::parse_duration_date()
  1034. {
  1035. // DurationDate :
  1036. // DurationYearsPart DurationTime[opt]
  1037. // DurationMonthsPart DurationTime[opt]
  1038. // DurationWeeksPart DurationTime[opt]
  1039. // DurationDaysPart DurationTime[opt]
  1040. auto success = parse_duration_years_part()
  1041. || parse_duration_months_part()
  1042. || parse_duration_weeks_part()
  1043. || parse_duration_days_part();
  1044. if (!success)
  1045. return false;
  1046. (void)parse_duration_time();
  1047. return true;
  1048. }
  1049. // https://tc39.es/proposal-temporal/#prod-Duration
  1050. bool ISO8601Parser::parse_duration()
  1051. {
  1052. // Duration :
  1053. // Sign[opt] DurationDesignator DurationDate
  1054. // Sign[opt] DurationDesignator DurationTime
  1055. StateTransaction transaction { *this };
  1056. (void)parse_sign();
  1057. if (!parse_duration_designator())
  1058. return false;
  1059. auto success = parse_duration_date()
  1060. || parse_duration_time();
  1061. if (!success)
  1062. return false;
  1063. transaction.commit();
  1064. return true;
  1065. }
  1066. // https://tc39.es/proposal-temporal/#prod-TemporalInstantString
  1067. bool ISO8601Parser::parse_temporal_instant_string()
  1068. {
  1069. // TemporalInstantString :
  1070. // Date TimeSpecSeparator[opt] TimeZoneOffsetRequired
  1071. StateTransaction transaction { *this };
  1072. if (!parse_date())
  1073. return false;
  1074. (void)parse_time_spec_separator();
  1075. if (!parse_time_zone_offset_required())
  1076. return false;
  1077. transaction.commit();
  1078. return true;
  1079. }
  1080. // https://tc39.es/proposal-temporal/#prod-TemporalDateString
  1081. bool ISO8601Parser::parse_temporal_date_string()
  1082. {
  1083. // TemporalDateString :
  1084. // CalendarDateTime
  1085. return parse_calendar_date_time();
  1086. }
  1087. // https://tc39.es/proposal-temporal/#prod-TemporalDateTimeString
  1088. bool ISO8601Parser::parse_temporal_date_time_string()
  1089. {
  1090. // TemporalDateTimeString :
  1091. // CalendarDateTime
  1092. return parse_calendar_date_time();
  1093. }
  1094. // https://tc39.es/proposal-temporal/#prod-TemporalDurationString
  1095. bool ISO8601Parser::parse_temporal_duration_string()
  1096. {
  1097. // TemporalDurationString :
  1098. // Duration
  1099. return parse_duration();
  1100. }
  1101. // https://tc39.es/proposal-temporal/#prod-TemporalMonthDayString
  1102. bool ISO8601Parser::parse_temporal_month_day_string()
  1103. {
  1104. // TemporalMonthDayString :
  1105. // DateSpecMonthDay
  1106. // DateTime
  1107. // NOTE: Reverse order here because `DateSpecMonthDay` can be a subset of `DateTime`,
  1108. // so we'd not attempt to parse that but may not exhaust the input string.
  1109. return parse_date_time()
  1110. || parse_date_spec_month_day();
  1111. }
  1112. // https://tc39.es/proposal-temporal/#prod-TemporalTimeString
  1113. bool ISO8601Parser::parse_temporal_time_string()
  1114. {
  1115. // TemporalTimeString :
  1116. // Time
  1117. // DateTime
  1118. // NOTE: Reverse order here because `Time` can be a subset of `DateTime`,
  1119. // so we'd not attempt to parse that but may not exhaust the input string.
  1120. return parse_date_time()
  1121. || parse_time();
  1122. }
  1123. // https://tc39.es/proposal-temporal/#prod-TemporalTimeZoneIdentifier
  1124. bool ISO8601Parser::parse_temporal_time_zone_identifier()
  1125. {
  1126. // TemporalTimeZoneIdentifier :
  1127. // TimeZoneNumericUTCOffset
  1128. // TimeZoneIANAName
  1129. return parse_time_zone_numeric_utc_offset()
  1130. || parse_time_zone_iana_name();
  1131. }
  1132. // https://tc39.es/proposal-temporal/#prod-TemporalTimeZoneString
  1133. bool ISO8601Parser::parse_temporal_time_zone_string()
  1134. {
  1135. // TemporalTimeZoneString :
  1136. // TemporalTimeZoneIdentifier
  1137. // Date TimeSpecSeparator[opt] TimeZone Calendar[opt]
  1138. StateTransaction transaction { *this };
  1139. if (!parse_temporal_time_zone_identifier()) {
  1140. if (!parse_date())
  1141. return false;
  1142. (void)parse_time_spec_separator();
  1143. if (!parse_time_zone())
  1144. return false;
  1145. (void)parse_calendar();
  1146. }
  1147. transaction.commit();
  1148. return true;
  1149. }
  1150. // https://tc39.es/proposal-temporal/#prod-TemporalYearMonthString
  1151. bool ISO8601Parser::parse_temporal_year_month_string()
  1152. {
  1153. // TemporalYearMonthString :
  1154. // DateSpecYearMonth
  1155. // DateTime
  1156. // NOTE: Reverse order here because `DateSpecYearMonth` can be a subset of `DateTime`,
  1157. // so we'd not attempt to parse that but may not exhaust the input string.
  1158. return parse_date_time()
  1159. || parse_date_spec_year_month();
  1160. }
  1161. // https://tc39.es/proposal-temporal/#prod-TemporalZonedDateTimeString
  1162. bool ISO8601Parser::parse_temporal_zoned_date_time_string()
  1163. {
  1164. // TemporalZonedDateTimeString :
  1165. // Date TimeSpecSeparator[opt] TimeZoneNameRequired Calendar[opt]
  1166. StateTransaction transaction { *this };
  1167. if (!parse_date())
  1168. return false;
  1169. (void)parse_time_spec_separator();
  1170. if (!parse_time_zone_name_required())
  1171. return false;
  1172. (void)parse_calendar();
  1173. transaction.commit();
  1174. return true;
  1175. }
  1176. // https://tc39.es/proposal-temporal/#prod-TemporalCalendarString
  1177. bool ISO8601Parser::parse_temporal_calendar_string()
  1178. {
  1179. // TemporalCalendarString :
  1180. // CalendarName
  1181. // TemporalInstantString
  1182. // CalendarDateTime
  1183. // Time
  1184. // DateSpecYearMonth
  1185. // DateSpecMonthDay
  1186. return parse_calendar_name()
  1187. || parse_temporal_instant_string()
  1188. || parse_calendar_date_time()
  1189. || parse_date_spec_year_month()
  1190. || parse_date_spec_month_day()
  1191. || parse_time();
  1192. }
  1193. // https://tc39.es/proposal-temporal/#prod-TemporalRelativeToString
  1194. bool ISO8601Parser::parse_temporal_relative_to_string()
  1195. {
  1196. // TemporalRelativeToString :
  1197. // TemporalDateTimeString
  1198. return parse_temporal_date_time_string();
  1199. }
  1200. }
  1201. #define JS_ENUMERATE_ISO8601_PRODUCTION_PARSERS \
  1202. __JS_ENUMERATE(TemporalInstantString, parse_temporal_instant_string) \
  1203. __JS_ENUMERATE(TemporalDateString, parse_temporal_date_string) \
  1204. __JS_ENUMERATE(TemporalDateTimeString, parse_temporal_date_time_string) \
  1205. __JS_ENUMERATE(TemporalDurationString, parse_temporal_duration_string) \
  1206. __JS_ENUMERATE(TemporalMonthDayString, parse_temporal_month_day_string) \
  1207. __JS_ENUMERATE(TemporalTimeString, parse_temporal_time_string) \
  1208. __JS_ENUMERATE(TemporalTimeZoneString, parse_temporal_time_zone_string) \
  1209. __JS_ENUMERATE(TemporalYearMonthString, parse_temporal_year_month_string) \
  1210. __JS_ENUMERATE(TemporalZonedDateTimeString, parse_temporal_zoned_date_time_string) \
  1211. __JS_ENUMERATE(TemporalCalendarString, parse_temporal_calendar_string) \
  1212. __JS_ENUMERATE(TemporalRelativeToString, parse_temporal_relative_to_string)
  1213. Optional<ParseResult> parse_iso8601(Production production, StringView input)
  1214. {
  1215. auto parser = Detail::ISO8601Parser { input };
  1216. switch (production) {
  1217. #define __JS_ENUMERATE(ProductionName, parse_production) \
  1218. case Production::ProductionName: \
  1219. if (!parser.parse_production()) \
  1220. return {}; \
  1221. break;
  1222. JS_ENUMERATE_ISO8601_PRODUCTION_PARSERS
  1223. #undef __JS_ENUMERATE
  1224. default:
  1225. VERIFY_NOT_REACHED();
  1226. }
  1227. // If we parsed successfully but didn't reach the end, the string doesn't match the given production.
  1228. if (!parser.lexer().is_eof())
  1229. return {};
  1230. return parser.parse_result();
  1231. }
  1232. }