v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
temporal-parser.cc
Go to the documentation of this file.
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
6
7#include <optional>
8
9#include "src/base/bounds.h"
12
13namespace v8::internal {
14
15namespace {
16
17// Temporal #prod-TZLeadingChar
18inline constexpr bool IsTZLeadingChar(base::uc32 c) {
19 return base::IsInRange(AsciiAlphaToLower(c), 'a', 'z') || c == '.' ||
20 c == '_';
21}
22
23// Temporal #prod-TZChar
24inline constexpr bool IsTZChar(base::uc32 c) {
25 return IsTZLeadingChar(c) || c == '-';
26}
27
28// Temporal #prod-DecimalSeparator
29inline constexpr bool IsDecimalSeparator(base::uc32 c) {
30 return c == '.' || c == ',';
31}
32
33// Temporal #prod-DateTimeSeparator
34inline constexpr bool IsDateTimeSeparator(base::uc32 c) {
35 return c == ' ' || AsciiAlphaToLower(c) == 't';
36}
37
38// Temporal #prod-ASCIISign
39inline constexpr bool IsAsciiSign(base::uc32 c) { return c == '-' || c == '+'; }
40
41// Temporal #prod-Sign
42inline constexpr bool IsSign(base::uc32 c) {
43 return c == 0x2212 || IsAsciiSign(c);
44}
45
46// Temporal #prod-TimeZoneUTCOffsetSign
47inline constexpr bool IsTimeZoneUTCOffsetSign(base::uc32 c) {
48 return IsSign(c);
49}
50
51inline constexpr base::uc32 CanonicalSign(base::uc32 c) {
52 return c == 0x2212 ? '-' : c;
53}
54
55inline constexpr int32_t ToInt(base::uc32 c) { return c - '0'; }
56
57// A helper template to make the scanning of production w/ two digits simpler.
58template <typename Char>
59bool HasTwoDigits(base::Vector<Char> str, int32_t s, int32_t* out) {
60 if (str.length() >= (s + 2) && IsDecimalDigit(str[s]) &&
61 IsDecimalDigit(str[s + 1])) {
62 *out = ToInt(str[s]) * 10 + ToInt(str[s + 1]);
63 return true;
64 }
65 return false;
66}
67
68// A helper template to make the scanning of production w/ a single two digits
69// value simpler.
70template <typename Char>
71int32_t ScanTwoDigitsExpectValue(base::Vector<Char> str, int32_t s,
72 int32_t expected, int32_t* out) {
73 return HasTwoDigits<Char>(str, s, out) && (*out == expected) ? 2 : 0;
74}
75
76// A helper template to make the scanning of production w/ two digits value in a
77// range simpler.
78template <typename Char>
79int32_t ScanTwoDigitsExpectRange(base::Vector<Char> str, int32_t s, int32_t min,
80 int32_t max, int32_t* out) {
81 return HasTwoDigits<Char>(str, s, out) && base::IsInRange(*out, min, max) ? 2
82 : 0;
83}
84
85// A helper template to make the scanning of production w/ two digits value as 0
86// or in a range simpler.
87template <typename Char>
88int32_t ScanTwoDigitsExpectZeroOrRange(base::Vector<Char> str, int32_t s,
89 int32_t min, int32_t max, int32_t* out) {
90 return HasTwoDigits<Char>(str, s, out) &&
91 (*out == 0 || base::IsInRange(*out, min, max))
92 ? 2
93 : 0;
94}
95
120// For Hour Production
121// Hour:
122// [0 1] Digit
123// 2 [0 1 2 3]
124template <typename Char>
125int32_t ScanHour(base::Vector<Char> str, int32_t s, int32_t* out) {
126 return ScanTwoDigitsExpectRange<Char>(str, s, 0, 23, out);
127}
128
129// UnpaddedHour :
130// DecimalDigit
131// 1 DecimalDigit
132// 20
133// 21
134// 22
135// 23
136template <typename Char>
137int32_t ScanUnpaddedHour(base::Vector<Char> str, int32_t s) {
138 int32_t dummy;
139 int32_t len = ScanTwoDigitsExpectRange<Char>(str, s, 10, 23, &dummy);
140 if (len > 0) return len;
141 if (str.length() >= (s + 1) && IsDecimalDigit(str[s])) return 1;
142 return 0;
143}
144
145// MinuteSecond:
146// [0 1 2 3 4 5] Digit
147template <typename Char>
148int32_t ScanMinuteSecond(base::Vector<Char> str, int32_t s, int32_t* out) {
149 return ScanTwoDigitsExpectRange<Char>(str, s, 0, 59, out);
150}
151
152// For the forward production in the grammar such as
153// ProductionB:
154// ProductionT
155#define SCAN_FORWARD(B, T, R) \
156 template <typename Char> \
157 int32_t Scan##B(base::Vector<Char> str, int32_t s, R* r) { \
158 return Scan##T(str, s, r); \
159 }
160
161// Same as above but store the result into a particular field in R
162
163// For the forward production in the grammar such as
164// ProductionB:
165// ProductionT1
166// ProductionT2
167#define SCAN_EITHER_FORWARD(B, T1, T2, R) \
168 template <typename Char> \
169 int32_t Scan##B(base::Vector<Char> str, int32_t s, R* r) { \
170 int32_t len; \
171 if ((len = Scan##T1(str, s, r)) > 0) return len; \
172 return Scan##T2(str, s, r); \
173 }
174
175// TimeHour: Hour
176SCAN_FORWARD(TimeHour, Hour, int32_t)
177
178// TimeMinute: MinuteSecond
179SCAN_FORWARD(TimeMinute, MinuteSecond, int32_t)
180
181// TimeSecond:
182// MinuteSecond
183// 60
184template <typename Char>
185int32_t ScanTimeSecond(base::Vector<Char> str, int32_t s, int32_t* out) {
186 return ScanTwoDigitsExpectRange<Char>(str, s, 0, 60, out);
187}
188
189constexpr int kPowerOfTen[] = {1, 10, 100, 1000, 10000,
190 100000, 1000000, 10000000, 100000000};
191
192// FractionalPart : Digit{1,9}
193template <typename Char>
194int32_t ScanFractionalPart(base::Vector<Char> str, int32_t s, int32_t* out) {
195 int32_t cur = s;
196 if ((str.length() < (cur + 1)) || !IsDecimalDigit(str[cur])) return 0;
197 *out = ToInt(str[cur++]);
198 while ((cur < str.length()) && ((cur - s) < 9) && IsDecimalDigit(str[cur])) {
199 *out = 10 * (*out) + ToInt(str[cur++]);
200 }
201 *out *= kPowerOfTen[9 - (cur - s)];
202 return cur - s;
203}
204
205// TimeFraction: FractionalPart
206SCAN_FORWARD(TimeFractionalPart, FractionalPart, int32_t)
207
208// Fraction: DecimalSeparator FractionalPart
209// DecimalSeparator: one of , .
210template <typename Char>
211int32_t ScanFraction(base::Vector<Char> str, int32_t s, int32_t* out) {
212 if ((str.length() < (s + 2)) || (!IsDecimalSeparator(str[s]))) return 0;
213 int32_t len;
214 if ((len = ScanFractionalPart(str, s + 1, out)) == 0) return 0;
215 return len + 1;
216}
217
218// TimeFraction: DecimalSeparator TimeFractionalPart
219// DecimalSeparator: one of , .
220template <typename Char>
221int32_t ScanTimeFraction(base::Vector<Char> str, int32_t s, int32_t* out) {
222 if ((str.length() < (s + 2)) || (!IsDecimalSeparator(str[s]))) return 0;
223 int32_t len;
224 if ((len = ScanTimeFractionalPart(str, s + 1, out)) == 0) return 0;
225 return len + 1;
226}
227
228template <typename Char>
229int32_t ScanTimeFraction(base::Vector<Char> str, int32_t s,
230 ParsedISO8601Result* r) {
231 return ScanTimeFraction(str, s, &(r->time_nanosecond));
232}
233
234// TimeSpec:
235// TimeHour
236// TimeHour : TimeMinute
237// TimeHour : TimeMinute : TimeSecond [TimeFraction]
238// TimeHour TimeMinute
239// TimeHour TimeMinute TimeSecond [TimeFraction]
240template <typename Char>
241int32_t ScanTimeSpec(base::Vector<Char> str, int32_t s,
242 ParsedISO8601Result* r) {
243 int32_t time_hour, time_minute, time_second;
244 int32_t len;
245 int32_t cur = s;
246 if ((len = ScanTimeHour(str, cur, &time_hour)) == 0) return 0;
247 cur += len;
248 if ((cur + 1) > str.length()) {
249 // TimeHour
250 r->time_hour = time_hour;
251 return cur - s;
252 }
253 if (str[cur] == ':') {
254 cur++;
255 if ((len = ScanTimeMinute(str, cur, &time_minute)) == 0) return 0;
256 cur += len;
257 if ((cur + 1) > str.length() || (str[cur] != ':')) {
258 // TimeHour : TimeMinute
259 r->time_hour = time_hour;
260 r->time_minute = time_minute;
261 return cur - s;
262 }
263 cur++;
264 if ((len = ScanTimeSecond(str, cur, &time_second)) == 0) return 0;
265 } else {
266 if ((len = ScanTimeMinute(str, cur, &time_minute)) == 0) {
267 // TimeHour
268 r->time_hour = time_hour;
269 return cur - s;
270 }
271 cur += len;
272 if ((len = ScanTimeSecond(str, cur, &time_second)) == 0) {
273 // TimeHour TimeMinute
274 r->time_hour = time_hour;
275 r->time_minute = time_minute;
276 return cur - s;
277 }
278 }
279 cur += len;
280 len = ScanTimeFraction(str, cur, r);
281 r->time_hour = time_hour;
282 r->time_minute = time_minute;
283 r->time_second = time_second;
284 cur += len;
285 return cur - s;
286}
287
288// TimeSpecSeparator: DateTimeSeparator TimeSpec
289// DateTimeSeparator: SPACE, 't', or 'T'
290template <typename Char>
291int32_t ScanTimeSpecSeparator(base::Vector<Char> str, int32_t s,
292 ParsedISO8601Result* r) {
293 if (!(((s + 1) < str.length()) && IsDateTimeSeparator(str[s]))) return 0;
294 int32_t len = ScanTimeSpec(str, s + 1, r);
295 return (len == 0) ? 0 : len + 1;
296}
297
298// DateExtendedYear: Sign Digit Digit Digit Digit Digit Digit
299template <typename Char>
300int32_t ScanDateExtendedYear(base::Vector<Char> str, int32_t s, int32_t* out) {
301 if (str.length() < (s + 7)) return 0;
302 if (IsSign(str[s]) && IsDecimalDigit(str[s + 1]) &&
303 IsDecimalDigit(str[s + 2]) && IsDecimalDigit(str[s + 3]) &&
304 IsDecimalDigit(str[s + 4]) && IsDecimalDigit(str[s + 5]) &&
305 IsDecimalDigit(str[s + 6])) {
306 int32_t sign = (CanonicalSign(str[s]) == '-') ? -1 : 1;
307 *out = sign * (ToInt(str[s + 1]) * 100000 + ToInt(str[s + 2]) * 10000 +
308 ToInt(str[s + 3]) * 1000 + ToInt(str[s + 4]) * 100 +
309 ToInt(str[s + 5]) * 10 + ToInt(str[s + 6]));
310 // In the end of #sec-temporal-iso8601grammar
311 // It is a Syntax Error if DateExtendedYear is "-000000" or "−000000"
312 // (U+2212 MINUS SIGN followed by 000000).
313 if (sign == -1 && *out == 0) return 0;
314 return 7;
315 }
316 return 0;
317}
318
319// DateFourDigitYear: Digit Digit Digit Digit
320template <typename Char>
321int32_t ScanDateFourDigitYear(base::Vector<Char> str, int32_t s, int32_t* out) {
322 if (str.length() < (s + 4)) return 0;
323 if (IsDecimalDigit(str[s]) && IsDecimalDigit(str[s + 1]) &&
324 IsDecimalDigit(str[s + 2]) && IsDecimalDigit(str[s + 3])) {
325 *out = ToInt(str[s]) * 1000 + ToInt(str[s + 1]) * 100 +
326 ToInt(str[s + 2]) * 10 + ToInt(str[s + 3]);
327 return 4;
328 }
329 return 0;
330}
331
332// DateYear:
333// DateFourDigitYear
334// DateExtendedYear
335// The lookahead is at most 1 char.
336SCAN_EITHER_FORWARD(DateYear, DateFourDigitYear, DateExtendedYear, int32_t)
337
338// DateMonth:
339// 0 NonzeroDigit
340// 10
341// 11
342// 12
343template <typename Char>
344int32_t ScanDateMonth(base::Vector<Char> str, int32_t s, int32_t* out) {
345 return ScanTwoDigitsExpectRange<Char>(str, s, 1, 12, out);
346}
347
348// DateDay:
349// 0 NonzeroDigit
350// 1 Digit
351// 2 Digit
352// 30
353// 31
354template <typename Char>
355int32_t ScanDateDay(base::Vector<Char> str, int32_t s, int32_t* out) {
356 return ScanTwoDigitsExpectRange<Char>(str, s, 1, 31, out);
357}
358
359// Date:
360// DateYear - DateMonth - DateDay
361// DateYear DateMonth DateDay
362template <typename Char>
363int32_t ScanDate(base::Vector<Char> str, int32_t s, ParsedISO8601Result* r) {
364 int32_t date_year, date_month, date_day;
365 int32_t cur = s;
366 int32_t len;
367 if ((len = ScanDateYear(str, cur, &date_year)) == 0) return 0;
368 if (((cur += len) + 1) > str.length()) return 0;
369 if (str[cur] == '-') {
370 cur++;
371 if ((len = ScanDateMonth(str, cur, &date_month)) == 0) return 0;
372 cur += len;
373 if (((cur + 1) > str.length()) || (str[cur++] != '-')) return 0;
374 } else {
375 if ((len = ScanDateMonth(str, cur, &date_month)) == 0) return 0;
376 cur += len;
377 }
378 if ((len = ScanDateDay(str, cur, &date_day)) == 0) return 0;
379 r->date_year = date_year;
380 r->date_month = date_month;
381 r->date_day = date_day;
382 return cur + len - s;
383}
384
385// DateMonthWithThirtyOneDays : one of
386// 01 03 05 07 08 10 12
387template <typename Char>
388int32_t ScanDateMonthWithThirtyOneDays(base::Vector<Char> str, int32_t s) {
390 if (!HasTwoDigits(str, s, &value)) return false;
391 return value == 1 || value == 3 || value == 5 || value == 7 || value == 8 ||
392 value == 10 || value == 12;
393}
394
395// TimeZoneUTCOffsetHour: Hour
396SCAN_FORWARD(TimeZoneUTCOffsetHour, Hour, int32_t)
397
398// TimeZoneUTCOffsetMinute
399SCAN_FORWARD(TimeZoneUTCOffsetMinute, MinuteSecond, int32_t)
400
401// TimeZoneUTCOffsetSecond
402SCAN_FORWARD(TimeZoneUTCOffsetSecond, MinuteSecond, int32_t)
403
404// TimeZoneUTCOffsetFractionalPart: FractionalPart
405// See PR1796
406SCAN_FORWARD(TimeZoneUTCOffsetFractionalPart, FractionalPart, int32_t)
407
408// TimeZoneUTCOffsetFraction: DecimalSeparator TimeZoneUTCOffsetFractionalPart
409// See PR1796
410template <typename Char>
411int32_t ScanTimeZoneUTCOffsetFraction(base::Vector<Char> str, int32_t s,
412 int32_t* out) {
413 if ((str.length() < (s + 2)) || (!IsDecimalSeparator(str[s]))) return 0;
414 int32_t len;
415 if ((len = ScanTimeZoneUTCOffsetFractionalPart(str, s + 1, out)) > 0) {
416 return len + 1;
417 }
418 return 0;
419}
420
421// TimeZoneNumericUTCOffset:
422// TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour
423// TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour : TimeZoneUTCOffsetMinute
424// TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour TimeZoneUTCOffsetMinute
425// TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour : TimeZoneUTCOffsetMinute :
426// TimeZoneUTCOffsetSecond [TimeZoneUTCOffsetFraction] TimeZoneUTCOffsetSign
427// TimeZoneUTCOffsetHour TimeZoneUTCOffsetMinute TimeZoneUTCOffsetSecond
428// [TimeZoneUTCOffsetFraction]
429
430template <typename Char>
431int32_t ScanTimeZoneNumericUTCOffset(base::Vector<Char> str, int32_t s,
432 ParsedISO8601Result* r) {
434 int32_t cur = s;
435 if ((str.length() < (cur + 1)) || (!IsTimeZoneUTCOffsetSign(str[cur]))) {
436 return 0;
437 }
438 int32_t sign = (CanonicalSign(str[cur++]) == '-') ? -1 : 1;
439 if ((len = ScanTimeZoneUTCOffsetHour(str, cur, &hour)) == 0) return 0;
440 cur += len;
441 if ((cur + 1) > str.length()) {
442 // TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour
443 r->tzuo_sign = sign;
444 r->tzuo_hour = hour;
445 r->offset_string_start = s;
446 r->offset_string_length = cur - s;
447 return cur - s;
448 }
449 if (str[cur] == ':') {
450 cur++;
451 if ((len = ScanTimeZoneUTCOffsetMinute(str, cur, &minute)) == 0) return 0;
452 cur += len;
453 if ((cur + 1) > str.length() || str[cur] != ':') {
454 // TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour : TimeZoneUTCOffsetMinute
455 r->tzuo_sign = sign;
456 r->tzuo_hour = hour;
457 r->tzuo_minute = minute;
458 r->offset_string_start = s;
459 r->offset_string_length = cur - s;
460 return cur - s;
461 }
462 cur++;
463 if ((len = ScanTimeZoneUTCOffsetSecond(str, cur, &second)) == 0) return 0;
464 } else {
465 if ((len = ScanTimeZoneUTCOffsetMinute(str, cur, &minute)) == 0) {
466 // TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour
467 r->tzuo_sign = sign;
468 r->tzuo_hour = hour;
469 r->offset_string_start = s;
470 r->offset_string_length = cur - s;
471 return cur - s;
472 }
473 cur += len;
474 if ((len = ScanTimeZoneUTCOffsetSecond(str, cur, &second)) == 0) {
475 // TimeZoneUTCOffsetSign TimeZoneUTCOffsetHour TimeZoneUTCOffsetMinute
476 r->tzuo_sign = sign;
477 r->tzuo_hour = hour;
478 r->tzuo_minute = minute;
479 r->offset_string_start = s;
480 r->offset_string_length = cur - s;
481 return cur - s;
482 }
483 }
484 cur += len;
485 len = ScanTimeZoneUTCOffsetFraction(str, cur, &nanosecond);
486 r->tzuo_sign = sign;
487 r->tzuo_hour = hour;
488 r->tzuo_minute = minute;
489 r->tzuo_second = second;
490 if (len > 0) r->tzuo_nanosecond = nanosecond;
491 r->offset_string_start = s;
492 r->offset_string_length = cur + len - s;
493 cur += len;
494 return cur - s;
495}
496
497// TimeZoneUTCOffset:
498// TimeZoneNumericUTCOffset
499// UTCDesignator
500template <typename Char>
501int32_t ScanTimeZoneUTCOffset(base::Vector<Char> str, int32_t s,
502 ParsedISO8601Result* r) {
503 if (str.length() < (s + 1)) return 0;
504 if (AsciiAlphaToLower(str[s]) == 'z') {
505 // UTCDesignator
506 r->utc_designator = true;
507 return 1;
508 }
509 // TimeZoneNumericUTCOffset
510 return ScanTimeZoneNumericUTCOffset(str, s, r);
511}
512
513// TimeZoneIANANameComponent :
514// TZLeadingChar TZChar{0,13} but not one of . or ..
515template <typename Char>
516int32_t ScanTimeZoneIANANameComponent(base::Vector<Char> str, int32_t s) {
517 int32_t cur = s;
518 if (str.length() < (cur + 1) || !IsTZLeadingChar(str[cur++])) return 0;
519 while (((cur) < str.length()) && ((cur - s) < 14) && IsTZChar(str[cur])) {
520 cur++;
521 }
522 if ((cur - s) == 1 && str[s] == '.') return 0;
523 if ((cur - s) == 2 && str[s] == '.' && str[s + 1] == '.') return 0;
524 return cur - s;
525}
526// TimeZoneIANALegacyName :
527// Etc/GMT0
528// GMT0
529// GMT-0
530// GMT+0
531// EST5EDT
532// CST6CDT
533// MST7MDT
534// PST8PDT
535
536template <typename Char>
537int32_t ScanTimeZoneIANALegacyName(base::Vector<Char> str, int32_t s) {
538 int32_t cur = s;
539 {
540 constexpr int32_t len = 4;
541 if (str.length() < cur + len) return 0;
542 if (CompareCharsEqual(str.begin() + cur, "GMT0", len)) return len;
543 }
544
545 {
546 constexpr int32_t len = 5;
547 if (str.length() < cur + len) return 0;
548 if (CompareCharsEqual(str.begin() + cur, "GMT+0", len) ||
549 CompareCharsEqual(str.begin() + cur, "GMT-0", len)) {
550 return len;
551 }
552 }
553
554 {
555 constexpr int32_t len = 7;
556 if (str.length() < cur + len) return 0;
557 if (CompareCharsEqual(str.begin() + cur, "EST5EDT", len) ||
558 CompareCharsEqual(str.begin() + cur, "CST6CDT", len) ||
559 CompareCharsEqual(str.begin() + cur, "MST7MDT", len) ||
560 CompareCharsEqual(str.begin() + cur, "PST8PDT", len)) {
561 return len;
562 }
563 }
564
565 {
566 constexpr int32_t len = 8;
567 if (str.length() < cur + len) return 0;
568 if (CompareCharsEqual(str.begin() + cur, "Etc/GMT0", len)) return len;
569 }
570
571 return 0;
572}
573
574// Etc/GMT ASCIISign UnpaddedHour
575template <typename Char>
576int32_t ScanEtcGMTASCIISignUnpaddedHour(base::Vector<Char> str, int32_t s) {
577 if ((s + 9) > str.length()) return 0;
578 int32_t cur = s;
579 int32_t len = arraysize("Etc/GMT") - 1;
580 if (!CompareCharsEqual(str.begin() + cur, "Etc/GMT", len)) return 0;
581 cur += len;
582 Char sign = str[cur++];
583 if (!IsAsciiSign(sign)) return 0;
584 len = ScanUnpaddedHour(str, cur);
585 if (len == 0) return 0;
586 cur += len;
587 return cur - s;
588}
589
590// TimeZoneIANANameTail :
591// TimeZoneIANANameComponent
592// TimeZoneIANANameComponent / TimeZoneIANANameTail
593// TimeZoneIANAName :
594// Etc/GMT ASCIISign UnpaddedHour
595// TimeZoneIANANameTail
596// TimeZoneIANALegacyName
597// The spec text use tail recusion with TimeZoneIANANameComponent and
598// TimeZoneIANANameTail. In our implementation, we use an iteration loop
599// instead.
600template <typename Char>
601int32_t ScanTimeZoneIANAName(base::Vector<Char> str, int32_t s) {
602 int32_t len;
603 if ((len = ScanEtcGMTASCIISignUnpaddedHour(str, s)) > 0 ||
604 (len = ScanTimeZoneIANALegacyName(str, s)) > 0) {
605 return len;
606 }
607 int32_t cur = s;
608 if ((len = ScanTimeZoneIANANameComponent(str, cur)) == 0) return 0;
609 cur += len;
610 while ((str.length() > (cur + 1)) && (str[cur] == '/')) {
611 cur++;
612 if ((len = ScanTimeZoneIANANameComponent(str, cur)) == 0) {
613 return 0;
614 }
615 // TimeZoneIANANameComponent / TimeZoneIANAName
616 cur += len;
617 }
618 return cur - s;
619}
620
621// TimeZoneUTCOffsetName
622// Sign Hour
623// Sign Hour : MinuteSecond
624// Sign Hour MinuteSecond
625// Sign Hour : MinuteSecond : MinuteSecond [Fraction]
626// Sign Hour MinuteSecond MinuteSecond [Fraction]
627//
628template <typename Char>
629int32_t ScanTimeZoneUTCOffsetName(base::Vector<Char> str, int32_t s) {
630 int32_t cur = s;
631 int32_t len;
632 if ((str.length() < (s + 3)) || !IsSign(str[cur++])) return 0;
633 int32_t hour, minute, second, fraction;
634 if ((len = ScanHour(str, cur, &hour)) == 0) return 0;
635 cur += len;
636 if ((cur + 1) > str.length()) {
637 // Sign Hour
638 return cur - s;
639 }
640 if (str[cur] == ':') {
641 // Sign Hour :
642 cur++;
643 if ((len = ScanMinuteSecond(str, cur, &minute)) == 0) return 0;
644 cur += len;
645 if ((cur + 1) > str.length() || (str[cur] != ':')) {
646 // Sign Hour : MinuteSecond
647 return cur - s;
648 }
649 cur++;
650 // Sign Hour : MinuteSecond :
651 if ((len = ScanMinuteSecond(str, cur, &second)) == 0) return 0;
652 cur += len;
653 len = ScanFraction(str, cur, &fraction);
654 return cur + len - s;
655 } else {
656 if ((len = ScanMinuteSecond(str, cur, &minute)) == 0) {
657 // Sign Hour
658 return cur - s;
659 }
660 cur += len;
661 if ((len = ScanMinuteSecond(str, cur, &second)) == 0) {
662 // Sign Hour MinuteSecond
663 return cur - s;
664 }
665 cur += len;
666 len = ScanFraction(str, cur, &fraction);
667 // Sign Hour MinuteSecond MinuteSecond [Fraction]
668 cur += len;
669 return cur - s;
670 }
671}
672
673// TimeZoneBracketedName
674// TimeZoneIANAName
675// "Etc/GMT" ASCIISign Hour
676// TimeZoneUTCOffsetName
677// Since "Etc/GMT" also fit TimeZoneIANAName so we need to try
678// "Etc/GMT" ASCIISign Hour first.
679template <typename Char>
680int32_t ScanEtcGMTAsciiSignHour(base::Vector<Char> str, int32_t s) {
681 if ((s + 10) > str.length()) return 0;
682 int32_t cur = s;
683 if ((str[cur++] != 'E') || (str[cur++] != 't') || (str[cur++] != 'c') ||
684 (str[cur++] != '/') || (str[cur++] != 'G') || (str[cur++] != 'M') ||
685 (str[cur++] != 'T')) {
686 return 0;
687 }
688 Char sign = str[cur++];
689 if (!IsAsciiSign(sign)) return 0;
691 int32_t len = ScanHour(str, cur, &hour);
692 if (len == 0) return 0;
693 // "Etc/GMT" ASCIISign Hour
694 return 10;
695}
696
697template <typename Char>
698int32_t ScanTimeZoneIdentifier(base::Vector<Char> str, int32_t s,
699 ParsedISO8601Result* r);
700// TimeZoneBracketedAnnotation :
701// [ TimeZoneIdentifier ]
702template <typename Char>
703int32_t ScanTimeZoneBracketedAnnotation(base::Vector<Char> str, int32_t s,
704 ParsedISO8601Result* r) {
705 if ((str.length() < (s + 3)) || (str[s] != '[')) return 0;
706 int32_t cur = s + 1;
707 int32_t len = ScanTimeZoneIdentifier(str, cur, r);
708 cur += len;
709 if (len == 0 || str.length() < (cur + 1) || (str[cur] != ']')) {
710 // Only ScanTimeZoneBracketedAnnotation know the post condition of
711 // TimeZoneIdentifier is not matched so we need to reset here.
712 r->tzi_name_start = 0;
713 r->tzi_name_length = 0;
714 return 0;
715 }
716 cur++;
717 return cur - s;
718}
719
720// TimeZoneOffsetRequired:
721// TimeZoneUTCOffset [TimeZoneBracketedAnnotation]
722template <typename Char>
723int32_t ScanTimeZoneOffsetRequired(base::Vector<Char> str, int32_t s,
724 ParsedISO8601Result* r) {
725 int32_t cur = s;
726 cur += ScanTimeZoneUTCOffset(str, cur, r);
727 if (cur == s) return 0;
728 cur += ScanTimeZoneBracketedAnnotation(str, cur, r);
729 return cur - s;
730}
731
732// TimeZoneNameRequired:
733// [TimeZoneUTCOffset] TimeZoneBracketedAnnotation
734template <typename Char>
735int32_t ScanTimeZoneNameRequired(base::Vector<Char> str, int32_t s,
736 ParsedISO8601Result* r) {
737 int32_t cur = s;
738 cur += ScanTimeZoneUTCOffset(str, cur, r);
739 int32_t len = ScanTimeZoneBracketedAnnotation(str, cur, r);
740 if (len == 0) return 0;
741 cur += len;
742 return cur - s;
743}
744
745// TimeZone:
746// TimeZoneUTCOffset [TimeZoneBracketedAnnotation]
747// TimeZoneBracketedAnnotation
748template <typename Char>
749int32_t ScanTimeZone(base::Vector<Char> str, int32_t s,
750 ParsedISO8601Result* r) {
751 int32_t cur = s;
752 int32_t len;
753 // TimeZoneUTCOffset [TimeZoneBracketedAnnotation]
754 if ((len = ScanTimeZoneUTCOffset(str, cur, r)) > 0) {
755 cur += len;
756 // [TimeZoneBracketedAnnotation]
757 len = ScanTimeZoneBracketedAnnotation(str, cur, r);
758 cur += len;
759 return cur - s;
760 }
761 // TimeZoneBracketedAnnotation
762 return ScanTimeZoneBracketedAnnotation(str, cur, r);
763}
764
765// ValidMonthDay :
766// DateMonth [-] 0 NonZeroDigit
767// DateMonth [-] 1 DecimalDigit
768// DateMonth [-] 2 DecimalDigit
769// DateMonth [-] 30 but not one of 0230 or 02-30
770// DateMonthWithThirtyOneDays [-] 31
771template <typename Char>
772int32_t ScanValidMonthDay(base::Vector<Char> str, int32_t s) {
773 int32_t len;
774 int32_t cur = s;
775 int32_t date_month;
776 if ((len = ScanDateMonth(str, cur, &date_month)) > 0) {
777 cur += len;
778 if (str.length() >= (cur + 1)) {
779 if (str[cur] == '-') cur++;
780 int32_t day_of_month;
781 if ((len = ScanTwoDigitsExpectRange(str, cur, 1, 30, &day_of_month)) >
782 0) {
783 cur += len;
784 // 0 NonZeroDigit
785 // 1 DecimalDigit
786 // 2 DecimalDigit
787 // 30 but not one of 0230 or 02-30
788 if (date_month != 2 || day_of_month != 30) {
789 return cur - s;
790 }
791 }
792 }
793 }
794 // Reset cur
795 cur = s;
796 // DateMonthWithThirtyOneDays [-] 31
797 if ((len = ScanDateMonthWithThirtyOneDays(str, cur)) > 0) {
798 cur += len;
799 if (str.length() >= (cur + 1)) {
800 if (str[cur] == '-') cur++;
801 int32_t dummy;
802 if ((len = ScanTwoDigitsExpectValue(str, cur, 31, &dummy)) > 0) {
803 cur += len;
804 return cur - s;
805 }
806 }
807 }
808 return 0;
809}
810
811template <typename Char>
812int32_t ScanDateSpecYearMonth(base::Vector<Char> str, int32_t s,
813 ParsedISO8601Result* r);
814
815// TimeSpecWithOptionalTimeZoneNotAmbiguous :
816// TimeSpec [TimeZone] but not one of ValidMonthDay or DateSpecYearMonth
817template <typename Char>
818int32_t ScanTimeSpecWithOptionalTimeZoneNotAmbiguous(base::Vector<Char> str,
819 int32_t s,
820 ParsedISO8601Result* r) {
821 int32_t cur = s;
822 int32_t len;
823 if ((len = ScanTimeSpec(str, cur, r)) == 0) return 0;
824 cur += len;
825 // [TimeZone]
826 len = ScanTimeZone(str, cur, r);
827 cur += len;
828 len = cur - s;
829 // If it match ValidMonthDay, consider invalid.
830 if (ScanValidMonthDay(str, s) == len) return 0;
831 // If it match DateSpecYearMonth, consider invalid.
832 ParsedISO8601Result tmp;
833 if (ScanDateSpecYearMonth(str, s, &tmp) == len) return 0;
834 return len;
835}
836
837// CalendarNameComponent:
838// CalChar {3,8}
839template <typename Char>
840int32_t ScanCalendarNameComponent(base::Vector<Char> str, int32_t s) {
841 int32_t cur = s;
842 while ((cur < str.length()) && IsAlphaNumeric(str[cur])) cur++;
843 if ((cur - s) < 3 || (cur - s) > 8) return 0;
844 return cur - s;
845}
846
847// CalendarNameTail :
848// CalendarNameComponent
849// CalendarNameComponent - CalendarNameTail
850// CalendarName :
851// CalendarNameTail
852// The spec text use tail recusion with CalendarNameComponent and
853// CalendarNameTail. In our implementation, we use an iteration loop instead.
854template <typename Char>
855int32_t ScanCalendarName(base::Vector<Char> str, int32_t s,
856 ParsedISO8601Result* r) {
857 int32_t cur = s;
858 int32_t len;
859 if ((len = ScanCalendarNameComponent(str, cur)) == 0) return 0;
860 cur += len;
861 while ((str.length() > (cur + 1)) && (str[cur++] == '-')) {
862 if ((len = ScanCalendarNameComponent(str, cur)) == 0) return 0;
863 // CalendarNameComponent - CalendarName
864 cur += len;
865 }
866 r->calendar_name_start = s;
867 r->calendar_name_length = cur - s;
868 return cur - s;
869}
870
871// Calendar: '[u-ca=' CalendarName ']'
872template <typename Char>
873int32_t ScanCalendar(base::Vector<Char> str, int32_t s,
874 ParsedISO8601Result* r) {
875 if (str.length() < (s + 7)) return 0;
876 int32_t cur = s;
877 // "[u-ca="
878 if ((str[cur++] != '[') || (str[cur++] != 'u') || (str[cur++] != '-') ||
879 (str[cur++] != 'c') || (str[cur++] != 'a') || (str[cur++] != '=')) {
880 return 0;
881 }
882 int32_t len = ScanCalendarName(str, cur, r);
883 if (len == 0) return 0;
884 if ((str.length() < (cur + len + 1)) || (str[cur + len] != ']')) {
885 // Only ScanCalendar know the post condition of CalendarName is not met and
886 // need to reset here.
887 r->calendar_name_start = 0;
888 r->calendar_name_length = 0;
889 return 0;
890 }
891 return 6 + len + 1;
892}
893
894// CalendarTime_L1:
895// TimeDesignator TimeSpec [TimeZone] [Calendar]
896template <typename Char>
897int32_t ScanCalendarTime_L1(base::Vector<Char> str, int32_t s,
898 ParsedISO8601Result* r) {
899 int32_t cur = s;
900 if (str.length() < (s + 1)) return 0;
901 // TimeDesignator
902 if (AsciiAlphaToLower(str[cur++]) != 't') return 0;
903 int32_t len = ScanTimeSpec(str, cur, r);
904 if (len == 0) return 0;
905 cur += len;
906 // [TimeZone]
907 cur += ScanTimeZone(str, cur, r);
908 // [Calendar]
909 cur += ScanCalendar(str, cur, r);
910 return cur - s;
911}
912
913// CalendarTime_L2 :
914// TimeSpecWithOptionalTimeZoneNotAmbiguous [Calendar]
915template <typename Char>
916int32_t ScanCalendarTime_L2(base::Vector<Char> str, int32_t s,
917 ParsedISO8601Result* r) {
918 int32_t cur = s;
919 int32_t len = ScanTimeSpecWithOptionalTimeZoneNotAmbiguous(str, cur, r);
920 if (len == 0) return 0;
921 cur += len;
922 // [Calendar]
923 cur += ScanCalendar(str, cur, r);
924 return cur - s;
925}
926
927// DateTime: Date [TimeSpecSeparator][TimeZone]
928template <typename Char>
929int32_t ScanDateTime(base::Vector<Char> str, int32_t s,
930 ParsedISO8601Result* r) {
931 int32_t cur = s;
932 int32_t len = ScanDate(str, cur, r);
933 if (len == 0) return 0;
934 cur += len;
935 cur += ScanTimeSpecSeparator(str, cur, r);
936 cur += ScanTimeZone(str, cur, r);
937 return cur - s;
938}
939
940// DateSpecYearMonth: DateYear ['-'] DateMonth
941template <typename Char>
942int32_t ScanDateSpecYearMonth(base::Vector<Char> str, int32_t s,
943 ParsedISO8601Result* r) {
944 int32_t date_year, date_month;
945 int32_t cur = s;
946 int32_t len = ScanDateYear(str, cur, &date_year);
947 if (len == 0) return 0;
948 cur += len;
949 if (str.length() < (cur + 1)) return 0;
950 if (str[cur] == '-') cur++;
951 len = ScanDateMonth(str, cur, &date_month);
952 if (len == 0) return 0;
953 r->date_year = date_year;
954 r->date_month = date_month;
955 cur += len;
956 return cur - s;
957}
958
959// DateSpecMonthDay:
960// [TwoDash] DateMonth [-] DateDay
961template <typename Char>
962int32_t ScanDateSpecMonthDay(base::Vector<Char> str, int32_t s,
963 ParsedISO8601Result* r) {
964 if (str.length() < (s + 4)) return 0;
965 int32_t cur = s;
966 if (str[cur] == '-') {
967 // The first two dash are optional together
968 if (str[++cur] != '-') return 0;
969 // TwoDash
970 cur++;
971 }
972 int32_t date_month, date_day;
973 int32_t len = ScanDateMonth(str, cur, &date_month);
974 if (len == 0) return 0;
975 cur += len;
976 if (str.length() < (cur + 1)) return 0;
977 // '-'
978 if (str[cur] == '-') cur++;
979 len = ScanDateDay(str, cur, &date_day);
980 if (len == 0) return 0;
981 r->date_month = date_month;
982 r->date_day = date_day;
983 cur += len;
984 return cur - s;
985}
986
987// TimeZoneIdentifier :
988// TimeZoneIANAName
989// TimeZoneUTCOffsetName
990template <typename Char>
991int32_t ScanTimeZoneIdentifier(base::Vector<Char> str, int32_t s,
992 ParsedISO8601Result* r) {
993 int32_t len;
994 int32_t cur = s;
995 if ((len = ScanTimeZoneIANAName(str, cur)) > 0 ||
996 (len = ScanTimeZoneUTCOffsetName(str, cur)) > 0) {
997 cur += len;
998 r->tzi_name_start = s;
999 r->tzi_name_length = len;
1000 return cur - s;
1001 }
1002 return 0;
1003}
1004
1005// CalendarDateTime: DateTime [Calendar]
1006template <typename Char>
1007int32_t ScanCalendarDateTime(base::Vector<Char> str, int32_t s,
1008 ParsedISO8601Result* r) {
1009 int32_t len = ScanDateTime(str, s, r);
1010 if (len == 0) return 0;
1011 return len + ScanCalendar(str, len, r);
1012}
1013
1014// CalendarDateTimeTimeRequired: Date TimeSpecSeparator [TimeZone] [Calendar]
1015template <typename Char>
1016int32_t ScanCalendarDateTimeTimeRequired(base::Vector<Char> str, int32_t s,
1017 ParsedISO8601Result* r) {
1018 int32_t cur = s;
1019 int32_t len = ScanDate(str, cur, r);
1020 if (len == 0) return 0;
1021 cur += len;
1022 len = ScanTimeSpecSeparator(str, cur, r);
1023 if (len == 0) return 0;
1024 cur += len;
1025 // [TimeZone]
1026 cur += ScanTimeZone(str, cur, r);
1027 // [Calendar]
1028 cur += ScanCalendar(str, cur, r);
1029 return cur - s;
1030}
1031
1032// TemporalZonedDateTimeString:
1033// Date [TimeSpecSeparator] TimeZoneNameRequired [Calendar]
1034template <typename Char>
1035int32_t ScanTemporalZonedDateTimeString(base::Vector<Char> str, int32_t s,
1036 ParsedISO8601Result* r) {
1037 // Date
1038 int32_t cur = s;
1039 int32_t len = ScanDate(str, cur, r);
1040 if (len == 0) return 0;
1041 cur += len;
1042
1043 // TimeSpecSeparator
1044 cur += ScanTimeSpecSeparator(str, cur, r);
1045
1046 // TimeZoneNameRequired
1047 len = ScanTimeZoneNameRequired(str, cur, r);
1048 if (len == 0) return 0;
1049 cur += len;
1050
1051 // Calendar
1052 cur += ScanCalendar(str, cur, r);
1053 return cur - s;
1054}
1055
1056SCAN_FORWARD(TemporalDateTimeString, CalendarDateTime, ParsedISO8601Result)
1057
1058// TemporalMonthDayString
1059// DateSpecMonthDay
1060// CalendarDateTime
1061// The lookahead is at most 5 chars.
1062SCAN_EITHER_FORWARD(TemporalMonthDayString, DateSpecMonthDay, CalendarDateTime,
1063 ParsedISO8601Result)
1064
1065// TemporalInstantString
1066// Date [TimeSpecSeparator] TimeZoneOffsetRequired [Calendar]
1067template <typename Char>
1068int32_t ScanTemporalInstantString(base::Vector<Char> str, int32_t s,
1069 ParsedISO8601Result* r) {
1070 // Date
1071 int32_t cur = s;
1072 int32_t len = ScanDate(str, cur, r);
1073 if (len == 0) return 0;
1074 cur += len;
1075
1076 // [TimeSpecSeparator]
1077 cur += ScanTimeSpecSeparator(str, cur, r);
1078
1079 // TimeZoneOffsetRequired
1080 len = ScanTimeZoneOffsetRequired(str, cur, r);
1081 if (len == 0) return 0;
1082 cur += len;
1083 // [Calendar]
1084 cur += ScanCalendar(str, cur, r);
1085 return cur - s;
1086}
1087
1088// ==============================================================================
1089#define SATISIFY(T, R) \
1090 template <typename Char> \
1091 bool Satisfy##T(base::Vector<Char> str, R* r) { \
1092 R ret; \
1093 int32_t len = Scan##T(str, 0, &ret); \
1094 if ((len > 0) && (len == str.length())) { \
1095 *r = ret; \
1096 return true; \
1097 } \
1098 return false; \
1099 }
1100
1101#define IF_SATISFY_RETURN(T) \
1102 { \
1103 if (Satisfy##T(str, r)) return true; \
1104 }
1105
1106#define SATISIFY_EITHER(T1, T2, T3, R) \
1107 template <typename Char> \
1108 bool Satisfy##T1(base::Vector<Char> str, R* r) { \
1109 IF_SATISFY_RETURN(T2) \
1110 IF_SATISFY_RETURN(T3) \
1111 return false; \
1112 }
1113
1114SATISIFY(TemporalDateTimeString, ParsedISO8601Result)
1115SATISIFY(DateTime, ParsedISO8601Result)
1116SATISIFY(DateSpecYearMonth, ParsedISO8601Result)
1117SATISIFY(DateSpecMonthDay, ParsedISO8601Result)
1118SATISIFY(CalendarDateTime, ParsedISO8601Result)
1119SATISIFY(CalendarTime_L1, ParsedISO8601Result)
1120SATISIFY(CalendarTime_L2, ParsedISO8601Result)
1121
1122template <typename Char>
1123bool SatisfyCalendarTime(base::Vector<Char> str, ParsedISO8601Result* r) {
1124 IF_SATISFY_RETURN(CalendarTime_L1)
1125 IF_SATISFY_RETURN(CalendarTime_L2)
1126 return false;
1127}
1128SATISIFY(CalendarDateTimeTimeRequired, ParsedISO8601Result)
1129SATISIFY_EITHER(TemporalTimeString, CalendarTime, CalendarDateTimeTimeRequired,
1130 ParsedISO8601Result)
1131SATISIFY_EITHER(TemporalYearMonthString, DateSpecYearMonth, CalendarDateTime,
1132 ParsedISO8601Result)
1133SATISIFY_EITHER(TemporalMonthDayString, DateSpecMonthDay, CalendarDateTime,
1134 ParsedISO8601Result)
1135SATISIFY(TimeZoneNumericUTCOffset, ParsedISO8601Result)
1136SATISIFY(TimeZoneIdentifier, ParsedISO8601Result)
1137SATISIFY(TemporalInstantString, ParsedISO8601Result)
1138SATISIFY(TemporalZonedDateTimeString, ParsedISO8601Result)
1139
1140SATISIFY(CalendarName, ParsedISO8601Result)
1141
1142// Duration
1143
1144// Digits : Digit [Digits]
1145
1146template <typename Char>
1147int32_t ScanDigits(base::Vector<Char> str, int32_t s, double* out) {
1148 if (str.length() < (s + 1) || !IsDecimalDigit(str[s])) return 0;
1149 *out = ToInt(str[s]);
1150 int32_t len = 1;
1151 while (s + len + 1 <= str.length() && IsDecimalDigit(str[s + len])) {
1152 *out = 10 * (*out) + ToInt(str[s + len]);
1153 len++;
1154 }
1155 return len;
1156}
1157
1158SCAN_FORWARD(DurationYears, Digits, double)
1159SCAN_FORWARD(DurationMonths, Digits, double)
1160SCAN_FORWARD(DurationWeeks, Digits, double)
1161SCAN_FORWARD(DurationDays, Digits, double)
1162
1163// DurationWholeHours : Digits
1164SCAN_FORWARD(DurationWholeHours, Digits, double)
1165
1166// DurationWholeMinutes : Digits
1167SCAN_FORWARD(DurationWholeMinutes, Digits, double)
1168
1169// DurationWholeSeconds : Digits
1170SCAN_FORWARD(DurationWholeSeconds, Digits, double)
1171
1172// DurationHoursFraction : TimeFraction
1173SCAN_FORWARD(DurationHoursFraction, TimeFraction, int32_t)
1174
1175// DurationMinutesFraction : TimeFraction
1176SCAN_FORWARD(DurationMinutesFraction, TimeFraction, int32_t)
1177
1178// DurationSecondsFraction : TimeFraction
1179SCAN_FORWARD(DurationSecondsFraction, TimeFraction, int32_t)
1180
1181#define DURATION_WHOLE_FRACTION_DESIGNATOR(Name, name, d) \
1182 template <typename Char> \
1183 int32_t ScanDurationWhole##Name##FractionDesignator( \
1184 base::Vector<Char> str, int32_t s, ParsedISO8601Duration* r) { \
1185 int32_t cur = s; \
1186 double whole = ParsedISO8601Duration::kEmpty; \
1187 cur += ScanDurationWhole##Name(str, cur, &whole); \
1188 if (cur == s) return 0; \
1189 int32_t fraction = ParsedISO8601Duration::kEmpty; \
1190 int32_t len = ScanDuration##Name##Fraction(str, cur, &fraction); \
1191 cur += len; \
1192 if (str.length() < (cur + 1) || AsciiAlphaToLower(str[cur++]) != (d)) \
1193 return 0; \
1194 r->whole_##name = whole; \
1195 r->name##_fraction = fraction; \
1196 return cur - s; \
1197 }
1198
1199DURATION_WHOLE_FRACTION_DESIGNATOR(Seconds, seconds, 's')
1200DURATION_WHOLE_FRACTION_DESIGNATOR(Minutes, minutes, 'm')
1201DURATION_WHOLE_FRACTION_DESIGNATOR(Hours, hours, 'h')
1202
1203// DurationSecondsPart :
1204// DurationWholeSeconds DurationSecondsFractionopt SecondsDesignator
1205SCAN_FORWARD(DurationSecondsPart, DurationWholeSecondsFractionDesignator,
1206 ParsedISO8601Duration)
1207
1208// DurationMinutesPart :
1209// DurationWholeMinutes DurationMinutesFractionopt MinutesDesignator
1210// [DurationSecondsPart]
1211template <typename Char>
1212int32_t ScanDurationMinutesPart(base::Vector<Char> str, int32_t s,
1213 ParsedISO8601Duration* r) {
1214 int32_t cur = s;
1215 int32_t len = ScanDurationWholeMinutesFractionDesignator(str, s, r);
1216 if (len == 0) return 0;
1217 cur += len;
1218 cur += ScanDurationSecondsPart(str, cur, r);
1219 return cur - s;
1220}
1221
1222// DurationHoursPart :
1223// DurationWholeHours DurationHoursFractionopt HoursDesignator
1224// DurationMinutesPart
1225//
1226// DurationWholeHours DurationHoursFractionopt HoursDesignator
1227// [DurationSecondsPart]
1228template <typename Char>
1229int32_t ScanDurationHoursPart(base::Vector<Char> str, int32_t s,
1230 ParsedISO8601Duration* r) {
1231 int32_t cur = s;
1232 int32_t len = ScanDurationWholeHoursFractionDesignator(str, s, r);
1233 if (len == 0) return 0;
1234 cur += len;
1235 len = ScanDurationMinutesPart(str, cur, r);
1236 if (len > 0) {
1237 cur += len;
1238 } else {
1239 cur += ScanDurationSecondsPart(str, cur, r);
1240 }
1241 return cur - s;
1242}
1243
1244// DurationTime :
1245// TimeDesignator DurationHoursPart
1246// TimeDesignator DurationMinutesPart
1247// TimeDesignator DurationSecondsPart
1248template <typename Char>
1249int32_t ScanDurationTime(base::Vector<Char> str, int32_t s,
1250 ParsedISO8601Duration* r) {
1251 int32_t cur = s;
1252 if (str.length() < (s + 1)) return 0;
1253 if (AsciiAlphaToLower(str[cur++]) != 't') return 0;
1254 if ((cur += ScanDurationHoursPart(str, cur, r)) - s > 1) return cur - s;
1255 if ((cur += ScanDurationMinutesPart(str, cur, r)) - s > 1) return cur - s;
1256 if ((cur += ScanDurationSecondsPart(str, cur, r)) - s > 1) return cur - s;
1257 return 0;
1258}
1259
1260#define DURATION_AND_DESIGNATOR(Name, name, d) \
1261 template <typename Char> \
1262 int32_t ScanDuration##Name##Designator(base::Vector<Char> str, int32_t s, \
1263 ParsedISO8601Duration* r) { \
1264 int32_t cur = s; \
1265 double name; \
1266 if ((cur += ScanDuration##Name(str, cur, &name)) == s) return 0; \
1267 if (str.length() < (cur + 1) || AsciiAlphaToLower(str[cur++]) != (d)) { \
1268 return 0; \
1269 } \
1270 r->name = name; \
1271 return cur - s; \
1272 }
1273
1274DURATION_AND_DESIGNATOR(Days, days, 'd')
1275DURATION_AND_DESIGNATOR(Weeks, weeks, 'w')
1278
1279// DurationDaysPart : DurationDays DaysDesignator
1280SCAN_FORWARD(DurationDaysPart, DurationDaysDesignator, ParsedISO8601Duration)
1281
1282// DurationWeeksPart : DurationWeeks WeeksDesignator [DurationDaysPart]
1283template <typename Char>
1284int32_t ScanDurationWeeksPart(base::Vector<Char> str, int32_t s,
1285 ParsedISO8601Duration* r) {
1286 int32_t cur = s;
1287 if ((cur += ScanDurationWeeksDesignator(str, cur, r)) == s) return 0;
1288 cur += ScanDurationDaysPart(str, cur, r);
1289 return cur - s;
1290}
1291
1292// DurationMonthsPart :
1293// DurationMonths MonthsDesignator DurationWeeksPart
1294// DurationMonths MonthsDesignator [DurationDaysPart]
1295template <typename Char>
1296int32_t ScanDurationMonthsPart(base::Vector<Char> str, int32_t s,
1297 ParsedISO8601Duration* r) {
1298 int32_t cur = s;
1299 int32_t len = ScanDurationMonthsDesignator(str, cur, r);
1300 if (len == 0) return 0;
1301 cur += len;
1302 if ((len = ScanDurationWeeksPart(str, cur, r)) > 0) {
1303 cur += len;
1304 } else {
1305 cur += ScanDurationDaysPart(str, cur, r);
1306 }
1307 return cur - s;
1308}
1309
1310// DurationYearsPart :
1311// DurationYears YearsDesignator DurationMonthsPart
1312// DurationYears YearsDesignator DurationWeeksPart
1313// DurationYears YearsDesignator [DurationDaysPart]
1314template <typename Char>
1315int32_t ScanDurationYearsPart(base::Vector<Char> str, int32_t s,
1316 ParsedISO8601Duration* r) {
1317 int32_t cur = s;
1318 int32_t len = ScanDurationYearsDesignator(str, cur, r);
1319 if (len == 0) return 0;
1320 cur += len;
1321 if ((len = ScanDurationMonthsPart(str, cur, r)) > 0) {
1322 cur += len;
1323 } else if ((len = ScanDurationWeeksPart(str, cur, r)) > 0) {
1324 cur += len;
1325 } else {
1326 len = ScanDurationDaysPart(str, cur, r);
1327 cur += len;
1328 }
1329 return cur - s;
1330}
1331
1332// DurationDate :
1333// DurationYearsPart [DurationTime]
1334// DurationMonthsPart [DurationTime]
1335// DurationWeeksPart [DurationTime]
1336// DurationDaysPart [DurationTime]
1337template <typename Char>
1338int32_t ScanDurationDate(base::Vector<Char> str, int32_t s,
1339 ParsedISO8601Duration* r) {
1340 int32_t cur = s;
1341 do {
1342 if ((cur += ScanDurationYearsPart(str, cur, r)) > s) break;
1343 if ((cur += ScanDurationMonthsPart(str, cur, r)) > s) break;
1344 if ((cur += ScanDurationWeeksPart(str, cur, r)) > s) break;
1345 if ((cur += ScanDurationDaysPart(str, cur, r)) > s) break;
1346 return 0;
1347 } while (false);
1348 cur += ScanDurationTime(str, cur, r);
1349 return cur - s;
1350}
1351
1352// Duration :
1353// Signopt DurationDesignator DurationDate
1354// Signopt DurationDesignator DurationTime
1355template <typename Char>
1356int32_t ScanDuration(base::Vector<Char> str, int32_t s,
1357 ParsedISO8601Duration* r) {
1358 if (str.length() < (s + 2)) return 0;
1359 int32_t cur = s;
1360 int32_t sign =
1361 (IsSign(str[cur]) && CanonicalSign(str[cur++]) == '-') ? -1 : 1;
1362 if (AsciiAlphaToLower(str[cur++]) != 'p') return 0;
1363 int32_t len = ScanDurationDate(str, cur, r);
1364 if (len == 0) len = ScanDurationTime(str, cur, r);
1365 if (len == 0) return 0;
1366 r->sign = sign;
1367 cur += len;
1368 return cur - s;
1369}
1370SCAN_FORWARD(TemporalDurationString, Duration, ParsedISO8601Duration)
1371
1372SATISIFY(TemporalDurationString, ParsedISO8601Duration)
1373
1374} // namespace
1375
1376#define IMPL_PARSE_METHOD(R, NAME) \
1377 std::optional<R> TemporalParser::Parse##NAME( \
1378 Isolate* isolate, DirectHandle<String> iso_string) { \
1379 bool valid; \
1380 R parsed; \
1381 iso_string = String::Flatten(isolate, iso_string); \
1382 { \
1383 DisallowGarbageCollection no_gc; \
1384 String::FlatContent str_content = iso_string->GetFlatContent(no_gc); \
1385 if (str_content.IsOneByte()) { \
1386 valid = Satisfy##NAME(str_content.ToOneByteVector(), &parsed); \
1387 } else { \
1388 valid = Satisfy##NAME(str_content.ToUC16Vector(), &parsed); \
1389 } \
1390 } \
1391 if (valid) return parsed; \
1392 return std::nullopt; \
1393 }
1394
1395IMPL_PARSE_METHOD(ParsedISO8601Result, TemporalDateTimeString)
1396IMPL_PARSE_METHOD(ParsedISO8601Result, TemporalYearMonthString)
1397IMPL_PARSE_METHOD(ParsedISO8601Result, TemporalMonthDayString)
1398IMPL_PARSE_METHOD(ParsedISO8601Result, TemporalTimeString)
1399IMPL_PARSE_METHOD(ParsedISO8601Result, TemporalInstantString)
1400IMPL_PARSE_METHOD(ParsedISO8601Result, TemporalZonedDateTimeString)
1401IMPL_PARSE_METHOD(ParsedISO8601Result, TimeZoneIdentifier)
1402IMPL_PARSE_METHOD(ParsedISO8601Result, CalendarName)
1403IMPL_PARSE_METHOD(ParsedISO8601Result, TimeZoneNumericUTCOffset)
1404IMPL_PARSE_METHOD(ParsedISO8601Duration, TemporalDurationString)
1405
1406} // namespace v8::internal
double hour
double second
double minute
double nanosecond
double years
double months
double weeks
double days
Register tmp
int s
Definition mul-fft.cc:297
int m
Definition mul-fft.cc:294
int r
Definition mul-fft.cc:298
int int32_t
Definition unicode.cc:40
uint32_t uc32
Definition strings.h:19
constexpr bool IsInRange(T value, U lower_limit, U higher_limit)
Definition bounds.h:20
bool CompareCharsEqual(const lchar *lhs, const rchar *rhs, size_t chars)
Definition utils.h:509
constexpr bool IsDecimalDigit(base::uc32 c)
return value
Definition map-inl.h:893
constexpr int AsciiAlphaToLower(base::uc32 c)
constexpr bool IsAlphaNumeric(base::uc32 c)
#define arraysize(array)
Definition macros.h:67
#define IF_SATISFY_RETURN(T)
#define SCAN_EITHER_FORWARD(B, T1, T2, R)
#define IMPL_PARSE_METHOD(R, NAME)
#define SATISIFY(T, R)
#define SCAN_FORWARD(B, T, R)
#define SATISIFY_EITHER(T1, T2, T3, R)
#define DURATION_WHOLE_FRACTION_DESIGNATOR(Name, name, d)
#define DURATION_AND_DESIGNATOR(Name, name, d)