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