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
34namespace v8 {
35namespace internal {
36
37class 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