1 // 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 31 #include "scanner.h" 32 33 namespace v8 { 34 namespace internal { 35 36 class 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 47 // [6]: UTC offset in seconds, or null value if no timezone specified 48 // If parsing fails, return false (content of output array is not defined). 49 template <typename Char> 50 static bool Parse(Vector<Char> str, FixedArray* output); 51 52 enum { 53 YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, UTC_OFFSET, OUTPUT_SIZE 54 }; 55 56 private: 57 // Range testing Between(int x,int lo,int hi)58 static inline bool Between(int x, int lo, int hi) { 59 return static_cast<unsigned>(x - lo) <= static_cast<unsigned>(hi - lo); 60 } 61 // Indicates a missing value. 62 static const int kNone = kMaxInt; 63 64 // InputReader provides basic string parsing and character classification. 65 template <typename Char> 66 class InputReader BASE_EMBEDDED { 67 public: InputReader(Vector<Char> s)68 explicit InputReader(Vector<Char> s) 69 : index_(0), 70 buffer_(s), 71 has_read_number_(false) { 72 Next(); 73 } 74 75 // Advance to the next character of the string. Next()76 void Next() { ch_ = (index_ < buffer_.length()) ? buffer_[index_++] : 0; } 77 78 // Read a string of digits as an unsigned number (cap just below kMaxInt). ReadUnsignedNumber()79 int ReadUnsignedNumber() { 80 has_read_number_ = true; 81 int n; 82 for (n = 0; IsAsciiDigit() && n < kMaxInt / 10 - 1; Next()) { 83 n = n * 10 + ch_ - '0'; 84 } 85 return n; 86 } 87 88 // Read a word (sequence of chars. >= 'A'), fill the given buffer with a 89 // lower-case prefix, and pad any remainder of the buffer with zeroes. 90 // Return word length. ReadWord(uint32_t * prefix,int prefix_size)91 int ReadWord(uint32_t* prefix, int prefix_size) { 92 int len; 93 for (len = 0; IsAsciiAlphaOrAbove(); Next(), len++) { 94 if (len < prefix_size) prefix[len] = GetAsciiAlphaLower(); 95 } 96 for (int i = len; i < prefix_size; i++) prefix[i] = 0; 97 return len; 98 } 99 100 // The skip methods return whether they actually skipped something. Skip(uint32_t c)101 bool Skip(uint32_t c) { return ch_ == c ? (Next(), true) : false; } 102 SkipWhiteSpace()103 bool SkipWhiteSpace() { 104 return Scanner::kIsWhiteSpace.get(ch_) ? (Next(), true) : false; 105 } 106 SkipParentheses()107 bool SkipParentheses() { 108 if (ch_ != '(') return false; 109 int balance = 0; 110 do { 111 if (ch_ == ')') --balance; 112 else if (ch_ == '(') ++balance; 113 Next(); 114 } while (balance > 0 && ch_); 115 return true; 116 } 117 118 // Character testing/classification. Non-ASCII digits are not supported. Is(uint32_t c)119 bool Is(uint32_t c) const { return ch_ == c; } IsEnd()120 bool IsEnd() const { return ch_ == 0; } IsAsciiDigit()121 bool IsAsciiDigit() const { return IsDecimalDigit(ch_); } IsAsciiAlphaOrAbove()122 bool IsAsciiAlphaOrAbove() const { return ch_ >= 'A'; } IsAsciiSign()123 bool IsAsciiSign() const { return ch_ == '+' || ch_ == '-'; } 124 125 // Return 1 for '+' and -1 for '-'. GetAsciiSignValue()126 int GetAsciiSignValue() const { return 44 - static_cast<int>(ch_); } 127 128 // Indicates whether any (possibly empty!) numbers have been read. HasReadNumber()129 bool HasReadNumber() const { return has_read_number_; } 130 131 private: 132 // If current character is in 'A'-'Z' or 'a'-'z', return its lower-case. 133 // Else, return something outside of 'A'-'Z' and 'a'-'z'. GetAsciiAlphaLower()134 uint32_t GetAsciiAlphaLower() const { return ch_ | 32; } 135 136 int index_; 137 Vector<Char> buffer_; 138 bool has_read_number_; 139 uint32_t ch_; 140 }; 141 142 enum KeywordType { INVALID, MONTH_NAME, TIME_ZONE_NAME, AM_PM }; 143 144 // KeywordTable maps names of months, time zones, am/pm to numbers. 145 class KeywordTable : public AllStatic { 146 public: 147 // Look up a word in the keyword table and return an index. 148 // 'pre' contains a prefix of the word, zero-padded to size kPrefixLength 149 // and 'len' is the word length. 150 static int Lookup(const uint32_t* pre, int len); 151 // Get the type of the keyword at index i. GetType(int i)152 static KeywordType GetType(int i) { 153 return static_cast<KeywordType>(array[i][kTypeOffset]); 154 } 155 // Get the value of the keyword at index i. GetValue(int i)156 static int GetValue(int i) { return array[i][kValueOffset]; } 157 158 static const int kPrefixLength = 3; 159 static const int kTypeOffset = kPrefixLength; 160 static const int kValueOffset = kTypeOffset + 1; 161 static const int kEntrySize = kValueOffset + 1; 162 static const int8_t array[][kEntrySize]; 163 }; 164 165 class TimeZoneComposer BASE_EMBEDDED { 166 public: TimeZoneComposer()167 TimeZoneComposer() : sign_(kNone), hour_(kNone), minute_(kNone) {} Set(int offset_in_hours)168 void Set(int offset_in_hours) { 169 sign_ = offset_in_hours < 0 ? -1 : 1; 170 hour_ = offset_in_hours * sign_; 171 minute_ = 0; 172 } SetSign(int sign)173 void SetSign(int sign) { sign_ = sign < 0 ? -1 : 1; } SetAbsoluteHour(int hour)174 void SetAbsoluteHour(int hour) { hour_ = hour; } SetAbsoluteMinute(int minute)175 void SetAbsoluteMinute(int minute) { minute_ = minute; } IsExpecting(int n)176 bool IsExpecting(int n) const { 177 return hour_ != kNone && minute_ == kNone && TimeComposer::IsMinute(n); 178 } IsUTC()179 bool IsUTC() const { return hour_ == 0 && minute_ == 0; } 180 bool Write(FixedArray* output); 181 private: 182 int sign_; 183 int hour_; 184 int minute_; 185 }; 186 187 class TimeComposer BASE_EMBEDDED { 188 public: TimeComposer()189 TimeComposer() : index_(0), hour_offset_(kNone) {} IsEmpty()190 bool IsEmpty() const { return index_ == 0; } IsExpecting(int n)191 bool IsExpecting(int n) const { 192 return (index_ == 1 && IsMinute(n)) || (index_ == 2 && IsSecond(n)); 193 } Add(int n)194 bool Add(int n) { 195 return index_ < kSize ? (comp_[index_++] = n, true) : false; 196 } AddFinal(int n)197 bool AddFinal(int n) { 198 if (!Add(n)) return false; 199 while (index_ < kSize) comp_[index_++] = 0; 200 return true; 201 } SetHourOffset(int n)202 void SetHourOffset(int n) { hour_offset_ = n; } 203 bool Write(FixedArray* output); 204 IsMinute(int x)205 static bool IsMinute(int x) { return Between(x, 0, 59); } 206 private: IsHour(int x)207 static bool IsHour(int x) { return Between(x, 0, 23); } IsHour12(int x)208 static bool IsHour12(int x) { return Between(x, 0, 12); } IsSecond(int x)209 static bool IsSecond(int x) { return Between(x, 0, 59); } 210 211 static const int kSize = 3; 212 int comp_[kSize]; 213 int index_; 214 int hour_offset_; 215 }; 216 217 class DayComposer BASE_EMBEDDED { 218 public: DayComposer()219 DayComposer() : index_(0), named_month_(kNone) {} IsEmpty()220 bool IsEmpty() const { return index_ == 0; } Add(int n)221 bool Add(int n) { 222 return index_ < kSize ? (comp_[index_++] = n, true) : false; 223 } SetNamedMonth(int n)224 void SetNamedMonth(int n) { named_month_ = n; } 225 bool Write(FixedArray* output); 226 private: IsMonth(int x)227 static bool IsMonth(int x) { return Between(x, 1, 12); } IsDay(int x)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_ 241