ISO8601.cpp 45 KB

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