blob: 6e87c3418519bb8a322086052f9576fd0ce4b6da [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
Ben Murdoch257744e2011-11-30 15:57:28 +000031#include "allocation.h"
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080032#include "char-predicates-inl.h"
33#include "scanner-base.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000034
35namespace v8 {
36namespace internal {
37
38class DateParser : public AllStatic {
39 public:
40
41 // Parse the string as a date. If parsing succeeds, return true after
42 // filling out the output array as follows (all integers are Smis):
43 // [0]: year
44 // [1]: month (0 = Jan, 1 = Feb, ...)
45 // [2]: day
46 // [3]: hour
47 // [4]: minute
48 // [5]: second
Steve Block6ded16b2010-05-10 14:33:55 +010049 // [6]: millisecond
50 // [7]: UTC offset in seconds, or null value if no timezone specified
Steve Blocka7e24c12009-10-30 11:49:00 +000051 // If parsing fails, return false (content of output array is not defined).
52 template <typename Char>
Ben Murdoch8b112d22011-06-08 16:22:53 +010053 static bool Parse(Vector<Char> str, FixedArray* output, UnicodeCache* cache);
Steve Blocka7e24c12009-10-30 11:49:00 +000054
55 enum {
Steve Block6ded16b2010-05-10 14:33:55 +010056 YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, MILLISECOND, UTC_OFFSET, OUTPUT_SIZE
Steve Blocka7e24c12009-10-30 11:49:00 +000057 };
58
59 private:
60 // Range testing
61 static inline bool Between(int x, int lo, int hi) {
62 return static_cast<unsigned>(x - lo) <= static_cast<unsigned>(hi - lo);
63 }
64 // Indicates a missing value.
65 static const int kNone = kMaxInt;
66
67 // InputReader provides basic string parsing and character classification.
68 template <typename Char>
69 class InputReader BASE_EMBEDDED {
70 public:
Ben Murdoch8b112d22011-06-08 16:22:53 +010071 InputReader(UnicodeCache* unicode_cache, Vector<Char> s)
Steve Blocka7e24c12009-10-30 11:49:00 +000072 : index_(0),
73 buffer_(s),
Steve Block44f0eee2011-05-26 01:26:41 +010074 has_read_number_(false),
Ben Murdoch8b112d22011-06-08 16:22:53 +010075 unicode_cache_(unicode_cache) {
Steve Blocka7e24c12009-10-30 11:49:00 +000076 Next();
77 }
78
79 // Advance to the next character of the string.
80 void Next() { ch_ = (index_ < buffer_.length()) ? buffer_[index_++] : 0; }
81
82 // Read a string of digits as an unsigned number (cap just below kMaxInt).
83 int ReadUnsignedNumber() {
84 has_read_number_ = true;
85 int n;
86 for (n = 0; IsAsciiDigit() && n < kMaxInt / 10 - 1; Next()) {
87 n = n * 10 + ch_ - '0';
88 }
89 return n;
90 }
91
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080092 // Read a string of digits, take the first three or fewer as an unsigned
93 // number of milliseconds, and ignore any digits after the first three.
94 int ReadMilliseconds() {
95 has_read_number_ = true;
96 int n = 0;
97 int power;
98 for (power = 100; IsAsciiDigit(); Next(), power = power / 10) {
99 n = n + power * (ch_ - '0');
100 }
101 return n;
102 }
103
Steve Blocka7e24c12009-10-30 11:49:00 +0000104 // Read a word (sequence of chars. >= 'A'), fill the given buffer with a
105 // lower-case prefix, and pad any remainder of the buffer with zeroes.
106 // Return word length.
107 int ReadWord(uint32_t* prefix, int prefix_size) {
108 int len;
109 for (len = 0; IsAsciiAlphaOrAbove(); Next(), len++) {
Iain Merrick9ac36c92010-09-13 15:29:50 +0100110 if (len < prefix_size) prefix[len] = AsciiAlphaToLower(ch_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000111 }
112 for (int i = len; i < prefix_size; i++) prefix[i] = 0;
113 return len;
114 }
115
116 // The skip methods return whether they actually skipped something.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800117 bool Skip(uint32_t c) {
118 if (ch_ == c) {
119 Next();
120 return true;
121 }
122 return false;
123 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000124
125 bool SkipWhiteSpace() {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100126 if (unicode_cache_->IsWhiteSpace(ch_)) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800127 Next();
128 return true;
129 }
130 return false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000131 }
132
133 bool SkipParentheses() {
134 if (ch_ != '(') return false;
135 int balance = 0;
136 do {
137 if (ch_ == ')') --balance;
138 else if (ch_ == '(') ++balance;
139 Next();
140 } while (balance > 0 && ch_);
141 return true;
142 }
143
144 // Character testing/classification. Non-ASCII digits are not supported.
145 bool Is(uint32_t c) const { return ch_ == c; }
146 bool IsEnd() const { return ch_ == 0; }
147 bool IsAsciiDigit() const { return IsDecimalDigit(ch_); }
148 bool IsAsciiAlphaOrAbove() const { return ch_ >= 'A'; }
149 bool IsAsciiSign() const { return ch_ == '+' || ch_ == '-'; }
150
151 // Return 1 for '+' and -1 for '-'.
152 int GetAsciiSignValue() const { return 44 - static_cast<int>(ch_); }
153
154 // Indicates whether any (possibly empty!) numbers have been read.
155 bool HasReadNumber() const { return has_read_number_; }
156
157 private:
Steve Blocka7e24c12009-10-30 11:49:00 +0000158 int index_;
159 Vector<Char> buffer_;
160 bool has_read_number_;
161 uint32_t ch_;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100162 UnicodeCache* unicode_cache_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000163 };
164
165 enum KeywordType { INVALID, MONTH_NAME, TIME_ZONE_NAME, AM_PM };
166
167 // KeywordTable maps names of months, time zones, am/pm to numbers.
168 class KeywordTable : public AllStatic {
169 public:
170 // Look up a word in the keyword table and return an index.
171 // 'pre' contains a prefix of the word, zero-padded to size kPrefixLength
172 // and 'len' is the word length.
173 static int Lookup(const uint32_t* pre, int len);
174 // Get the type of the keyword at index i.
175 static KeywordType GetType(int i) {
176 return static_cast<KeywordType>(array[i][kTypeOffset]);
177 }
178 // Get the value of the keyword at index i.
179 static int GetValue(int i) { return array[i][kValueOffset]; }
180
181 static const int kPrefixLength = 3;
182 static const int kTypeOffset = kPrefixLength;
183 static const int kValueOffset = kTypeOffset + 1;
184 static const int kEntrySize = kValueOffset + 1;
185 static const int8_t array[][kEntrySize];
186 };
187
188 class TimeZoneComposer BASE_EMBEDDED {
189 public:
190 TimeZoneComposer() : sign_(kNone), hour_(kNone), minute_(kNone) {}
191 void Set(int offset_in_hours) {
192 sign_ = offset_in_hours < 0 ? -1 : 1;
193 hour_ = offset_in_hours * sign_;
194 minute_ = 0;
195 }
196 void SetSign(int sign) { sign_ = sign < 0 ? -1 : 1; }
197 void SetAbsoluteHour(int hour) { hour_ = hour; }
198 void SetAbsoluteMinute(int minute) { minute_ = minute; }
199 bool IsExpecting(int n) const {
200 return hour_ != kNone && minute_ == kNone && TimeComposer::IsMinute(n);
201 }
202 bool IsUTC() const { return hour_ == 0 && minute_ == 0; }
203 bool Write(FixedArray* output);
204 private:
205 int sign_;
206 int hour_;
207 int minute_;
208 };
209
210 class TimeComposer BASE_EMBEDDED {
211 public:
212 TimeComposer() : index_(0), hour_offset_(kNone) {}
213 bool IsEmpty() const { return index_ == 0; }
214 bool IsExpecting(int n) const {
Steve Block6ded16b2010-05-10 14:33:55 +0100215 return (index_ == 1 && IsMinute(n)) ||
216 (index_ == 2 && IsSecond(n)) ||
217 (index_ == 3 && IsMillisecond(n));
Steve Blocka7e24c12009-10-30 11:49:00 +0000218 }
219 bool Add(int n) {
220 return index_ < kSize ? (comp_[index_++] = n, true) : false;
221 }
222 bool AddFinal(int n) {
223 if (!Add(n)) return false;
224 while (index_ < kSize) comp_[index_++] = 0;
225 return true;
226 }
227 void SetHourOffset(int n) { hour_offset_ = n; }
228 bool Write(FixedArray* output);
229
230 static bool IsMinute(int x) { return Between(x, 0, 59); }
231 private:
232 static bool IsHour(int x) { return Between(x, 0, 23); }
233 static bool IsHour12(int x) { return Between(x, 0, 12); }
234 static bool IsSecond(int x) { return Between(x, 0, 59); }
Steve Block6ded16b2010-05-10 14:33:55 +0100235 static bool IsMillisecond(int x) { return Between(x, 0, 999); }
Steve Blocka7e24c12009-10-30 11:49:00 +0000236
Steve Block6ded16b2010-05-10 14:33:55 +0100237 static const int kSize = 4;
Steve Blocka7e24c12009-10-30 11:49:00 +0000238 int comp_[kSize];
239 int index_;
240 int hour_offset_;
241 };
242
243 class DayComposer BASE_EMBEDDED {
244 public:
245 DayComposer() : index_(0), named_month_(kNone) {}
246 bool IsEmpty() const { return index_ == 0; }
247 bool Add(int n) {
248 return index_ < kSize ? (comp_[index_++] = n, true) : false;
249 }
250 void SetNamedMonth(int n) { named_month_ = n; }
251 bool Write(FixedArray* output);
252 private:
253 static bool IsMonth(int x) { return Between(x, 1, 12); }
254 static bool IsDay(int x) { return Between(x, 1, 31); }
255
256 static const int kSize = 3;
257 int comp_[kSize];
258 int index_;
259 int named_month_;
260 };
261};
262
263
264} } // namespace v8::internal
265
266#endif // V8_DATEPARSER_H_