blob: cae9b08d5b191b58ec55799c9ee3d4621a231d15 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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
31#include "scanner.h"
32
kasperl@chromium.org71affb52009-05-26 05:44:31 +000033namespace v8 {
34namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000035
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036class DateParser : public AllStatic {
37 public:
38
39 // Parse the string as a date. If parsing succeeds, return true after
40 // filling out the output array as follows (all integers are Smis):
41 // [0]: year
42 // [1]: month (0 = Jan, 1 = Feb, ...)
43 // [2]: day
44 // [3]: hour
45 // [4]: minute
46 // [5]: second
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000047 // [6]: millisecond
48 // [7]: UTC offset in seconds, or null value if no timezone specified
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049 // If parsing fails, return false (content of output array is not defined).
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000050 template <typename Char>
51 static bool Parse(Vector<Char> str, FixedArray* output);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000053 enum {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000054 YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, MILLISECOND, UTC_OFFSET, OUTPUT_SIZE
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000055 };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000056
57 private:
58 // Range testing
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000059 static inline bool Between(int x, int lo, int hi) {
60 return static_cast<unsigned>(x - lo) <= static_cast<unsigned>(hi - lo);
61 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000062 // Indicates a missing value.
63 static const int kNone = kMaxInt;
64
65 // InputReader provides basic string parsing and character classification.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000066 template <typename Char>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000067 class InputReader BASE_EMBEDDED {
68 public:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000069 explicit InputReader(Vector<Char> s)
70 : index_(0),
71 buffer_(s),
72 has_read_number_(false) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000073 Next();
74 }
75
76 // Advance to the next character of the string.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000077 void Next() { ch_ = (index_ < buffer_.length()) ? buffer_[index_++] : 0; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000078
79 // Read a string of digits as an unsigned number (cap just below kMaxInt).
80 int ReadUnsignedNumber() {
81 has_read_number_ = true;
82 int n;
83 for (n = 0; IsAsciiDigit() && n < kMaxInt / 10 - 1; Next()) {
84 n = n * 10 + ch_ - '0';
85 }
86 return n;
87 }
88
89 // Read a word (sequence of chars. >= 'A'), fill the given buffer with a
90 // lower-case prefix, and pad any remainder of the buffer with zeroes.
91 // Return word length.
92 int ReadWord(uint32_t* prefix, int prefix_size) {
93 int len;
94 for (len = 0; IsAsciiAlphaOrAbove(); Next(), len++) {
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +000095 if (len < prefix_size) prefix[len] = AsciiAlphaToLower(ch_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096 }
97 for (int i = len; i < prefix_size; i++) prefix[i] = 0;
98 return len;
99 }
100
101 // The skip methods return whether they actually skipped something.
102 bool Skip(uint32_t c) { return ch_ == c ? (Next(), true) : false; }
103
104 bool SkipWhiteSpace() {
105 return Scanner::kIsWhiteSpace.get(ch_) ? (Next(), true) : false;
106 }
107
108 bool SkipParentheses() {
109 if (ch_ != '(') return false;
110 int balance = 0;
111 do {
112 if (ch_ == ')') --balance;
113 else if (ch_ == '(') ++balance;
114 Next();
115 } while (balance > 0 && ch_);
116 return true;
117 }
118
119 // Character testing/classification. Non-ASCII digits are not supported.
120 bool Is(uint32_t c) const { return ch_ == c; }
121 bool IsEnd() const { return ch_ == 0; }
122 bool IsAsciiDigit() const { return IsDecimalDigit(ch_); }
123 bool IsAsciiAlphaOrAbove() const { return ch_ >= 'A'; }
124 bool IsAsciiSign() const { return ch_ == '+' || ch_ == '-'; }
125
126 // Return 1 for '+' and -1 for '-'.
127 int GetAsciiSignValue() const { return 44 - static_cast<int>(ch_); }
128
129 // Indicates whether any (possibly empty!) numbers have been read.
130 bool HasReadNumber() const { return has_read_number_; }
131
132 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000133 int index_;
134 Vector<Char> buffer_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000135 bool has_read_number_;
136 uint32_t ch_;
137 };
138
139 enum KeywordType { INVALID, MONTH_NAME, TIME_ZONE_NAME, AM_PM };
140
141 // KeywordTable maps names of months, time zones, am/pm to numbers.
142 class KeywordTable : public AllStatic {
143 public:
144 // Look up a word in the keyword table and return an index.
145 // 'pre' contains a prefix of the word, zero-padded to size kPrefixLength
146 // and 'len' is the word length.
147 static int Lookup(const uint32_t* pre, int len);
148 // Get the type of the keyword at index i.
149 static KeywordType GetType(int i) {
150 return static_cast<KeywordType>(array[i][kTypeOffset]);
151 }
152 // Get the value of the keyword at index i.
153 static int GetValue(int i) { return array[i][kValueOffset]; }
154
155 static const int kPrefixLength = 3;
156 static const int kTypeOffset = kPrefixLength;
157 static const int kValueOffset = kTypeOffset + 1;
158 static const int kEntrySize = kValueOffset + 1;
159 static const int8_t array[][kEntrySize];
160 };
161
162 class TimeZoneComposer BASE_EMBEDDED {
163 public:
164 TimeZoneComposer() : sign_(kNone), hour_(kNone), minute_(kNone) {}
165 void Set(int offset_in_hours) {
166 sign_ = offset_in_hours < 0 ? -1 : 1;
167 hour_ = offset_in_hours * sign_;
168 minute_ = 0;
169 }
170 void SetSign(int sign) { sign_ = sign < 0 ? -1 : 1; }
171 void SetAbsoluteHour(int hour) { hour_ = hour; }
172 void SetAbsoluteMinute(int minute) { minute_ = minute; }
173 bool IsExpecting(int n) const {
174 return hour_ != kNone && minute_ == kNone && TimeComposer::IsMinute(n);
175 }
176 bool IsUTC() const { return hour_ == 0 && minute_ == 0; }
177 bool Write(FixedArray* output);
178 private:
179 int sign_;
180 int hour_;
181 int minute_;
182 };
183
184 class TimeComposer BASE_EMBEDDED {
185 public:
186 TimeComposer() : index_(0), hour_offset_(kNone) {}
187 bool IsEmpty() const { return index_ == 0; }
188 bool IsExpecting(int n) const {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000189 return (index_ == 1 && IsMinute(n)) ||
190 (index_ == 2 && IsSecond(n)) ||
191 (index_ == 3 && IsMillisecond(n));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000192 }
193 bool Add(int n) {
194 return index_ < kSize ? (comp_[index_++] = n, true) : false;
195 }
196 bool AddFinal(int n) {
197 if (!Add(n)) return false;
198 while (index_ < kSize) comp_[index_++] = 0;
199 return true;
200 }
201 void SetHourOffset(int n) { hour_offset_ = n; }
202 bool Write(FixedArray* output);
203
204 static bool IsMinute(int x) { return Between(x, 0, 59); }
205 private:
206 static bool IsHour(int x) { return Between(x, 0, 23); }
207 static bool IsHour12(int x) { return Between(x, 0, 12); }
208 static bool IsSecond(int x) { return Between(x, 0, 59); }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000209 static bool IsMillisecond(int x) { return Between(x, 0, 999); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000210
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000211 static const int kSize = 4;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000212 int comp_[kSize];
213 int index_;
214 int hour_offset_;
215 };
216
217 class DayComposer BASE_EMBEDDED {
218 public:
219 DayComposer() : index_(0), named_month_(kNone) {}
220 bool IsEmpty() const { return index_ == 0; }
221 bool Add(int n) {
222 return index_ < kSize ? (comp_[index_++] = n, true) : false;
223 }
224 void SetNamedMonth(int n) { named_month_ = n; }
225 bool Write(FixedArray* output);
226 private:
227 static bool IsMonth(int x) { return Between(x, 1, 12); }
228 static bool IsDay(int x) { return Between(x, 1, 31); }
229
230 static const int kSize = 3;
231 int comp_[kSize];
232 int index_;
233 int named_month_;
234 };
235};
236
237
238} } // namespace v8::internal
239
240#endif // V8_DATEPARSER_H_