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