blob: 40e56f3024be49155b19ddc4cfb7d5ef602ad124 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2008 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
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>
52 static bool Parse(Vector<Char> str, FixedArray* output);
53
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:
70 explicit InputReader(Vector<Char> s)
71 : index_(0),
72 buffer_(s),
73 has_read_number_(false) {
74 Next();
75 }
76
77 // Advance to the next character of the string.
78 void Next() { ch_ = (index_ < buffer_.length()) ? buffer_[index_++] : 0; }
79
80 // Read a string of digits as an unsigned number (cap just below kMaxInt).
81 int ReadUnsignedNumber() {
82 has_read_number_ = true;
83 int n;
84 for (n = 0; IsAsciiDigit() && n < kMaxInt / 10 - 1; Next()) {
85 n = n * 10 + ch_ - '0';
86 }
87 return n;
88 }
89
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080090 // Read a string of digits, take the first three or fewer as an unsigned
91 // number of milliseconds, and ignore any digits after the first three.
92 int ReadMilliseconds() {
93 has_read_number_ = true;
94 int n = 0;
95 int power;
96 for (power = 100; IsAsciiDigit(); Next(), power = power / 10) {
97 n = n + power * (ch_ - '0');
98 }
99 return n;
100 }
101
Steve Blocka7e24c12009-10-30 11:49:00 +0000102 // Read a word (sequence of chars. >= 'A'), fill the given buffer with a
103 // lower-case prefix, and pad any remainder of the buffer with zeroes.
104 // Return word length.
105 int ReadWord(uint32_t* prefix, int prefix_size) {
106 int len;
107 for (len = 0; IsAsciiAlphaOrAbove(); Next(), len++) {
Iain Merrick9ac36c92010-09-13 15:29:50 +0100108 if (len < prefix_size) prefix[len] = AsciiAlphaToLower(ch_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000109 }
110 for (int i = len; i < prefix_size; i++) prefix[i] = 0;
111 return len;
112 }
113
114 // The skip methods return whether they actually skipped something.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800115 bool Skip(uint32_t c) {
116 if (ch_ == c) {
117 Next();
118 return true;
119 }
120 return false;
121 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000122
123 bool SkipWhiteSpace() {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800124 if (ScannerConstants::kIsWhiteSpace.get(ch_)) {
125 Next();
126 return true;
127 }
128 return false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000129 }
130
131 bool SkipParentheses() {
132 if (ch_ != '(') return false;
133 int balance = 0;
134 do {
135 if (ch_ == ')') --balance;
136 else if (ch_ == '(') ++balance;
137 Next();
138 } while (balance > 0 && ch_);
139 return true;
140 }
141
142 // Character testing/classification. Non-ASCII digits are not supported.
143 bool Is(uint32_t c) const { return ch_ == c; }
144 bool IsEnd() const { return ch_ == 0; }
145 bool IsAsciiDigit() const { return IsDecimalDigit(ch_); }
146 bool IsAsciiAlphaOrAbove() const { return ch_ >= 'A'; }
147 bool IsAsciiSign() const { return ch_ == '+' || ch_ == '-'; }
148
149 // Return 1 for '+' and -1 for '-'.
150 int GetAsciiSignValue() const { return 44 - static_cast<int>(ch_); }
151
152 // Indicates whether any (possibly empty!) numbers have been read.
153 bool HasReadNumber() const { return has_read_number_; }
154
155 private:
Steve Blocka7e24c12009-10-30 11:49:00 +0000156 int index_;
157 Vector<Char> buffer_;
158 bool has_read_number_;
159 uint32_t ch_;
160 };
161
162 enum KeywordType { INVALID, MONTH_NAME, TIME_ZONE_NAME, AM_PM };
163
164 // KeywordTable maps names of months, time zones, am/pm to numbers.
165 class KeywordTable : public AllStatic {
166 public:
167 // Look up a word in the keyword table and return an index.
168 // 'pre' contains a prefix of the word, zero-padded to size kPrefixLength
169 // and 'len' is the word length.
170 static int Lookup(const uint32_t* pre, int len);
171 // Get the type of the keyword at index i.
172 static KeywordType GetType(int i) {
173 return static_cast<KeywordType>(array[i][kTypeOffset]);
174 }
175 // Get the value of the keyword at index i.
176 static int GetValue(int i) { return array[i][kValueOffset]; }
177
178 static const int kPrefixLength = 3;
179 static const int kTypeOffset = kPrefixLength;
180 static const int kValueOffset = kTypeOffset + 1;
181 static const int kEntrySize = kValueOffset + 1;
182 static const int8_t array[][kEntrySize];
183 };
184
185 class TimeZoneComposer BASE_EMBEDDED {
186 public:
187 TimeZoneComposer() : sign_(kNone), hour_(kNone), minute_(kNone) {}
188 void Set(int offset_in_hours) {
189 sign_ = offset_in_hours < 0 ? -1 : 1;
190 hour_ = offset_in_hours * sign_;
191 minute_ = 0;
192 }
193 void SetSign(int sign) { sign_ = sign < 0 ? -1 : 1; }
194 void SetAbsoluteHour(int hour) { hour_ = hour; }
195 void SetAbsoluteMinute(int minute) { minute_ = minute; }
196 bool IsExpecting(int n) const {
197 return hour_ != kNone && minute_ == kNone && TimeComposer::IsMinute(n);
198 }
199 bool IsUTC() const { return hour_ == 0 && minute_ == 0; }
200 bool Write(FixedArray* output);
201 private:
202 int sign_;
203 int hour_;
204 int minute_;
205 };
206
207 class TimeComposer BASE_EMBEDDED {
208 public:
209 TimeComposer() : index_(0), hour_offset_(kNone) {}
210 bool IsEmpty() const { return index_ == 0; }
211 bool IsExpecting(int n) const {
Steve Block6ded16b2010-05-10 14:33:55 +0100212 return (index_ == 1 && IsMinute(n)) ||
213 (index_ == 2 && IsSecond(n)) ||
214 (index_ == 3 && IsMillisecond(n));
Steve Blocka7e24c12009-10-30 11:49:00 +0000215 }
216 bool Add(int n) {
217 return index_ < kSize ? (comp_[index_++] = n, true) : false;
218 }
219 bool AddFinal(int n) {
220 if (!Add(n)) return false;
221 while (index_ < kSize) comp_[index_++] = 0;
222 return true;
223 }
224 void SetHourOffset(int n) { hour_offset_ = n; }
225 bool Write(FixedArray* output);
226
227 static bool IsMinute(int x) { return Between(x, 0, 59); }
228 private:
229 static bool IsHour(int x) { return Between(x, 0, 23); }
230 static bool IsHour12(int x) { return Between(x, 0, 12); }
231 static bool IsSecond(int x) { return Between(x, 0, 59); }
Steve Block6ded16b2010-05-10 14:33:55 +0100232 static bool IsMillisecond(int x) { return Between(x, 0, 999); }
Steve Blocka7e24c12009-10-30 11:49:00 +0000233
Steve Block6ded16b2010-05-10 14:33:55 +0100234 static const int kSize = 4;
Steve Blocka7e24c12009-10-30 11:49:00 +0000235 int comp_[kSize];
236 int index_;
237 int hour_offset_;
238 };
239
240 class DayComposer BASE_EMBEDDED {
241 public:
242 DayComposer() : index_(0), named_month_(kNone) {}
243 bool IsEmpty() const { return index_ == 0; }
244 bool Add(int n) {
245 return index_ < kSize ? (comp_[index_++] = n, true) : false;
246 }
247 void SetNamedMonth(int n) { named_month_ = n; }
248 bool Write(FixedArray* output);
249 private:
250 static bool IsMonth(int x) { return Between(x, 1, 12); }
251 static bool IsDay(int x) { return Between(x, 1, 31); }
252
253 static const int kSize = 3;
254 int comp_[kSize];
255 int index_;
256 int named_month_;
257 };
258};
259
260
261} } // namespace v8::internal
262
263#endif // V8_DATEPARSER_H_