• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/temporal/temporal-parser.h"
6 
7 #include "src/base/bounds.h"
8 #include "src/objects/string-inl.h"
9 #include "src/strings/char-predicates-inl.h"
10 
11 namespace v8 {
12 namespace internal {
13 
14 namespace {
15 
16 // Temporal #prod-NonzeroDigit
IsNonZeroDecimalDigit(base::uc32 c)17 inline constexpr bool IsNonZeroDecimalDigit(base::uc32 c) {
18   return base::IsInRange(c, '1', '9');
19 }
20 
21 // Temporal #prod-TZLeadingChar
IsTZLeadingChar(base::uc32 c)22 inline constexpr bool IsTZLeadingChar(base::uc32 c) {
23   return base::IsInRange(AsciiAlphaToLower(c), 'a', 'z') || c == '.' ||
24          c == '_';
25 }
26 
27 // Temporal #prod-TZChar
IsTZChar(base::uc32 c)28 inline constexpr bool IsTZChar(base::uc32 c) {
29   return IsTZLeadingChar(c) || c == '-';
30 }
31 
32 // Temporal #prod-DecimalSeparator
IsDecimalSeparator(base::uc32 c)33 inline constexpr bool IsDecimalSeparator(base::uc32 c) {
34   return c == '.' || c == ',';
35 }
36 
37 // Temporal #prod-DateTimeSeparator
IsDateTimeSeparator(base::uc32 c)38 inline constexpr bool IsDateTimeSeparator(base::uc32 c) {
39   return c == ' ' || AsciiAlphaToLower(c) == 't';
40 }
41 
42 // Temporal #prod-ASCIISign
IsAsciiSign(base::uc32 c)43 inline constexpr bool IsAsciiSign(base::uc32 c) { return c == '-' || c == '+'; }
44 
45 // Temporal #prod-Sign
IsSign(base::uc32 c)46 inline constexpr bool IsSign(base::uc32 c) {
47   return c == 0x2212 || IsAsciiSign(c);
48 }
49 
CanonicalSign(base::uc32 c)50 inline constexpr base::uc32 CanonicalSign(base::uc32 c) {
51   return c == 0x2212 ? '-' : c;
52 }
53 
ToInt(base::uc32 c)54 inline constexpr int32_t ToInt(base::uc32 c) { return c - '0'; }
55 
56 /**
57  * The TemporalParser use two types of internal routine:
58  * - Scan routines: Follow the function signature below:
59  *   template <typename Char> int32_t Scan$ProductionName(
60  *   base::Vector<Char> str, int32_t s, R* out)
61  *
62  *   These routine scan the next item from position s in str and store the
63  *   parsed result into out if the expected string is successfully scanned.
64  *   It return the length of matched text from s or 0 to indicate no
65  *   expected item matched.
66  *
67  * - Satisfy routines: Follow the function sigature below:
68  *   template <typename Char>
69  *   bool Satisfy$ProductionName(base::Vector<Char> str, R* r);
70  *   It scan from the beginning of the str by calling Scan routines to put
71  *   parsed result into r and return true if the entire str satisfy the
72  *   production. It internally use Scan routines.
73  *
74  * TODO(ftang) investigate refactoring to class before shipping
75  * Reference to RegExpParserImpl by encapsulating the cursor position and
76  * only manipulating the current character and position with Next(),
77  * Advance(), current(), etc
78  */
79 
80 // For Hour Production
81 // Hour:
82 //   [0 1] Digit
83 //   2 [0 1 2 3]
84 template <typename Char>
IsHour(base::Vector<Char> str,int32_t s)85 bool IsHour(base::Vector<Char> str, int32_t s) {
86   return (str.length() >= (s + 2)) &&
87          ((base::IsInRange(str[s], '0', '1') && IsDecimalDigit(str[s + 1])) ||
88           ((str[s] == '2') && base::IsInRange(str[s + 1], '0', '3')));
89 }
90 
91 template <typename Char>
ScanHour(base::Vector<Char> str,int32_t s,int32_t * out)92 int32_t ScanHour(base::Vector<Char> str, int32_t s, int32_t* out) {
93   if (!IsHour(str, s)) return 0;
94   *out = ToInt(str[s]) * 10 + ToInt(str[s + 1]);
95   return 2;
96 }
97 
98 // MinuteSecond:
99 //   [0 1 2 3 4 5] Digit
100 template <typename Char>
IsMinuteSecond(base::Vector<Char> str,int32_t s)101 bool IsMinuteSecond(base::Vector<Char> str, int32_t s) {
102   return (str.length() >= (s + 2)) &&
103          (base::IsInRange(str[s], '0', '5') && IsDecimalDigit(str[s + 1]));
104 }
105 
106 template <typename Char>
ScanMinuteSecond(base::Vector<Char> str,int32_t s,int32_t * out)107 int32_t ScanMinuteSecond(base::Vector<Char> str, int32_t s, int32_t* out) {
108   if (!IsMinuteSecond(str, s)) return 0;
109   *out = ToInt(str[s]) * 10 + ToInt(str[s + 1]);
110   return 2;
111 }
112 
113 // For the forward production in the grammar such as
114 // ProductionB:
115 //   ProductionT
116 #define SCAN_FORWARD(B, T, R)                                \
117   template <typename Char>                                   \
118   int32_t Scan##B(base::Vector<Char> str, int32_t s, R* r) { \
119     return Scan##T(str, s, r);                               \
120   }
121 
122 // Same as above but store the result into a particular field in R
123 
124 // For the forward production in the grammar such as
125 // ProductionB:
126 //   ProductionT1
127 //   ProductionT2
128 #define SCAN_EITHER_FORWARD(B, T1, T2, R)                    \
129   template <typename Char>                                   \
130   int32_t Scan##B(base::Vector<Char> str, int32_t s, R* r) { \
131     int32_t len;                                             \
132     if ((len = Scan##T1(str, s, r)) > 0) return len;         \
133     return Scan##T2(str, s, r);                              \
134   }
135 
136 // TimeHour: Hour
SCAN_FORWARD(TimeHour,Hour,int32_t)137 SCAN_FORWARD(TimeHour, Hour, int32_t)
138 
139 // TimeMinute: MinuteSecond
140 SCAN_FORWARD(TimeMinute, MinuteSecond, int32_t)
141 
142 // TimeSecond:
143 //   MinuteSecond
144 //   60
145 template <typename Char>
146 int32_t ScanTimeSecond(base::Vector<Char> str, int32_t s, int32_t* out) {
147   int32_t len = ScanMinuteSecond(str, s, out);
148   // MinuteSecond
149   if (len > 0) return len;
150   if ((str.length() < (s + 2)) || (str[s] != '6') || (str[s + 1] != '0')) {
151     return 0;
152   }
153   // 60
154   *out = 60;
155   return 2;
156 }
157 
158 constexpr int kPowerOfTen[] = {1,      10,      100,      1000,     10000,
159                                100000, 1000000, 10000000, 100000000};
160 
161 // FractionalPart : Digit{1,9}
162 template <typename Char>
ScanFractionalPart(base::Vector<Char> str,int32_t s,int32_t * out)163 int32_t ScanFractionalPart(base::Vector<Char> str, int32_t s, int32_t* out) {
164   int32_t cur = s;
165   if ((str.length() < (cur + 1)) || !IsDecimalDigit(str[cur])) return 0;
166   *out = ToInt(str[cur++]);
167   while ((cur < str.length()) && ((cur - s) < 9) && IsDecimalDigit(str[cur])) {
168     *out = 10 * (*out) + ToInt(str[cur++]);
169   }
170   *out *= kPowerOfTen[9 - (cur - s)];
171   return cur - s;
172 }
173 
174 template <typename Char>
ScanFractionalPart(base::Vector<Char> str,int32_t s,int64_t * out)175 int32_t ScanFractionalPart(base::Vector<Char> str, int32_t s, int64_t* out) {
176   int32_t out32;
177   int32_t len = ScanFractionalPart(str, s, &out32);
178   *out = out32;
179   return len;
180 }
181 
182 // TimeFraction: FractionalPart
SCAN_FORWARD(TimeFractionalPart,FractionalPart,int32_t)183 SCAN_FORWARD(TimeFractionalPart, FractionalPart, int32_t)
184 
185 // Fraction: DecimalSeparator FractionalPart
186 // DecimalSeparator: one of , .
187 template <typename Char>
188 int32_t ScanFraction(base::Vector<Char> str, int32_t s, int32_t* out) {
189   if ((str.length() < (s + 2)) || (!IsDecimalSeparator(str[s]))) return 0;
190   int32_t len;
191   if ((len = ScanFractionalPart(str, s + 1, out)) == 0) return 0;
192   return len + 1;
193 }
194 
195 // TimeFraction: DecimalSeparator TimeFractionalPart
196 // DecimalSeparator: one of , .
197 template <typename Char>
ScanTimeFraction(base::Vector<Char> str,int32_t s,int32_t * out)198 int32_t ScanTimeFraction(base::Vector<Char> str, int32_t s, int32_t* out) {
199   if ((str.length() < (s + 2)) || (!IsDecimalSeparator(str[s]))) return 0;
200   int32_t len;
201   if ((len = ScanTimeFractionalPart(str, s + 1, out)) == 0) return 0;
202   return len + 1;
203 }
204 
205 template <typename Char>
ScanTimeFraction(base::Vector<Char> str,int32_t s,ParsedISO8601Result * r)206 int32_t ScanTimeFraction(base::Vector<Char> str, int32_t s,
207                          ParsedISO8601Result* r) {
208   return ScanTimeFraction(str, s, &(r->time_nanosecond));
209 }
210 
211 // TimeSpec:
212 //  TimeHour
213 //  TimeHour : TimeMinute
214 //  TimeHour : TimeMinute : TimeSecond [TimeFraction]
215 //  TimeHour TimeMinute
216 //  TimeHour TimeMinute TimeSecond [TimeFraction]
217 template <typename Char>
ScanTimeSpec(base::Vector<Char> str,int32_t s,ParsedISO8601Result * r)218 int32_t ScanTimeSpec(base::Vector<Char> str, int32_t s,
219                      ParsedISO8601Result* r) {
220   int32_t time_hour, time_minute, time_second;
221   int32_t len;
222   int32_t cur = s;
223   if ((len = ScanTimeHour(str, cur, &time_hour)) == 0) return 0;
224   cur += len;
225   if ((cur + 1) > str.length()) {
226     // TimeHour
227     r->time_hour = time_hour;
228     return cur - s;
229   }
230   if (str[cur] == ':') {
231     cur++;
232     if ((len = ScanTimeMinute(str, cur, &time_minute)) == 0) return 0;
233     cur += len;
234     if ((cur + 1) > str.length() || (str[cur] != ':')) {
235       // TimeHour : TimeMinute
236       r->time_hour = time_hour;
237       r->time_minute = time_minute;
238       return cur - s;
239     }
240     cur++;
241     if ((len = ScanTimeSecond(str, cur, &time_second)) == 0) return 0;
242   } else {
243     if ((len = ScanTimeMinute(str, cur, &time_minute)) == 0) {
244       // TimeHour
245       r->time_hour = time_hour;
246       return cur - s;
247     }
248     cur += len;
249     if ((len = ScanTimeSecond(str, cur, &time_second)) == 0) {
250       // TimeHour TimeMinute
251       r->time_hour = time_hour;
252       r->time_minute = time_minute;
253       return cur - s;
254     }
255   }
256   cur += len;
257   len = ScanTimeFraction(str, cur, r);
258   r->time_hour = time_hour;
259   r->time_minute = time_minute;
260   r->time_second = time_second;
261   return cur + len - s;
262 }
263 
264 // TimeSpecSeparator: DateTimeSeparator TimeSpec
265 // DateTimeSeparator: SPACE, 't', or 'T'
266 template <typename Char>
ScanTimeSpecSeparator(base::Vector<Char> str,int32_t s,ParsedISO8601Result * r)267 int32_t ScanTimeSpecSeparator(base::Vector<Char> str, int32_t s,
268                               ParsedISO8601Result* r) {
269   if (!(((s + 1) < str.length()) && IsDateTimeSeparator(str[s]))) return 0;
270   int32_t len = ScanTimeSpec(str, s + 1, r);
271   return (len == 0) ? 0 : len + 1;
272 }
273 
274 // DateExtendedYear: Sign Digit Digit Digit Digit Digit Digit
275 template <typename Char>
ScanDateExtendedYear(base::Vector<Char> str,int32_t s,int32_t * out)276 int32_t ScanDateExtendedYear(base::Vector<Char> str, int32_t s, int32_t* out) {
277   if (str.length() < (s + 7)) return 0;
278   if (IsSign(str[s]) && IsDecimalDigit(str[s + 1]) &&
279       IsDecimalDigit(str[s + 2]) && IsDecimalDigit(str[s + 3]) &&
280       IsDecimalDigit(str[s + 4]) && IsDecimalDigit(str[s + 5]) &&
281       IsDecimalDigit(str[s + 6])) {
282     int32_t sign = (CanonicalSign(str[s]) == '-') ? -1 : 1;
283     *out = sign * (ToInt(str[s + 1]) * 100000 + ToInt(str[s + 2]) * 10000 +
284                    ToInt(str[s + 3]) * 1000 + ToInt(str[s + 4]) * 100 +
285                    ToInt(str[s + 5]) * 10 + ToInt(str[s + 6]));
286     return 7;
287   }
288   return 0;
289 }
290 
291 // DateFourDigitYear: Digit Digit Digit Digit
292 template <typename Char>
ScanDateFourDigitYear(base::Vector<Char> str,int32_t s,int32_t * out)293 int32_t ScanDateFourDigitYear(base::Vector<Char> str, int32_t s, int32_t* out) {
294   if (str.length() < (s + 4)) return 0;
295   if (IsDecimalDigit(str[s]) && IsDecimalDigit(str[s + 1]) &&
296       IsDecimalDigit(str[s + 2]) && IsDecimalDigit(str[s + 3])) {
297     *out = ToInt(str[s]) * 1000 + ToInt(str[s + 1]) * 100 +
298            ToInt(str[s + 2]) * 10 + ToInt(str[s + 3]);
299     return 4;
300   }
301   return 0;
302 }
303 
304 // DateYear:
305 //   DateFourDigitYear
306 //   DateExtendedYear
307 // The lookahead is at most 1 char.
SCAN_EITHER_FORWARD(DateYear,DateFourDigitYear,DateExtendedYear,int32_t)308 SCAN_EITHER_FORWARD(DateYear, DateFourDigitYear, DateExtendedYear, int32_t)
309 
310 // DateMonth:
311 //   0 NonzeroDigit
312 //   10
313 //   11
314 //   12
315 template <typename Char>
316 int32_t ScanDateMonth(base::Vector<Char> str, int32_t s, int32_t* out) {
317   if (str.length() < (s + 2)) return 0;
318   if (((str[s] == '0') && IsNonZeroDecimalDigit(str[s + 1])) ||
319       ((str[s] == '1') && base::IsInRange(str[s + 1], '0', '2'))) {
320     *out = ToInt(str[s]) * 10 + ToInt(str[s + 1]);
321     return 2;
322   }
323   return 0;
324 }
325 
326 // DateDay:
327 //   0 NonzeroDigit
328 //   1 Digit
329 //   2 Digit
330 //   30
331 //   31
332 template <typename Char>
ScanDateDay(base::Vector<Char> str,int32_t s,int32_t * out)333 int32_t ScanDateDay(base::Vector<Char> str, int32_t s, int32_t* out) {
334   if (str.length() < (s + 2)) return 0;
335   if (((str[s] == '0') && IsNonZeroDecimalDigit(str[s + 1])) ||
336       (base::IsInRange(str[s], '1', '2') && IsDecimalDigit(str[s + 1])) ||
337       ((str[s] == '3') && base::IsInRange(str[s + 1], '0', '1'))) {
338     *out = ToInt(str[s]) * 10 + ToInt(str[s + 1]);
339     return 2;
340   }
341   return 0;
342 }
343 
344 // Date:
345 //   DateYear - DateMonth - DateDay
346 //   DateYear DateMonth DateDay
347 template <typename Char>
ScanDate(base::Vector<Char> str,int32_t s,ParsedISO8601Result * r)348 int32_t ScanDate(base::Vector<Char> str, int32_t s, ParsedISO8601Result* r) {
349   int32_t date_year, date_month, date_day;
350   int32_t cur = s;
351   int32_t len;
352   if ((len = ScanDateYear(str, cur, &date_year)) == 0) return 0;
353   if (((cur += len) + 1) > str.length()) return 0;
354   if (str[cur] == '-') {
355     cur++;
356     if ((len = ScanDateMonth(str, cur, &date_month)) == 0) return 0;
357     cur += len;
358     if (((cur + 1) > str.length()) || (str[cur++] != '-')) return 0;
359   } else {
360     if ((len = ScanDateMonth(str, cur, &date_month)) == 0) return 0;
361     cur += len;
362   }
363   if ((len = ScanDateDay(str, cur, &date_day)) == 0) return 0;
364   r->date_year = date_year;
365   r->date_month = date_month;
366   r->date_day = date_day;
367   return cur + len - s;
368 }
369 
370 // TimeZoneUTCOffsetHour: Hour
SCAN_FORWARD(TimeZoneUTCOffsetHour,Hour,int32_t)371 SCAN_FORWARD(TimeZoneUTCOffsetHour, Hour, int32_t)
372 
373 // TimeZoneUTCOffsetMinute
374 SCAN_FORWARD(TimeZoneUTCOffsetMinute, MinuteSecond, int32_t)
375 
376 // TimeZoneUTCOffsetSecond
377 SCAN_FORWARD(TimeZoneUTCOffsetSecond, MinuteSecond, int32_t)
378 
379 // TimeZoneUTCOffsetFractionalPart: FractionalPart
380 // See PR1796
381 SCAN_FORWARD(TimeZoneUTCOffsetFractionalPart, FractionalPart, int32_t)
382 
383 // TimeZoneUTCOffsetFraction: DecimalSeparator TimeZoneUTCOffsetFractionalPart
384 // See PR1796
385 template <typename Char>
386 int32_t ScanTimeZoneUTCOffsetFraction(base::Vector<Char> str, int32_t s,
387                                       int32_t* out) {
388   if ((str.length() < (s + 2)) || (!IsDecimalSeparator(str[s]))) return 0;
389   int32_t len;
390   if ((len = ScanTimeZoneUTCOffsetFractionalPart(str, s + 1, out)) > 0) {
391     return len + 1;
392   }
393   return 0;
394 }
395 
396 // Note: "TimeZoneUTCOffset" is abbreviated as "TZUO" below
397 // TimeZoneNumericUTCOffset:
398 //   TZUOSign TZUOHour
399 //   TZUOSign TZUOHour : TZUOMinute
400 //   TZUOSign TZUOHour : TZUOMinute : TZUOSecond [TZUOFraction]
401 //   TZUOSign TZUOHour TZUOMinute
402 //   TZUOSign TZUOHour TZUOMinute TZUOSecond [TZUOFraction]
403 template <typename Char>
ScanTimeZoneNumericUTCOffset(base::Vector<Char> str,int32_t s,ParsedISO8601Result * r)404 int32_t ScanTimeZoneNumericUTCOffset(base::Vector<Char> str, int32_t s,
405                                      ParsedISO8601Result* r) {
406   int32_t len, hour, minute, second, nanosecond;
407   int32_t cur = s;
408   if ((str.length() < (cur + 1)) || (!IsSign(str[cur]))) return 0;
409   int32_t sign = (CanonicalSign(str[cur++]) == '-') ? -1 : 1;
410   if ((len = ScanTimeZoneUTCOffsetHour(str, cur, &hour)) == 0) return 0;
411   cur += len;
412   if ((cur + 1) > str.length()) {
413     // TZUOSign TZUOHour
414     r->tzuo_sign = sign;
415     r->tzuo_hour = hour;
416     return cur - s;
417   }
418   if (str[cur] == ':') {
419     cur++;
420     if ((len = ScanTimeZoneUTCOffsetMinute(str, cur, &minute)) == 0) return 0;
421     cur += len;
422     if ((cur + 1) > str.length() || str[cur] != ':') {
423       // TZUOSign TZUOHour : TZUOMinute
424       r->tzuo_sign = sign;
425       r->tzuo_hour = hour;
426       r->tzuo_minute = minute;
427       return cur - s;
428     }
429     cur++;
430     if ((len = ScanTimeZoneUTCOffsetSecond(str, cur, &second)) == 0) return 0;
431   } else {
432     if ((len = ScanTimeZoneUTCOffsetMinute(str, cur, &minute)) == 0) {
433       // TZUOSign TZUOHour
434       r->tzuo_sign = sign;
435       r->tzuo_hour = hour;
436       return cur - s;
437     }
438     cur += len;
439     if ((len = ScanTimeZoneUTCOffsetSecond(str, cur, &second)) == 0) {
440       // TZUOSign TZUOHour TZUOMinute
441       r->tzuo_sign = sign;
442       r->tzuo_hour = hour;
443       r->tzuo_minute = minute;
444       return cur - s;
445     }
446   }
447   cur += len;
448   len = ScanTimeZoneUTCOffsetFraction(str, cur, &nanosecond);
449   r->tzuo_sign = sign;
450   r->tzuo_hour = hour;
451   r->tzuo_minute = minute;
452   r->tzuo_second = second;
453   if (len > 0) r->tzuo_nanosecond = nanosecond;
454   return cur + len - s;
455 }
456 
457 // TimeZoneUTCOffset:
458 //   TimeZoneNumericUTCOffset
459 //   UTCDesignator
460 template <typename Char>
ScanTimeZoneUTCOffset(base::Vector<Char> str,int32_t s,ParsedISO8601Result * r)461 int32_t ScanTimeZoneUTCOffset(base::Vector<Char> str, int32_t s,
462                               ParsedISO8601Result* r) {
463   if (str.length() < (s + 1)) return 0;
464   if (AsciiAlphaToLower(str[s]) == 'z') {
465     // UTCDesignator
466     r->utc_designator = true;
467     return 1;
468   }
469   // TimeZoneNumericUTCOffset
470   return ScanTimeZoneNumericUTCOffset(str, s, r);
471 }
472 
473 // TimeZoneIANANameComponent :
474 //   TZLeadingChar TZChar{0,13} but not one of . or ..
475 template <typename Char>
ScanTimeZoneIANANameComponent(base::Vector<Char> str,int32_t s)476 int32_t ScanTimeZoneIANANameComponent(base::Vector<Char> str, int32_t s) {
477   int32_t cur = s;
478   if (str.length() < (cur + 1) || !IsTZLeadingChar(str[cur++])) return 0;
479   while (((cur) < str.length()) && ((cur - s) < 14) && IsTZChar(str[cur])) {
480     cur++;
481   }
482   if ((cur - s) == 1 && str[s] == '.') return 0;
483   if ((cur - s) == 2 && str[s] == '.' && str[s + 1] == '.') return 0;
484   return cur - s;
485 }
486 
487 // TimeZoneIANANameTail :
488 //   TimeZoneIANANameComponent
489 //   TimeZoneIANANameComponent / TimeZoneIANANameTail
490 // TimeZoneIANAName :
491 //   TimeZoneIANANameTail
492 // The spec text use tail recusion with TimeZoneIANANameComponent and
493 // TimeZoneIANANameTail. In our implementation, we use an iteration loop
494 // instead.
495 template <typename Char>
ScanTimeZoneIANAName(base::Vector<Char> str,int32_t s)496 int32_t ScanTimeZoneIANAName(base::Vector<Char> str, int32_t s) {
497   int32_t cur = s;
498   int32_t len;
499   if ((len = ScanTimeZoneIANANameComponent(str, cur)) == 0) return 0;
500   cur += len;
501   while ((str.length() > (cur + 1)) && (str[cur] == '/')) {
502     cur++;
503     if ((len = ScanTimeZoneIANANameComponent(str, cur)) == 0) {
504       return 0;
505     }
506     // TimeZoneIANANameComponent / TimeZoneIANAName
507     cur += len;
508   }
509   return cur - s;
510 }
511 
512 template <typename Char>
ScanTimeZoneIANAName(base::Vector<Char> str,int32_t s,ParsedISO8601Result * r)513 int32_t ScanTimeZoneIANAName(base::Vector<Char> str, int32_t s,
514                              ParsedISO8601Result* r) {
515   int32_t len;
516   if ((len = ScanTimeZoneIANAName(str, s)) == 0) return 0;
517   r->tzi_name_start = s;
518   r->tzi_name_length = len;
519   return len;
520 }
521 
522 // TimeZoneUTCOffsetName
523 //   Sign Hour
524 //   Sign Hour : MinuteSecond
525 //   Sign Hour MinuteSecond
526 //   Sign Hour : MinuteSecond : MinuteSecond [Fraction]
527 //   Sign Hour MinuteSecond MinuteSecond [Fraction]
528 //
529 template <typename Char>
ScanTimeZoneUTCOffsetName(base::Vector<Char> str,int32_t s)530 int32_t ScanTimeZoneUTCOffsetName(base::Vector<Char> str, int32_t s) {
531   int32_t cur = s;
532   int32_t len;
533   if ((str.length() < (s + 3)) || !IsSign(str[cur++])) return 0;
534   int32_t hour, minute, second, fraction;
535   if ((len = ScanHour(str, cur, &hour)) == 0) return 0;
536   cur += len;
537   if ((cur + 1) > str.length()) {
538     // Sign Hour
539     return cur - s;
540   }
541   if (str[cur] == ':') {
542     // Sign Hour :
543     cur++;
544     if ((len = ScanMinuteSecond(str, cur, &minute)) == 0) return 0;
545     cur += len;
546     if ((cur + 1) > str.length() || (str[cur] != ':')) {
547       // Sign Hour : MinuteSecond
548       return cur - s;
549     }
550     cur++;
551     // Sign Hour : MinuteSecond :
552     if ((len = ScanMinuteSecond(str, cur, &second)) == 0) return 0;
553     cur += len;
554     len = ScanFraction(str, cur, &fraction);
555     return cur + len - s;
556   } else {
557     if ((len = ScanMinuteSecond(str, cur, &minute)) == 0) {
558       // Sign Hour
559       return cur - s;
560     }
561     cur += len;
562     if ((len = ScanMinuteSecond(str, cur, &second)) == 0) {
563       // Sign Hour MinuteSecond
564       return cur - s;
565     }
566     cur += len;
567     len = ScanFraction(str, cur, &fraction);
568     //  Sign Hour MinuteSecond MinuteSecond [Fraction]
569     return cur + len - s;
570   }
571 }
572 
573 // TimeZoneBracketedName
574 //   TimeZoneIANAName
575 //   "Etc/GMT" ASCIISign Hour
576 //   TimeZoneUTCOffsetName
577 // Since "Etc/GMT" also fit TimeZoneIANAName so we need to try
578 // "Etc/GMT" ASCIISign Hour first.
579 template <typename Char>
ScanEtcGMTAsciiSignHour(base::Vector<Char> str,int32_t s)580 int32_t ScanEtcGMTAsciiSignHour(base::Vector<Char> str, int32_t s) {
581   if ((s + 10) > str.length()) return 0;
582   int32_t cur = s;
583   if ((str[cur++] != 'E') || (str[cur++] != 't') || (str[cur++] != 'c') ||
584       (str[cur++] != '/') || (str[cur++] != 'G') || (str[cur++] != 'M') ||
585       (str[cur++] != 'T')) {
586     return 0;
587   }
588   Char sign = str[cur++];
589   if (!IsAsciiSign(sign)) return 0;
590   int32_t hour;
591   int32_t len = ScanHour(str, cur, &hour);
592   if (len == 0) return 0;
593   //   "Etc/GMT" ASCIISign Hour
594   return 10;
595 }
596 
597 template <typename Char>
ScanTimeZoneBracketedName(base::Vector<Char> str,int32_t s,ParsedISO8601Result * r)598 int32_t ScanTimeZoneBracketedName(base::Vector<Char> str, int32_t s,
599                                   ParsedISO8601Result* r) {
600   int32_t len;
601   if ((len = ScanEtcGMTAsciiSignHour(str, s)) > 0) return len;
602   if ((len = ScanTimeZoneIANAName(str, s)) > 0) {
603     r->tzi_name_start = s;
604     r->tzi_name_length = len;
605     return len;
606   }
607   return ScanTimeZoneUTCOffsetName(str, s);
608 }
609 
610 // TimeZoneBracketedAnnotation: '[' TimeZoneBracketedName ']'
611 template <typename Char>
ScanTimeZoneBracketedAnnotation(base::Vector<Char> str,int32_t s,ParsedISO8601Result * r)612 int32_t ScanTimeZoneBracketedAnnotation(base::Vector<Char> str, int32_t s,
613                                         ParsedISO8601Result* r) {
614   if ((str.length() < (s + 3)) || (str[s] != '[')) return 0;
615   int32_t cur = s + 1;
616   cur += ScanTimeZoneBracketedName(str, cur, r);
617   if ((cur - s == 1) || str.length() < (cur + 1) || (str[cur++] != ']')) {
618     return 0;
619   }
620   return cur - s;
621 }
622 
623 // TimeZoneOffsetRequired:
624 //   TimeZoneUTCOffset [TimeZoneBracketedAnnotation]
625 template <typename Char>
ScanTimeZoneOffsetRequired(base::Vector<Char> str,int32_t s,ParsedISO8601Result * r)626 int32_t ScanTimeZoneOffsetRequired(base::Vector<Char> str, int32_t s,
627                                    ParsedISO8601Result* r) {
628   int32_t cur = s;
629   cur += ScanTimeZoneUTCOffset(str, cur, r);
630   if (cur == s) return 0;
631   return cur + ScanTimeZoneBracketedAnnotation(str, cur, r) - s;
632 }
633 
634 //   TimeZoneNameRequired:
635 //   [TimeZoneUTCOffset] TimeZoneBracketedAnnotation
636 template <typename Char>
ScanTimeZoneNameRequired(base::Vector<Char> str,int32_t s,ParsedISO8601Result * r)637 int32_t ScanTimeZoneNameRequired(base::Vector<Char> str, int32_t s,
638                                  ParsedISO8601Result* r) {
639   int32_t cur = s;
640   cur += ScanTimeZoneUTCOffset(str, cur, r);
641   int32_t len = ScanTimeZoneBracketedAnnotation(str, cur, r);
642   if (len == 0) return 0;
643   return cur + len - s;
644 }
645 
646 // TimeZone:
647 //   TimeZoneOffsetRequired
648 //   TimeZoneNameRequired
649 // The lookahead is at most 1 char.
SCAN_EITHER_FORWARD(TimeZone,TimeZoneOffsetRequired,TimeZoneNameRequired,ParsedISO8601Result)650 SCAN_EITHER_FORWARD(TimeZone, TimeZoneOffsetRequired, TimeZoneNameRequired,
651                     ParsedISO8601Result)
652 
653 // CalendarNameComponent:
654 //   CalChar {3,8}
655 template <typename Char>
656 int32_t ScanCalendarNameComponent(base::Vector<Char> str, int32_t s) {
657   int32_t cur = s;
658   while ((cur < str.length()) && IsAlphaNumeric(str[cur])) cur++;
659   if ((cur - s) < 3 || (cur - s) > 8) return 0;
660   return (cur - s);
661 }
662 
663 // CalendarNameTail :
664 //   CalendarNameComponent
665 //   CalendarNameComponent - CalendarNameTail
666 // CalendarName :
667 //   CalendarNameTail
668 // The spec text use tail recusion with CalendarNameComponent and
669 // CalendarNameTail. In our implementation, we use an iteration loop instead.
670 template <typename Char>
ScanCalendarName(base::Vector<Char> str,int32_t s,ParsedISO8601Result * r)671 int32_t ScanCalendarName(base::Vector<Char> str, int32_t s,
672                          ParsedISO8601Result* r) {
673   int32_t cur = s;
674   int32_t len;
675   if ((len = ScanCalendarNameComponent(str, cur)) == 0) return 0;
676   cur += len;
677   while ((str.length() > (cur + 1)) && (str[cur++] == '-')) {
678     if ((len = ScanCalendarNameComponent(str, cur)) == 0) return 0;
679     // CalendarNameComponent - CalendarName
680     cur += len;
681   }
682   r->calendar_name_start = s;
683   r->calendar_name_length = cur - s;
684   return cur - s;
685 }
686 
687 // Calendar: '[u-ca=' CalendarName ']'
688 template <typename Char>
ScanCalendar(base::Vector<Char> str,int32_t s,ParsedISO8601Result * r)689 int32_t ScanCalendar(base::Vector<Char> str, int32_t s,
690                      ParsedISO8601Result* r) {
691   if (str.length() < (s + 7)) return 0;
692   int32_t cur = s;
693   // "[u-ca="
694   if ((str[cur++] != '[') || (str[cur++] != 'u') || (str[cur++] != '-') ||
695       (str[cur++] != 'c') || (str[cur++] != 'a') || (str[cur++] != '=')) {
696     return 0;
697   }
698   int32_t len = ScanCalendarName(str, cur, r);
699   if (len == 0) return 0;
700   if ((str.length() < (cur + len + 1)) || (str[cur + len] != ']')) {
701     return 0;
702   }
703   return 6 + len + 1;
704 }
705 
706 // CalendarTime: TimeSpec [TimeZone] [Calendar]
707 template <typename Char>
ScanCalendarTime(base::Vector<Char> str,int32_t s,ParsedISO8601Result * r)708 int32_t ScanCalendarTime(base::Vector<Char> str, int32_t s,
709                          ParsedISO8601Result* r) {
710   int32_t cur = s;
711   cur += ScanTimeSpec(str, cur, r);
712   if (cur - s == 0) return 0;
713   cur += ScanTimeZone(str, cur, r);
714   cur += ScanCalendar(str, cur, r);
715   return cur - s;
716 }
717 
718 // DateTime: Date [TimeSpecSeparator][TimeZone]
719 template <typename Char>
ScanDateTime(base::Vector<Char> str,int32_t s,ParsedISO8601Result * r)720 int32_t ScanDateTime(base::Vector<Char> str, int32_t s,
721                      ParsedISO8601Result* r) {
722   int32_t cur = s;
723   cur += ScanDate(str, cur, r);
724   if (cur == s) return 0;
725   cur += ScanTimeSpecSeparator(str, cur, r);
726   return cur + ScanTimeZone(str, cur, r) - s;
727 }
728 
729 // DateSpecYearMonth: DateYear ['-'] DateMonth
730 template <typename Char>
ScanDateSpecYearMonth(base::Vector<Char> str,int32_t s,ParsedISO8601Result * r)731 int32_t ScanDateSpecYearMonth(base::Vector<Char> str, int32_t s,
732                               ParsedISO8601Result* r) {
733   int32_t date_year, date_month;
734   int32_t cur = s;
735   cur += ScanDateYear(str, cur, &date_year);
736   if (cur == s) return 0;
737   if (str.length() < (cur + 1)) return 0;
738   if (str[cur] == '-') cur++;
739   int32_t len = ScanDateMonth(str, cur, &date_month);
740   if (len == 0) return 0;
741   r->date_year = date_year;
742   r->date_month = date_month;
743   return cur + len - s;
744 }
745 
746 // DateSpecMonthDay:
747 // TwoDashopt DateMonth -opt DateDay
748 template <typename Char>
ScanDateSpecMonthDay(base::Vector<Char> str,int32_t s,ParsedISO8601Result * r)749 int32_t ScanDateSpecMonthDay(base::Vector<Char> str, int32_t s,
750                              ParsedISO8601Result* r) {
751   if (str.length() < (s + 4)) return 0;
752   int32_t cur = s;
753   if (str[cur] == '-') {
754     // The first two dash are optional together
755     if (str[++cur] != '-') return 0;
756     // TwoDash
757     cur++;
758   }
759   int32_t date_month, date_day;
760   int32_t len = ScanDateMonth(str, cur, &date_month);
761   if (len == 0) return 0;
762   cur += len;
763   if (str.length() < (cur + 1)) return 0;
764   // '-'
765   if (str[cur] == '-') cur++;
766   len = ScanDateDay(str, cur, &date_day);
767   if (len == 0) return 0;
768   r->date_month = date_month;
769   r->date_day = date_day;
770   return cur + len - s;
771 }
772 
773 // TemporalTimeZoneIdentifier:
774 //   TimeZoneNumericUTCOffset
775 //   TimeZoneIANAName
776 template <typename Char>
ScanTemporalTimeZoneIdentifier(base::Vector<Char> str,int32_t s,ParsedISO8601Result * r)777 int32_t ScanTemporalTimeZoneIdentifier(base::Vector<Char> str, int32_t s,
778                                        ParsedISO8601Result* r) {
779   int32_t len;
780   if ((len = ScanTimeZoneNumericUTCOffset(str, s, r)) > 0) return len;
781   if ((len = ScanTimeZoneIANAName(str, s)) == 0) return 0;
782   r->tzi_name_start = s;
783   r->tzi_name_length = len;
784   return len;
785 }
786 
787 // CalendarDateTime: DateTime [Calendar]
788 template <typename Char>
ScanCalendarDateTime(base::Vector<Char> str,int32_t s,ParsedISO8601Result * r)789 int32_t ScanCalendarDateTime(base::Vector<Char> str, int32_t s,
790                              ParsedISO8601Result* r) {
791   int32_t len = ScanDateTime(str, 0, r);
792   if (len == 0) return 0;
793   return len + ScanCalendar(str, len, r);
794 }
795 
796 // TemporalZonedDateTimeString:
797 //   Date [TimeSpecSeparator] TimeZoneNameRequired [Calendar]
798 template <typename Char>
ScanTemporalZonedDateTimeString(base::Vector<Char> str,int32_t s,ParsedISO8601Result * r)799 int32_t ScanTemporalZonedDateTimeString(base::Vector<Char> str, int32_t s,
800                                         ParsedISO8601Result* r) {
801   // Date
802   int32_t cur = s;
803   cur += ScanDate(str, cur, r);
804   if (cur == s) return 0;
805 
806   // TimeSpecSeparator
807   cur += ScanTimeSpecSeparator(str, cur, r);
808 
809   // TimeZoneNameRequired
810   int32_t len = ScanTimeZoneNameRequired(str, cur, r);
811   if (len == 0) return 0;
812   cur += len;
813 
814   // Calendar
815   return cur + ScanCalendar(str, cur, r) - s;
816 }
817 
SCAN_FORWARD(TemporalDateString,CalendarDateTime,ParsedISO8601Result)818 SCAN_FORWARD(TemporalDateString, CalendarDateTime, ParsedISO8601Result)
819 SCAN_FORWARD(TemporalDateTimeString, CalendarDateTime, ParsedISO8601Result)
820 
821 // TemporalTimeZoneString:
822 //   TemporalTimeZoneIdentifier
823 //   Date [TimeSpecSeparator] TimeZone [Calendar]
824 template <typename Char>
825 int32_t ScanDate_TimeSpecSeparator_TimeZone_Calendar(base::Vector<Char> str,
826                                                      int32_t s,
827                                                      ParsedISO8601Result* r) {
828   int32_t cur = s;
829   cur += ScanDate(str, cur, r);
830   if (cur == s) return 0;
831   cur += ScanTimeSpecSeparator(str, cur, r);
832   int32_t len = ScanTimeZone(str, cur, r);
833   if (len == 0) return 0;
834   cur += len;
835   return cur + ScanCalendar(str, cur, r) - s;
836 }
837 
838 // The lookahead is at most 8 chars.
SCAN_EITHER_FORWARD(TemporalTimeZoneString,TemporalTimeZoneIdentifier,Date_TimeSpecSeparator_TimeZone_Calendar,ParsedISO8601Result)839 SCAN_EITHER_FORWARD(TemporalTimeZoneString, TemporalTimeZoneIdentifier,
840                     Date_TimeSpecSeparator_TimeZone_Calendar,
841                     ParsedISO8601Result)
842 
843 // TemporalTimeString
844 //   CalendarTime
845 //   CalendarDateTime
846 // The lookahead is at most 7 chars.
847 SCAN_EITHER_FORWARD(TemporalTimeString, CalendarTime, CalendarDateTime,
848                     ParsedISO8601Result)
849 
850 // TemporalYearMonthString:
851 //   DateSpecYearMonth
852 //   CalendarDateTime
853 // The lookahead is at most 11 chars.
854 SCAN_EITHER_FORWARD(TemporalYearMonthString, DateSpecYearMonth,
855                     CalendarDateTime, ParsedISO8601Result)
856 
857 // TemporalMonthDayString
858 //   DateSpecMonthDay
859 //   CalendarDateTime
860 // The lookahead is at most 5 chars.
861 SCAN_EITHER_FORWARD(TemporalMonthDayString, DateSpecMonthDay, CalendarDateTime,
862                     ParsedISO8601Result)
863 
864 // TemporalRelativeToString:
865 //   TemporalDateTimeString
866 //   TemporalZonedDateTimeString
867 // TemporalZonedDateTimeString is subset of TemporalDateTimeString
868 // See https://github.com/tc39/proposal-temporal/issues/1939
869 SCAN_FORWARD(TemporalRelativeToString, TemporalDateTimeString,
870              ParsedISO8601Result)
871 
872 // TemporalInstantString
873 //   Date TimeZoneOffsetRequired
874 //   Date DateTimeSeparator TimeSpec TimeZoneOffsetRequired
875 template <typename Char>
876 int32_t ScanTemporalInstantString(base::Vector<Char> str, int32_t s,
877                                   ParsedISO8601Result* r) {
878   // Date
879   int32_t cur = s;
880   cur += ScanDate(str, cur, r);
881   if (cur == s) return 0;
882 
883   // TimeZoneOffsetRequired
884   int32_t len = ScanTimeZoneOffsetRequired(str, cur, r);
885   if (len > 0) return cur + len - s;
886 
887   // DateTimeSeparator
888   if (!(((cur + 1) < str.length()) && IsDateTimeSeparator(str[cur++]))) {
889     return 0;
890   }
891   // TimeSpec
892   len = ScanTimeSpec(str, cur, r);
893   if (len == 0) return 0;
894   cur += len;
895 
896   // TimeZoneOffsetRequired
897   len = ScanTimeZoneOffsetRequired(str, cur, r);
898   if (len == 0) return 0;
899   return cur + len - s;
900 }
901 
902 // ==============================================================================
903 #define SATISIFY(T, R)                            \
904   template <typename Char>                        \
905   bool Satisfy##T(base::Vector<Char> str, R* r) { \
906     R ret;                                        \
907     int32_t len = Scan##T(str, 0, &ret);          \
908     if ((len > 0) && (len == str.length())) {     \
909       *r = ret;                                   \
910       return true;                                \
911     }                                             \
912     return false;                                 \
913   }
914 
915 #define IF_SATISFY_RETURN(T)             \
916   {                                      \
917     if (Satisfy##T(str, r)) return true; \
918   }
919 
920 #define SATISIFY_EITHER(T1, T2, T3, R)             \
921   template <typename Char>                         \
922   bool Satisfy##T1(base::Vector<Char> str, R* r) { \
923     IF_SATISFY_RETURN(T2)                          \
924     IF_SATISFY_RETURN(T3)                          \
925     return false;                                  \
926   }
927 
SATISIFY(TemporalDateTimeString,ParsedISO8601Result)928 SATISIFY(TemporalDateTimeString, ParsedISO8601Result)
929 SATISIFY(TemporalDateString, ParsedISO8601Result)
930 SATISIFY(CalendarTime, ParsedISO8601Result)
931 SATISIFY(DateTime, ParsedISO8601Result)
932 SATISIFY(DateSpecYearMonth, ParsedISO8601Result)
933 SATISIFY(DateSpecMonthDay, ParsedISO8601Result)
934 SATISIFY(Date_TimeSpecSeparator_TimeZone_Calendar, ParsedISO8601Result)
935 SATISIFY(CalendarDateTime, ParsedISO8601Result)
936 SATISIFY_EITHER(TemporalTimeString, CalendarTime, CalendarDateTime,
937                 ParsedISO8601Result)
938 SATISIFY_EITHER(TemporalYearMonthString, DateSpecYearMonth, CalendarDateTime,
939                 ParsedISO8601Result)
940 SATISIFY_EITHER(TemporalMonthDayString, DateSpecMonthDay, CalendarDateTime,
941                 ParsedISO8601Result)
942 SATISIFY(TimeZoneNumericUTCOffset, ParsedISO8601Result)
943 SATISIFY(TimeZoneIANAName, ParsedISO8601Result)
944 SATISIFY_EITHER(TemporalTimeZoneIdentifier, TimeZoneNumericUTCOffset,
945                 TimeZoneIANAName, ParsedISO8601Result)
946 SATISIFY_EITHER(TemporalTimeZoneString, TemporalTimeZoneIdentifier,
947                 Date_TimeSpecSeparator_TimeZone_Calendar, ParsedISO8601Result)
948 SATISIFY(TemporalInstantString, ParsedISO8601Result)
949 SATISIFY(TemporalZonedDateTimeString, ParsedISO8601Result)
950 
951 SATISIFY_EITHER(TemporalRelativeToString, TemporalDateTimeString,
952                 TemporalZonedDateTimeString, ParsedISO8601Result)
953 
954 SATISIFY(CalendarName, ParsedISO8601Result)
955 
956 template <typename Char>
957 bool SatisfyTemporalCalendarString(base::Vector<Char> str,
958                                    ParsedISO8601Result* r) {
959   IF_SATISFY_RETURN(CalendarName)
960   IF_SATISFY_RETURN(TemporalInstantString)
961   IF_SATISFY_RETURN(CalendarDateTime)
962   IF_SATISFY_RETURN(CalendarTime)
963   IF_SATISFY_RETURN(DateSpecYearMonth)
964   IF_SATISFY_RETURN(DateSpecMonthDay)
965   return false;
966 }
967 
968 // Duration
969 
SCAN_FORWARD(TimeFractionalPart,FractionalPart,int64_t)970 SCAN_FORWARD(TimeFractionalPart, FractionalPart, int64_t)
971 
972 template <typename Char>
973 int32_t ScanFraction(base::Vector<Char> str, int32_t s, int64_t* out) {
974   if (str.length() < (s + 2) || !IsDecimalSeparator(str[s])) return 0;
975   int32_t len = ScanTimeFractionalPart(str, s + 1, out);
976   return (len == 0) ? 0 : len + 1;
977 }
978 
SCAN_FORWARD(TimeFraction,Fraction,int64_t)979 SCAN_FORWARD(TimeFraction, Fraction, int64_t)
980 
981 // Digits : Digit [Digits]
982 
983 template <typename Char>
984 int32_t ScanDigits(base::Vector<Char> str, int32_t s, int64_t* out) {
985   if (str.length() < (s + 1) || !IsDecimalDigit(str[s])) return 0;
986   *out = ToInt(str[s]);
987   int32_t len = 1;
988   while (s + len + 1 <= str.length() && IsDecimalDigit(str[s + len])) {
989     *out = 10 * (*out) + ToInt(str[s + len]);
990     len++;
991   }
992   return len;
993 }
994 
SCAN_FORWARD(DurationYears,Digits,int64_t)995 SCAN_FORWARD(DurationYears, Digits, int64_t)
996 SCAN_FORWARD(DurationMonths, Digits, int64_t)
997 SCAN_FORWARD(DurationWeeks, Digits, int64_t)
998 SCAN_FORWARD(DurationDays, Digits, int64_t)
999 
1000 // DurationWholeHours : Digits
1001 SCAN_FORWARD(DurationWholeHours, Digits, int64_t)
1002 
1003 // DurationWholeMinutes : Digits
1004 SCAN_FORWARD(DurationWholeMinutes, Digits, int64_t)
1005 
1006 // DurationWholeSeconds : Digits
1007 SCAN_FORWARD(DurationWholeSeconds, Digits, int64_t)
1008 
1009 // DurationHoursFraction : TimeFraction
1010 SCAN_FORWARD(DurationHoursFraction, TimeFraction, int64_t)
1011 
1012 // DurationMinutesFraction : TimeFraction
1013 SCAN_FORWARD(DurationMinutesFraction, TimeFraction, int64_t)
1014 
1015 // DurationSecondsFraction : TimeFraction
1016 SCAN_FORWARD(DurationSecondsFraction, TimeFraction, int64_t)
1017 
1018 #define DURATION_WHOLE_FRACTION_DESIGNATOR(Name, name, d)                 \
1019   template <typename Char>                                                \
1020   int32_t ScanDurationWhole##Name##FractionDesignator(                    \
1021       base::Vector<Char> str, int32_t s, ParsedISO8601Duration* r) {      \
1022     int32_t cur = s;                                                      \
1023     int64_t whole = 0;                                                    \
1024     cur += ScanDurationWhole##Name(str, cur, &whole);                     \
1025     if (cur == s) return 0;                                               \
1026     int64_t fraction = 0;                                                 \
1027     int32_t len = ScanDuration##Name##Fraction(str, cur, &fraction);      \
1028     cur += len;                                                           \
1029     if (str.length() < (cur + 1) || AsciiAlphaToLower(str[cur++]) != (d)) \
1030       return 0;                                                           \
1031     r->whole_##name = whole;                                              \
1032     r->name##_fraction = fraction;                                        \
1033     return cur - s;                                                       \
1034   }
1035 
1036 DURATION_WHOLE_FRACTION_DESIGNATOR(Seconds, seconds, 's')
1037 DURATION_WHOLE_FRACTION_DESIGNATOR(Minutes, minutes, 'm')
1038 DURATION_WHOLE_FRACTION_DESIGNATOR(Hours, hours, 'h')
1039 
1040 // DurationSecondsPart :
1041 //   DurationWholeSeconds DurationSecondsFractionopt SecondsDesignator
1042 SCAN_FORWARD(DurationSecondsPart, DurationWholeSecondsFractionDesignator,
1043              ParsedISO8601Duration)
1044 
1045 // DurationMinutesPart :
1046 //   DurationWholeMinutes DurationMinutesFractionopt MinutesDesignator
1047 //   [DurationSecondsPart]
1048 template <typename Char>
1049 int32_t ScanDurationMinutesPart(base::Vector<Char> str, int32_t s,
1050                                 ParsedISO8601Duration* r) {
1051   int32_t cur = s + ScanDurationWholeMinutesFractionDesignator(str, s, r);
1052   if (cur == s) return 0;
1053   return cur + ScanDurationSecondsPart(str, cur, r) - s;
1054 }
1055 
1056 // DurationHoursPart :
1057 //   DurationWholeHours DurationHoursFractionopt HoursDesignator
1058 //   DurationMinutesPart
1059 //
1060 //   DurationWholeHours DurationHoursFractionopt HoursDesignator
1061 //   [DurationSecondsPart]
1062 template <typename Char>
ScanDurationHoursPart(base::Vector<Char> str,int32_t s,ParsedISO8601Duration * r)1063 int32_t ScanDurationHoursPart(base::Vector<Char> str, int32_t s,
1064                               ParsedISO8601Duration* r) {
1065   int32_t cur = s + ScanDurationWholeHoursFractionDesignator(str, s, r);
1066   if (cur == s) return 0;
1067   int32_t len = ScanDurationMinutesPart(str, cur, r);
1068   if (len > 0) return cur + len - s;
1069   return cur + ScanDurationSecondsPart(str, cur, r) - s;
1070 }
1071 
1072 // DurationTime :
1073 //   DurationTimeDesignator DurationHoursPart
1074 //   DurationTimeDesignator DurationMinutesPart
1075 //   DurationTimeDesignator DurationSecondsPart
1076 template <typename Char>
ScanDurationTime(base::Vector<Char> str,int32_t s,ParsedISO8601Duration * r)1077 int32_t ScanDurationTime(base::Vector<Char> str, int32_t s,
1078                          ParsedISO8601Duration* r) {
1079   int32_t cur = s;
1080   if (str.length() < (s + 1)) return 0;
1081   if (AsciiAlphaToLower(str[cur++]) != 't') return 0;
1082   if ((cur += ScanDurationHoursPart(str, cur, r)) - s > 1) return cur - s;
1083   if ((cur += ScanDurationMinutesPart(str, cur, r)) - s > 1) return cur - s;
1084   if ((cur += ScanDurationSecondsPart(str, cur, r)) - s > 1) return cur - s;
1085   return 0;
1086 }
1087 
1088 #define DURATION_AND_DESIGNATOR(Name, name, d)                              \
1089   template <typename Char>                                                  \
1090   int32_t ScanDuration##Name##Designator(base::Vector<Char> str, int32_t s, \
1091                                          ParsedISO8601Duration* r) {        \
1092     int32_t cur = s;                                                        \
1093     int64_t name;                                                           \
1094     if ((cur += ScanDuration##Name(str, cur, &name)) == s) return 0;        \
1095     if (str.length() < (cur + 1) || AsciiAlphaToLower(str[cur++]) != (d)) { \
1096       return 0;                                                             \
1097     }                                                                       \
1098     r->name = name;                                                         \
1099     return cur - s;                                                         \
1100   }
1101 
1102 DURATION_AND_DESIGNATOR(Days, days, 'd')
1103 DURATION_AND_DESIGNATOR(Weeks, weeks, 'w')
1104 DURATION_AND_DESIGNATOR(Months, months, 'm')
1105 DURATION_AND_DESIGNATOR(Years, years, 'y')
1106 
1107 // DurationDaysPart : DurationDays DaysDesignator
SCAN_FORWARD(DurationDaysPart,DurationDaysDesignator,ParsedISO8601Duration)1108 SCAN_FORWARD(DurationDaysPart, DurationDaysDesignator, ParsedISO8601Duration)
1109 
1110 // DurationWeeksPart : DurationWeeks WeeksDesignator [DurationDaysPart]
1111 template <typename Char>
1112 int32_t ScanDurationWeeksPart(base::Vector<Char> str, int32_t s,
1113                               ParsedISO8601Duration* r) {
1114   int32_t cur = s;
1115   if ((cur += ScanDurationWeeksDesignator(str, cur, r)) == s) return 0;
1116   return cur + ScanDurationDaysPart(str, cur, r) - s;
1117 }
1118 
1119 // DurationMonthsPart :
1120 //   DurationMonths MonthsDesignator DurationWeeksPart
1121 //   DurationMonths MonthsDesignator [DurationDaysPart]
1122 template <typename Char>
ScanDurationMonthsPart(base::Vector<Char> str,int32_t s,ParsedISO8601Duration * r)1123 int32_t ScanDurationMonthsPart(base::Vector<Char> str, int32_t s,
1124                                ParsedISO8601Duration* r) {
1125   int32_t cur = s;
1126   int32_t len;
1127   if ((cur += ScanDurationMonthsDesignator(str, cur, r)) == s) return 0;
1128   if ((len = ScanDurationWeeksPart(str, cur, r)) > 0) return cur + len - s;
1129   return cur + ScanDurationDaysPart(str, cur, r) - s;
1130 }
1131 
1132 // DurationYearsPart :
1133 //   DurationYears YearsDesignator DurationMonthsPart
1134 //   DurationYears YearsDesignator DurationWeeksPart
1135 //   DurationYears YearsDesignator [DurationDaysPart]
1136 template <typename Char>
ScanDurationYearsPart(base::Vector<Char> str,int32_t s,ParsedISO8601Duration * r)1137 int32_t ScanDurationYearsPart(base::Vector<Char> str, int32_t s,
1138                               ParsedISO8601Duration* r) {
1139   int32_t cur = s;
1140   int32_t len;
1141   if ((cur += ScanDurationYearsDesignator(str, cur, r)) == s) return 0;
1142   if ((len = ScanDurationMonthsPart(str, cur, r)) > 0) return cur + len - s;
1143   if ((len = ScanDurationWeeksPart(str, cur, r)) > 0) return cur + len - s;
1144   return cur + ScanDurationDaysPart(str, cur, r) - s;
1145 }
1146 
1147 // DurationDate :
1148 //   DurationYearsPart [DurationTime]
1149 //   DurationMonthsPart [DurationTime]
1150 //   DurationWeeksPart [DurationTime]
1151 //   DurationDaysPart [DurationTime]
1152 template <typename Char>
ScanDurationDate(base::Vector<Char> str,int32_t s,ParsedISO8601Duration * r)1153 int32_t ScanDurationDate(base::Vector<Char> str, int32_t s,
1154                          ParsedISO8601Duration* r) {
1155   int32_t cur = s;
1156   do {
1157     if ((cur += ScanDurationYearsPart(str, cur, r)) > s) break;
1158     if ((cur += ScanDurationMonthsPart(str, cur, r)) > s) break;
1159     if ((cur += ScanDurationWeeksPart(str, cur, r)) > s) break;
1160     if ((cur += ScanDurationDaysPart(str, cur, r)) > s) break;
1161     return 0;
1162   } while (false);
1163   return cur + ScanDurationTime(str, cur, r) - s;
1164 }
1165 
1166 // Duration :
1167 //   Signopt DurationDesignator DurationDate
1168 //   Signopt DurationDesignator DurationTime
1169 template <typename Char>
ScanDuration(base::Vector<Char> str,int32_t s,ParsedISO8601Duration * r)1170 int32_t ScanDuration(base::Vector<Char> str, int32_t s,
1171                      ParsedISO8601Duration* r) {
1172   if (str.length() < (s + 2)) return 0;
1173   int32_t cur = s;
1174   int32_t sign =
1175       (IsSign(str[cur]) && CanonicalSign(str[cur++]) == '-') ? -1 : 1;
1176   if (AsciiAlphaToLower(str[cur++]) != 'p') return 0;
1177   int32_t len = ScanDurationDate(str, cur, r);
1178   if (len == 0) len = ScanDurationTime(str, cur, r);
1179   if (len == 0) return 0;
1180   r->sign = sign;
1181   return cur + len - s;
1182 }
1183 SCAN_FORWARD(TemporalDurationString, Duration, ParsedISO8601Duration)
1184 
1185 SATISIFY(TemporalDurationString, ParsedISO8601Duration)
1186 
1187 }  // namespace
1188 
1189 #define IMPL_PARSE_METHOD(R, NAME)                                         \
1190   Maybe<R> TemporalParser::Parse##NAME(Isolate* isolate,                   \
1191                                        Handle<String> iso_string) {        \
1192     bool valid;                                                            \
1193     R parsed;                                                              \
1194     iso_string = String::Flatten(isolate, iso_string);                     \
1195     {                                                                      \
1196       DisallowGarbageCollection no_gc;                                     \
1197       String::FlatContent str_content = iso_string->GetFlatContent(no_gc); \
1198       if (str_content.IsOneByte()) {                                       \
1199         valid = Satisfy##NAME(str_content.ToOneByteVector(), &parsed);     \
1200       } else {                                                             \
1201         valid = Satisfy##NAME(str_content.ToUC16Vector(), &parsed);        \
1202       }                                                                    \
1203     }                                                                      \
1204     if (valid) return Just(parsed);                                        \
1205     return Nothing<R>();                                                   \
1206   }
1207 
1208 IMPL_PARSE_METHOD(ParsedISO8601Result, TemporalDateTimeString)
1209 IMPL_PARSE_METHOD(ParsedISO8601Result, TemporalDateString)
1210 IMPL_PARSE_METHOD(ParsedISO8601Result, TemporalYearMonthString)
1211 IMPL_PARSE_METHOD(ParsedISO8601Result, TemporalMonthDayString)
1212 IMPL_PARSE_METHOD(ParsedISO8601Result, TemporalTimeString)
1213 IMPL_PARSE_METHOD(ParsedISO8601Result, TemporalInstantString)
1214 IMPL_PARSE_METHOD(ParsedISO8601Result, TemporalZonedDateTimeString)
1215 IMPL_PARSE_METHOD(ParsedISO8601Result, TemporalTimeZoneString)
1216 IMPL_PARSE_METHOD(ParsedISO8601Result, TemporalRelativeToString)
1217 IMPL_PARSE_METHOD(ParsedISO8601Result, TemporalCalendarString)
1218 IMPL_PARSE_METHOD(ParsedISO8601Result, TimeZoneNumericUTCOffset)
1219 IMPL_PARSE_METHOD(ParsedISO8601Duration, TemporalDurationString)
1220 
1221 }  // namespace internal
1222 }  // namespace v8
1223