blob: 9d297155230b13c8664b7a1a754fe9ed423e0d93 [file] [log] [blame]
Ben Murdoch8b112d22011-06-08 16:22:53 +01001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// 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
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080031#include "char-predicates-inl.h"
32#include "scanner-base.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000033
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
Steve Block6ded16b2010-05-10 14:33:55 +010048 // [6]: millisecond
49 // [7]: UTC offset in seconds, or null value if no timezone specified
Steve Blocka7e24c12009-10-30 11:49:00 +000050 // If parsing fails, return false (content of output array is not defined).
51 template <typename Char>
Ben Murdoch8b112d22011-06-08 16:22:53 +010052 static bool Parse(Vector<Char> str, FixedArray* output, UnicodeCache* cache);
Steve Blocka7e24c12009-10-30 11:49:00 +000053
54 enum {
Steve Block6ded16b2010-05-10 14:33:55 +010055 YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, MILLISECOND, UTC_OFFSET, OUTPUT_SIZE
Steve Blocka7e24c12009-10-30 11:49:00 +000056 };
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:
Ben Murdoch8b112d22011-06-08 16:22:53 +010070 InputReader(UnicodeCache* unicode_cache, Vector<Char> s)
Steve Blocka7e24c12009-10-30 11:49:00 +000071 : index_(0),
72 buffer_(s),
Steve Block44f0eee2011-05-26 01:26:41 +010073 has_read_number_(false),
Ben Murdoch8b112d22011-06-08 16:22:53 +010074 unicode_cache_(unicode_cache) {
Steve Blocka7e24c12009-10-30 11:49:00 +000075 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
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080091 // 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
Steve Blocka7e24c12009-10-30 11:49:00 +0000103 // 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++) {
Iain Merrick9ac36c92010-09-13 15:29:50 +0100109 if (len < prefix_size) prefix[len] = AsciiAlphaToLower(ch_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000110 }
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.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800116 bool Skip(uint32_t c) {
117 if (ch_ == c) {
118 Next();
119 return true;
120 }
121 return false;
122 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000123
124 bool SkipWhiteSpace() {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100125 if (unicode_cache_->IsWhiteSpace(ch_)) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800126 Next();
127 return true;
128 }
129 return false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000130 }
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:
Steve Blocka7e24c12009-10-30 11:49:00 +0000157 int index_;
158 Vector<Char> buffer_;
159 bool has_read_number_;
160 uint32_t ch_;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100161 UnicodeCache* unicode_cache_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000162 };
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 {
Steve Block6ded16b2010-05-10 14:33:55 +0100214 return (index_ == 1 && IsMinute(n)) ||
215 (index_ == 2 && IsSecond(n)) ||
216 (index_ == 3 && IsMillisecond(n));
Steve Blocka7e24c12009-10-30 11:49:00 +0000217 }
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); }
Steve Block6ded16b2010-05-10 14:33:55 +0100234 static bool IsMillisecond(int x) { return Between(x, 0, 999); }
Steve Blocka7e24c12009-10-30 11:49:00 +0000235
Steve Block6ded16b2010-05-10 14:33:55 +0100236 static const int kSize = 4;
Steve Blocka7e24c12009-10-30 11:49:00 +0000237 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_