18b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch// Copyright 2011 the V8 project authors. All rights reserved.
2b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// found in the LICENSE file.
4a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifndef V8_DATEPARSER_H_
6a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#define V8_DATEPARSER_H_
7a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/allocation.h"
9014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/char-predicates.h"
10014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/parsing/scanner.h"
11a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
12a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace v8 {
13a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace internal {
14a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
15a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass DateParser : public AllStatic {
16a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
17a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Parse the string as a date. If parsing succeeds, return true after
18a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // filling out the output array as follows (all integers are Smis):
19a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // [0]: year
20a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // [1]: month (0 = Jan, 1 = Feb, ...)
21a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // [2]: day
22a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // [3]: hour
23a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // [4]: minute
24a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // [5]: second
256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // [6]: millisecond
266ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // [7]: UTC offset in seconds, or null value if no timezone specified
27a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If parsing fails, return false (content of output array is not defined).
28a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  template <typename Char>
298b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  static bool Parse(Vector<Char> str, FixedArray* output, UnicodeCache* cache);
30a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
31a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  enum {
326ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, MILLISECOND, UTC_OFFSET, OUTPUT_SIZE
33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  };
34a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
36a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Range testing
37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static inline bool Between(int x, int lo, int hi) {
38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return static_cast<unsigned>(x - lo) <= static_cast<unsigned>(hi - lo);
39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Indicates a missing value.
42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static const int kNone = kMaxInt;
43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Maximal number of digits used to build the value of a numeral.
453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Remaining digits are ignored.
463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  static const int kMaxSignificantDigits = 9;
473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
48a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // InputReader provides basic string parsing and character classification.
49a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  template <typename Char>
50a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  class InputReader BASE_EMBEDDED {
51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block   public:
528b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    InputReader(UnicodeCache* unicode_cache, Vector<Char> s)
53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        : index_(0),
54a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          buffer_(s),
558b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch          unicode_cache_(unicode_cache) {
56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Next();
57a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    int position() { return index_; }
603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Advance to the next character of the string.
623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    void Next() {
633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      ch_ = (index_ < buffer_.length()) ? buffer_[index_] : 0;
643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      index_++;
65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
673fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    // Read a string of digits as an unsigned number. Cap value at
683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    // kMaxSignificantDigits, but skip remaining digits if the numeral
693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    // is longer.
703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    int ReadUnsignedNumeral() {
718a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      int n = 0;
723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      int i = 0;
733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      while (IsAsciiDigit()) {
743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        if (i < kMaxSignificantDigits) n = n * 10 + ch_ - '0';
753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        i++;
763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        Next();
778a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      }
788a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      return n;
798a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang    }
808a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
81a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Read a word (sequence of chars. >= 'A'), fill the given buffer with a
82a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // lower-case prefix, and pad any remainder of the buffer with zeroes.
83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Return word length.
84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int ReadWord(uint32_t* prefix, int prefix_size) {
85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      int len;
86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      for (len = 0; IsAsciiAlphaOrAbove(); Next(), len++) {
879ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick        if (len < prefix_size) prefix[len] = AsciiAlphaToLower(ch_);
88a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
89a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      for (int i = len; i < prefix_size; i++) prefix[i] = 0;
90a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return len;
91a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
92a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
93a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // The skip methods return whether they actually skipped something.
948a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang    bool Skip(uint32_t c) {
958a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      if (ch_ == c) {
968a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang        Next();
978a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang        return true;
988a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      }
998a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      return false;
1008a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang    }
101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
102014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    inline bool SkipWhiteSpace();
103014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    inline bool SkipParentheses();
104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Character testing/classification. Non-ASCII digits are not supported.
106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    bool Is(uint32_t c) const { return ch_ == c; }
107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    bool IsEnd() const { return ch_ == 0; }
108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    bool IsAsciiDigit() const { return IsDecimalDigit(ch_); }
109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    bool IsAsciiAlphaOrAbove() const { return ch_ >= 'A'; }
110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    bool IsAsciiSign() const { return ch_ == '+' || ch_ == '-'; }
111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Return 1 for '+' and -1 for '-'.
113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int GetAsciiSignValue() const { return 44 - static_cast<int>(ch_); }
114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block   private:
116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int index_;
117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Vector<Char> buffer_;
118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    uint32_t ch_;
1198b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    UnicodeCache* unicode_cache_;
120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  };
121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  enum KeywordType {
1233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      INVALID, MONTH_NAME, TIME_ZONE_NAME, TIME_SEPARATOR, AM_PM
1243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  };
1253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
1263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  struct DateToken {
1273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch   public:
1283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    bool IsInvalid() { return tag_ == kInvalidTokenTag; }
1293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    bool IsUnknown() { return tag_ == kUnknownTokenTag; }
1303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    bool IsNumber() { return tag_ == kNumberTag; }
1313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    bool IsSymbol() { return tag_ == kSymbolTag; }
1323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    bool IsWhiteSpace() { return tag_ == kWhiteSpaceTag; }
1333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    bool IsEndOfInput() { return tag_ == kEndOfInputTag; }
1343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    bool IsKeyword() { return tag_ >= kKeywordTagStart; }
1353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
1363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    int length() { return length_; }
1373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
1383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    int number() {
139b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      DCHECK(IsNumber());
1403fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      return value_;
1413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
1423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    KeywordType keyword_type() {
143b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      DCHECK(IsKeyword());
1443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      return static_cast<KeywordType>(tag_);
1453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
1463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    int keyword_value() {
147b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      DCHECK(IsKeyword());
1483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      return value_;
1493fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
1503fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    char symbol() {
151b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      DCHECK(IsSymbol());
1523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      return static_cast<char>(value_);
1533fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
1543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    bool IsSymbol(char symbol) {
1553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      return IsSymbol() && this->symbol() == symbol;
1563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
1573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    bool IsKeywordType(KeywordType tag) {
1583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      return tag_ == tag;
1593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
1603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    bool IsFixedLengthNumber(int length) {
1613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      return IsNumber() && length_ == length;
1623fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
1633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    bool IsAsciiSign() {
1643fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      return tag_ == kSymbolTag && (value_ == '-' || value_ == '+');
1653fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
1663fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    int ascii_sign() {
167b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      DCHECK(IsAsciiSign());
1683fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      return 44 - value_;
1693fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
1703fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    bool IsKeywordZ() {
1713fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      return IsKeywordType(TIME_ZONE_NAME) && length_ == 1 && value_ == 0;
1723fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
1733fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    bool IsUnknown(int character) {
1743fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      return IsUnknown() && value_ == character;
1753fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
1763fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    // Factory functions.
1773fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    static DateToken Keyword(KeywordType tag, int value, int length) {
1783fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      return DateToken(tag, length, value);
1793fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
1803fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    static DateToken Number(int value, int length) {
1813fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      return DateToken(kNumberTag, length, value);
1823fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
1833fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    static DateToken Symbol(char symbol) {
1843fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      return DateToken(kSymbolTag, 1, symbol);
1853fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
1863fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    static DateToken EndOfInput() {
1873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      return DateToken(kEndOfInputTag, 0, -1);
1883fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
1893fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    static DateToken WhiteSpace(int length) {
1903fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      return DateToken(kWhiteSpaceTag, length, -1);
1913fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
1923fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    static DateToken Unknown() {
1933fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      return DateToken(kUnknownTokenTag, 1, -1);
1943fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
1953fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    static DateToken Invalid() {
1963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      return DateToken(kInvalidTokenTag, 0, -1);
1973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
198589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch
1993fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch   private:
2003fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    enum TagType {
2013fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      kInvalidTokenTag = -6,
2023fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      kUnknownTokenTag = -5,
2033fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      kWhiteSpaceTag = -4,
2043fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      kNumberTag = -3,
2053fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      kSymbolTag = -2,
2063fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      kEndOfInputTag = -1,
2073fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      kKeywordTagStart = 0
2083fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    };
2093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    DateToken(int tag, int length, int value)
2103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        : tag_(tag),
2113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          length_(length),
2123fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch          value_(value) { }
2133fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
2143fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    int tag_;
2153fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    int length_;  // Number of characters.
2163fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    int value_;
2173fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  };
2183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
2193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  template <typename Char>
2203fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  class DateStringTokenizer {
2213fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch   public:
2223fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    explicit DateStringTokenizer(InputReader<Char>* in)
2233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        : in_(in), next_(Scan()) { }
2243fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    DateToken Next() {
2253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      DateToken result = next_;
2263fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      next_ = Scan();
2273fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      return result;
2283fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
2293fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
2303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    DateToken Peek() {
2313fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      return next_;
2323fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
2333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    bool SkipSymbol(char symbol) {
2343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      if (next_.IsSymbol(symbol)) {
2353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        next_ = Scan();
2363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        return true;
2373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      }
2383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      return false;
2393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    }
240589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch
2413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch   private:
2423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    DateToken Scan();
2433fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
2443fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    InputReader<Char>* in_;
2453fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    DateToken next_;
2463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  };
2473fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
2483fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  static int ReadMilliseconds(DateToken number);
249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // KeywordTable maps names of months, time zones, am/pm to numbers.
251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  class KeywordTable : public AllStatic {
252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block   public:
253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Look up a word in the keyword table and return an index.
254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // 'pre' contains a prefix of the word, zero-padded to size kPrefixLength
255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // and 'len' is the word length.
256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    static int Lookup(const uint32_t* pre, int len);
257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Get the type of the keyword at index i.
258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    static KeywordType GetType(int i) {
259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return static_cast<KeywordType>(array[i][kTypeOffset]);
260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Get the value of the keyword at index i.
262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    static int GetValue(int i) { return array[i][kValueOffset]; }
263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    static const int kPrefixLength = 3;
265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    static const int kTypeOffset = kPrefixLength;
266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    static const int kValueOffset = kTypeOffset + 1;
267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    static const int kEntrySize = kValueOffset + 1;
268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    static const int8_t array[][kEntrySize];
269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  };
270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  class TimeZoneComposer BASE_EMBEDDED {
272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block   public:
273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    TimeZoneComposer() : sign_(kNone), hour_(kNone), minute_(kNone) {}
274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    void Set(int offset_in_hours) {
275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      sign_ = offset_in_hours < 0 ? -1 : 1;
276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      hour_ = offset_in_hours * sign_;
277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      minute_ = 0;
278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    void SetSign(int sign) { sign_ = sign < 0 ? -1 : 1; }
280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    void SetAbsoluteHour(int hour) { hour_ = hour; }
281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    void SetAbsoluteMinute(int minute) { minute_ = minute; }
282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    bool IsExpecting(int n) const {
283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return hour_ != kNone && minute_ == kNone && TimeComposer::IsMinute(n);
284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    bool IsUTC() const { return hour_ == 0 && minute_ == 0; }
286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    bool Write(FixedArray* output);
2873fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    bool IsEmpty() { return hour_ == kNone; }
288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block   private:
289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int sign_;
290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int hour_;
291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int minute_;
292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  };
293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  class TimeComposer BASE_EMBEDDED {
295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block   public:
296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    TimeComposer() : index_(0), hour_offset_(kNone) {}
297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    bool IsEmpty() const { return index_ == 0; }
298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    bool IsExpecting(int n) const {
2996ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      return (index_ == 1 && IsMinute(n)) ||
3006ded16be15dd865a9b21ea304d5273c8be299c87Steve Block             (index_ == 2 && IsSecond(n)) ||
3016ded16be15dd865a9b21ea304d5273c8be299c87Steve Block             (index_ == 3 && IsMillisecond(n));
302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    bool Add(int n) {
304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return index_ < kSize ? (comp_[index_++] = n, true) : false;
305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    bool AddFinal(int n) {
307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (!Add(n)) return false;
308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      while (index_ < kSize) comp_[index_++] = 0;
309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return true;
310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    void SetHourOffset(int n) { hour_offset_ = n; }
312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    bool Write(FixedArray* output);
313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    static bool IsMinute(int x) { return Between(x, 0, 59); }
315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    static bool IsHour(int x) { return Between(x, 0, 23); }
316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    static bool IsSecond(int x) { return Between(x, 0, 59); }
317589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch
3183fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch   private:
3193fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    static bool IsHour12(int x) { return Between(x, 0, 12); }
3206ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    static bool IsMillisecond(int x) { return Between(x, 0, 999); }
321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3226ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    static const int kSize = 4;
323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int comp_[kSize];
324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int index_;
325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int hour_offset_;
326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  };
327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  class DayComposer BASE_EMBEDDED {
329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block   public:
3303fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    DayComposer() : index_(0), named_month_(kNone), is_iso_date_(false) {}
331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    bool IsEmpty() const { return index_ == 0; }
332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    bool Add(int n) {
3333fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      if (index_ < kSize) {
3343fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        comp_[index_] = n;
3353fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        index_++;
3363fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        return true;
3373fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      }
3383fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      return false;
339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    void SetNamedMonth(int n) { named_month_ = n; }
341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    bool Write(FixedArray* output);
3423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    void set_iso_date() { is_iso_date_ = true; }
343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    static bool IsMonth(int x) { return Between(x, 1, 12); }
344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    static bool IsDay(int x) { return Between(x, 1, 31); }
345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3463fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch   private:
347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    static const int kSize = 3;
348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int comp_[kSize];
349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int index_;
350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    int named_month_;
3513fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    // If set, ensures that data is always parsed in year-month-date order.
3523fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    bool is_iso_date_;
353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  };
3543fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch
3553fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // Tries to parse an ES5 Date Time String. Returns the next token
3563fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // to continue with in the legacy date string parser. If parsing is
3573fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // complete, returns DateToken::EndOfInput(). If terminally unsuccessful,
3583fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // returns DateToken::Invalid(). Otherwise parsing continues in the
3593fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  // legacy parser.
3603fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  template <typename Char>
3613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch  static DateParser::DateToken ParseES5DateTime(
362014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      DateStringTokenizer<Char>* scanner, DayComposer* day, TimeComposer* time,
3633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      TimeZoneComposer* tz);
364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
367014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace internal
368014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace v8
369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif  // V8_DATEPARSER_H_
371