Home | History | Annotate | Download | only in src
      1 // Copyright 2011 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #ifndef V8_DATEPARSER_H_
     29 #define V8_DATEPARSER_H_
     30 
     31 #include "char-predicates-inl.h"
     32 #include "scanner-base.h"
     33 
     34 namespace v8 {
     35 namespace internal {
     36 
     37 class DateParser : public AllStatic {
     38  public:
     39 
     40   // Parse the string as a date. If parsing succeeds, return true after
     41   // filling out the output array as follows (all integers are Smis):
     42   // [0]: year
     43   // [1]: month (0 = Jan, 1 = Feb, ...)
     44   // [2]: day
     45   // [3]: hour
     46   // [4]: minute
     47   // [5]: second
     48   // [6]: millisecond
     49   // [7]: UTC offset in seconds, or null value if no timezone specified
     50   // If parsing fails, return false (content of output array is not defined).
     51   template <typename Char>
     52   static bool Parse(Vector<Char> str, FixedArray* output, UnicodeCache* cache);
     53 
     54   enum {
     55     YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, MILLISECOND, UTC_OFFSET, OUTPUT_SIZE
     56   };
     57 
     58  private:
     59   // Range testing
     60   static inline bool Between(int x, int lo, int hi) {
     61     return static_cast<unsigned>(x - lo) <= static_cast<unsigned>(hi - lo);
     62   }
     63   // Indicates a missing value.
     64   static const int kNone = kMaxInt;
     65 
     66   // InputReader provides basic string parsing and character classification.
     67   template <typename Char>
     68   class InputReader BASE_EMBEDDED {
     69    public:
     70     InputReader(UnicodeCache* unicode_cache, Vector<Char> s)
     71         : index_(0),
     72           buffer_(s),
     73           has_read_number_(false),
     74           unicode_cache_(unicode_cache) {
     75       Next();
     76     }
     77 
     78     // Advance to the next character of the string.
     79     void Next() { ch_ = (index_ < buffer_.length()) ? buffer_[index_++] : 0; }
     80 
     81     // Read a string of digits as an unsigned number (cap just below kMaxInt).
     82     int ReadUnsignedNumber() {
     83       has_read_number_ = true;
     84       int n;
     85       for (n = 0; IsAsciiDigit() && n < kMaxInt / 10 - 1; Next()) {
     86         n = n * 10 + ch_ - '0';
     87       }
     88       return n;
     89     }
     90 
     91     // Read a string of digits, take the first three or fewer as an unsigned
     92     // number of milliseconds, and ignore any digits after the first three.
     93     int ReadMilliseconds() {
     94       has_read_number_ = true;
     95       int n = 0;
     96       int power;
     97       for (power = 100; IsAsciiDigit(); Next(), power = power / 10) {
     98         n = n + power * (ch_ - '0');
     99       }
    100       return n;
    101     }
    102 
    103     // Read a word (sequence of chars. >= 'A'), fill the given buffer with a
    104     // lower-case prefix, and pad any remainder of the buffer with zeroes.
    105     // Return word length.
    106     int ReadWord(uint32_t* prefix, int prefix_size) {
    107       int len;
    108       for (len = 0; IsAsciiAlphaOrAbove(); Next(), len++) {
    109         if (len < prefix_size) prefix[len] = AsciiAlphaToLower(ch_);
    110       }
    111       for (int i = len; i < prefix_size; i++) prefix[i] = 0;
    112       return len;
    113     }
    114 
    115     // The skip methods return whether they actually skipped something.
    116     bool Skip(uint32_t c) {
    117       if (ch_ == c) {
    118         Next();
    119         return true;
    120       }
    121       return false;
    122     }
    123 
    124     bool SkipWhiteSpace() {
    125       if (unicode_cache_->IsWhiteSpace(ch_)) {
    126         Next();
    127         return true;
    128       }
    129       return false;
    130     }
    131 
    132     bool SkipParentheses() {
    133       if (ch_ != '(') return false;
    134       int balance = 0;
    135       do {
    136         if (ch_ == ')') --balance;
    137         else if (ch_ == '(') ++balance;
    138         Next();
    139       } while (balance > 0 && ch_);
    140       return true;
    141     }
    142 
    143     // Character testing/classification. Non-ASCII digits are not supported.
    144     bool Is(uint32_t c) const { return ch_ == c; }
    145     bool IsEnd() const { return ch_ == 0; }
    146     bool IsAsciiDigit() const { return IsDecimalDigit(ch_); }
    147     bool IsAsciiAlphaOrAbove() const { return ch_ >= 'A'; }
    148     bool IsAsciiSign() const { return ch_ == '+' || ch_ == '-'; }
    149 
    150     // Return 1 for '+' and -1 for '-'.
    151     int GetAsciiSignValue() const { return 44 - static_cast<int>(ch_); }
    152 
    153     // Indicates whether any (possibly empty!) numbers have been read.
    154     bool HasReadNumber() const { return has_read_number_; }
    155 
    156    private:
    157     int index_;
    158     Vector<Char> buffer_;
    159     bool has_read_number_;
    160     uint32_t ch_;
    161     UnicodeCache* unicode_cache_;
    162   };
    163 
    164   enum KeywordType { INVALID, MONTH_NAME, TIME_ZONE_NAME, AM_PM };
    165 
    166   // KeywordTable maps names of months, time zones, am/pm to numbers.
    167   class KeywordTable : public AllStatic {
    168    public:
    169     // Look up a word in the keyword table and return an index.
    170     // 'pre' contains a prefix of the word, zero-padded to size kPrefixLength
    171     // and 'len' is the word length.
    172     static int Lookup(const uint32_t* pre, int len);
    173     // Get the type of the keyword at index i.
    174     static KeywordType GetType(int i) {
    175       return static_cast<KeywordType>(array[i][kTypeOffset]);
    176     }
    177     // Get the value of the keyword at index i.
    178     static int GetValue(int i) { return array[i][kValueOffset]; }
    179 
    180     static const int kPrefixLength = 3;
    181     static const int kTypeOffset = kPrefixLength;
    182     static const int kValueOffset = kTypeOffset + 1;
    183     static const int kEntrySize = kValueOffset + 1;
    184     static const int8_t array[][kEntrySize];
    185   };
    186 
    187   class TimeZoneComposer BASE_EMBEDDED {
    188    public:
    189     TimeZoneComposer() : sign_(kNone), hour_(kNone), minute_(kNone) {}
    190     void Set(int offset_in_hours) {
    191       sign_ = offset_in_hours < 0 ? -1 : 1;
    192       hour_ = offset_in_hours * sign_;
    193       minute_ = 0;
    194     }
    195     void SetSign(int sign) { sign_ = sign < 0 ? -1 : 1; }
    196     void SetAbsoluteHour(int hour) { hour_ = hour; }
    197     void SetAbsoluteMinute(int minute) { minute_ = minute; }
    198     bool IsExpecting(int n) const {
    199       return hour_ != kNone && minute_ == kNone && TimeComposer::IsMinute(n);
    200     }
    201     bool IsUTC() const { return hour_ == 0 && minute_ == 0; }
    202     bool Write(FixedArray* output);
    203    private:
    204     int sign_;
    205     int hour_;
    206     int minute_;
    207   };
    208 
    209   class TimeComposer BASE_EMBEDDED {
    210    public:
    211     TimeComposer() : index_(0), hour_offset_(kNone) {}
    212     bool IsEmpty() const { return index_ == 0; }
    213     bool IsExpecting(int n) const {
    214       return (index_ == 1 && IsMinute(n)) ||
    215              (index_ == 2 && IsSecond(n)) ||
    216              (index_ == 3 && IsMillisecond(n));
    217     }
    218     bool Add(int n) {
    219       return index_ < kSize ? (comp_[index_++] = n, true) : false;
    220     }
    221     bool AddFinal(int n) {
    222       if (!Add(n)) return false;
    223       while (index_ < kSize) comp_[index_++] = 0;
    224       return true;
    225     }
    226     void SetHourOffset(int n) { hour_offset_ = n; }
    227     bool Write(FixedArray* output);
    228 
    229     static bool IsMinute(int x) { return Between(x, 0, 59); }
    230    private:
    231     static bool IsHour(int x) { return Between(x, 0, 23); }
    232     static bool IsHour12(int x) { return Between(x, 0, 12); }
    233     static bool IsSecond(int x) { return Between(x, 0, 59); }
    234     static bool IsMillisecond(int x) { return Between(x, 0, 999); }
    235 
    236     static const int kSize = 4;
    237     int comp_[kSize];
    238     int index_;
    239     int hour_offset_;
    240   };
    241 
    242   class DayComposer BASE_EMBEDDED {
    243    public:
    244     DayComposer() : index_(0), named_month_(kNone) {}
    245     bool IsEmpty() const { return index_ == 0; }
    246     bool Add(int n) {
    247       return index_ < kSize ? (comp_[index_++] = n, true) : false;
    248     }
    249     void SetNamedMonth(int n) { named_month_ = n; }
    250     bool Write(FixedArray* output);
    251    private:
    252     static bool IsMonth(int x) { return Between(x, 1, 12); }
    253     static bool IsDay(int x) { return Between(x, 1, 31); }
    254 
    255     static const int kSize = 3;
    256     int comp_[kSize];
    257     int index_;
    258     int named_month_;
    259   };
    260 };
    261 
    262 
    263 } }  // namespace v8::internal
    264 
    265 #endif  // V8_DATEPARSER_H_
    266