| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| 11 // with the distribution. | 11 // with the distribution. |
| 12 // * Neither the name of Google Inc. nor the names of its | 12 // * Neither the name of Google Inc. nor the names of its |
| 13 // contributors may be used to endorse or promote products derived | 13 // contributors may be used to endorse or promote products derived |
| 14 // from this software without specific prior written permission. | 14 // from this software without specific prior written permission. |
| 15 // | 15 // |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include <stdarg.h> | 28 #include <stdarg.h> |
| 29 #include <limits.h> | |
| 30 | 29 |
| 31 #include "v8.h" | 30 #include "v8.h" |
| 32 | 31 |
| 33 #include "conversions-inl.h" | 32 #include "conversions-inl.h" |
| 34 #include "factory.h" | 33 #include "factory.h" |
| 35 #include "fast-dtoa.h" | 34 #include "fast-dtoa.h" |
| 36 #include "scanner.h" | 35 #include "scanner.h" |
| 37 | 36 |
| 38 namespace v8 { | 37 namespace v8 { |
| 39 namespace internal { | 38 namespace internal { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 result[i - index] = static_cast<char>(c); | 85 result[i - index] = static_cast<char>(c); |
| 87 } else { | 86 } else { |
| 88 result[i - index] = 127; // Force number parsing to fail. | 87 result[i - index] = 127; // Force number parsing to fail. |
| 89 } | 88 } |
| 90 } | 89 } |
| 91 result[length - index] = '\0'; | 90 result[length - index] = '\0'; |
| 92 return result; | 91 return result; |
| 93 } | 92 } |
| 94 | 93 |
| 95 | 94 |
| 96 namespace { | |
| 97 | |
| 98 // C++-style iterator adaptor for StringInputBuffer | |
| 99 // (unlike C++ iterators the end-marker has different type). | |
| 100 class StringInputBufferIterator { | |
| 101 public: | |
| 102 class EndMarker {}; | |
| 103 | |
| 104 explicit StringInputBufferIterator(StringInputBuffer* buffer); | |
| 105 | |
| 106 int operator*() const; | |
| 107 void operator++(); | |
| 108 bool operator==(EndMarker const&) const { return end_; } | |
| 109 bool operator!=(EndMarker const& m) const { return !end_; } | |
| 110 | |
| 111 private: | |
| 112 StringInputBuffer* const buffer_; | |
| 113 int current_; | |
| 114 bool end_; | |
| 115 }; | |
| 116 | |
| 117 | |
| 118 StringInputBufferIterator::StringInputBufferIterator( | |
| 119 StringInputBuffer* buffer) : buffer_(buffer) { | |
| 120 ++(*this); | |
| 121 } | |
| 122 | |
| 123 int StringInputBufferIterator::operator*() const { | |
| 124 return current_; | |
| 125 } | |
| 126 | |
| 127 | |
| 128 void StringInputBufferIterator::operator++() { | |
| 129 end_ = !buffer_->has_more(); | |
| 130 if (!end_) { | |
| 131 current_ = buffer_->GetNext(); | |
| 132 } | |
| 133 } | |
| 134 } | |
| 135 | |
| 136 | |
| 137 static inline void ReleaseCString(const char* original, const char* str) { | 95 static inline void ReleaseCString(const char* original, const char* str) { |
| 138 } | 96 } |
| 139 | 97 |
| 140 | 98 |
| 141 static inline void ReleaseCString(String* original, const char* str) { | 99 static inline void ReleaseCString(String* original, const char* str) { |
| 142 DeleteArray(const_cast<char *>(str)); | 100 DeleteArray(const_cast<char *>(str)); |
| 143 } | 101 } |
| 144 | 102 |
| 145 | 103 |
| 146 template <class Iterator, class EndMark> | 104 static inline bool IsSpace(const char* str, int index) { |
| 147 static bool SubStringEquals(Iterator* current, | 105 ASSERT(index >= 0 && index < StrLength(str)); |
| 148 EndMark end, | 106 return Scanner::kIsWhiteSpace.get(str[index]); |
| 149 const char* substring) { | 107 } |
| 150 ASSERT(**current == *substring); | 108 |
| 151 for (substring++; *substring != '\0'; substring++) { | 109 |
| 152 ++*current; | 110 static inline bool IsSpace(String* str, int index) { |
| 153 if (*current == end || **current != *substring) return false; | 111 return Scanner::kIsWhiteSpace.get(str->Get(index)); |
| 112 } |
| 113 |
| 114 |
| 115 static inline bool SubStringEquals(const char* str, |
| 116 int index, |
| 117 const char* other) { |
| 118 return strncmp(str + index, other, strlen(other)) != 0; |
| 119 } |
| 120 |
| 121 |
| 122 static inline bool SubStringEquals(String* str, int index, const char* other) { |
| 123 HandleScope scope; |
| 124 int str_length = str->length(); |
| 125 int other_length = StrLength(other); |
| 126 int end = index + other_length < str_length ? |
| 127 index + other_length : |
| 128 str_length; |
| 129 Handle<String> substring = |
| 130 Factory::NewSubString(Handle<String>(str), index, end); |
| 131 return substring->IsEqualTo(Vector<const char>(other, other_length)); |
| 132 } |
| 133 |
| 134 |
| 135 // Check if a string should be parsed as an octal number. The string |
| 136 // can be either a char* or a String*. |
| 137 template<class S> |
| 138 static bool ShouldParseOctal(S* s, int i) { |
| 139 int index = i; |
| 140 int len = GetLength(s); |
| 141 if (index < len && GetChar(s, index) != '0') return false; |
| 142 |
| 143 // If the first real character (following '0') is not an octal |
| 144 // digit, bail out early. This also takes care of numbers of the |
| 145 // forms 0.xxx and 0exxx by not allowing the first 0 to be |
| 146 // interpreted as an octal. |
| 147 index++; |
| 148 if (index < len) { |
| 149 int d = GetChar(s, index) - '0'; |
| 150 if (d < 0 || d > 7) return false; |
| 151 } else { |
| 152 return false; |
| 154 } | 153 } |
| 155 ++*current; | 154 |
| 155 // Traverse all digits (including the first). If there is an octal |
| 156 // prefix which is not a part of a longer decimal prefix, we return |
| 157 // true. Otherwise, false is returned. |
| 158 while (index < len) { |
| 159 int d = GetChar(s, index++) - '0'; |
| 160 if (d == 8 || d == 9) return false; |
| 161 if (d < 0 || d > 7) return true; |
| 162 } |
| 156 return true; | 163 return true; |
| 157 } | 164 } |
| 158 | 165 |
| 159 | 166 |
| 160 extern "C" double gay_strtod(const char* s00, const char** se); | 167 extern "C" double gay_strtod(const char* s00, const char** se); |
| 161 | 168 |
| 162 | 169 |
| 163 // Parse an int from a string starting a given index and in a given | 170 // Parse an int from a string starting a given index and in a given |
| 164 // radix. The string can be either a char* or a String*. | 171 // radix. The string can be either a char* or a String*. |
| 165 template <class S> | 172 template <class S> |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 248 | 255 |
| 249 | 256 |
| 250 int StringToInt(const char* str, int index, int radix, double* value) { | 257 int StringToInt(const char* str, int index, int radix, double* value) { |
| 251 return InternalStringToInt(const_cast<char*>(str), index, radix, value); | 258 return InternalStringToInt(const_cast<char*>(str), index, radix, value); |
| 252 } | 259 } |
| 253 | 260 |
| 254 | 261 |
| 255 static const double JUNK_STRING_VALUE = OS::nan_value(); | 262 static const double JUNK_STRING_VALUE = OS::nan_value(); |
| 256 | 263 |
| 257 | 264 |
| 258 // Returns true if a nonspace found and false if the end has reached. | 265 // Convert a string to a double value. The string can be either a |
| 259 template <class Iterator, class EndMark> | 266 // char* or a String*. |
| 260 static inline bool AdvanceToNonspace(Iterator* current, EndMark end) { | 267 template<class S> |
| 261 while (*current != end) { | 268 static double InternalStringToDouble(S* str, |
| 262 if (!Scanner::kIsWhiteSpace.get(**current)) return true; | 269 int flags, |
| 263 ++*current; | 270 double empty_string_val) { |
| 271 double result = 0.0; |
| 272 int index = 0; |
| 273 |
| 274 int len = GetLength(str); |
| 275 |
| 276 // Skip leading spaces. |
| 277 while ((index < len) && IsSpace(str, index)) index++; |
| 278 |
| 279 // Is the string empty? |
| 280 if (index >= len) return empty_string_val; |
| 281 |
| 282 // Get the first character. |
| 283 uint16_t first = GetChar(str, index); |
| 284 |
| 285 // Numbers can only start with '-', '+', '.', 'I' (Infinity), or a digit. |
| 286 if (first != '-' && first != '+' && first != '.' && first != 'I' && |
| 287 (first > '9' || first < '0')) { |
| 288 return JUNK_STRING_VALUE; |
| 264 } | 289 } |
| 265 return false; | 290 |
| 291 // Compute sign of result based on first character. |
| 292 int sign = 1; |
| 293 if (first == '-') { |
| 294 sign = -1; |
| 295 index++; |
| 296 // String only containing a '-' are junk chars. |
| 297 if (index == len) return JUNK_STRING_VALUE; |
| 298 } |
| 299 |
| 300 // do we have a hex number? |
| 301 // (since the string is 0-terminated, it's ok to look one char beyond the end) |
| 302 if ((flags & ALLOW_HEX) != 0 && |
| 303 (index + 1) < len && |
| 304 GetChar(str, index) == '0' && |
| 305 (GetChar(str, index + 1) == 'x' || GetChar(str, index + 1) == 'X')) { |
| 306 index += 2; |
| 307 index = StringToInt(str, index, 16, &result); |
| 308 } else if ((flags & ALLOW_OCTALS) != 0 && ShouldParseOctal(str, index)) { |
| 309 // NOTE: We optimistically try to parse the number as an octal (if |
| 310 // we're allowed to), even though this is not as dictated by |
| 311 // ECMA-262. The reason for doing this is compatibility with IE and |
| 312 // Firefox. |
| 313 index = StringToInt(str, index, 8, &result); |
| 314 } else { |
| 315 const char* cstr = GetCString(str, index); |
| 316 const char* end; |
| 317 // Optimistically parse the number and then, if that fails, |
| 318 // check if it might have been {+,-,}Infinity. |
| 319 result = gay_strtod(cstr, &end); |
| 320 ReleaseCString(str, cstr); |
| 321 if (result != 0.0 || end != cstr) { |
| 322 // It appears that strtod worked |
| 323 index += static_cast<int>(end - cstr); |
| 324 } else { |
| 325 // Check for {+,-,}Infinity |
| 326 bool is_negative = (GetChar(str, index) == '-'); |
| 327 if (GetChar(str, index) == '+' || GetChar(str, index) == '-') |
| 328 index++; |
| 329 if (!SubStringEquals(str, index, "Infinity")) |
| 330 return JUNK_STRING_VALUE; |
| 331 result = is_negative ? -V8_INFINITY : V8_INFINITY; |
| 332 index += 8; |
| 333 } |
| 334 } |
| 335 |
| 336 if ((flags & ALLOW_TRAILING_JUNK) == 0) { |
| 337 // skip trailing spaces |
| 338 while ((index < len) && IsSpace(str, index)) index++; |
| 339 // string ending with junk? |
| 340 if (index < len) return JUNK_STRING_VALUE; |
| 341 } |
| 342 |
| 343 return sign * result; |
| 266 } | 344 } |
| 267 | 345 |
| 268 | 346 |
| 269 template <class Iterator, class EndMark> | |
| 270 static double InternalHexidecimalStringToDouble(Iterator current, | |
| 271 EndMark end, | |
| 272 char* buffer, | |
| 273 bool allow_trailing_junk) { | |
| 274 ASSERT(current != end); | |
| 275 // We reuse the buffer of InternalStringToDouble. Since hexidecimal | |
| 276 // numbers may have much less digits than decimal the buffer won't overflow. | |
| 277 int significant_digits = 0; | |
| 278 int insignificant_digits = 0; | |
| 279 bool leading_zero = false; | |
| 280 // Hexidecomal may have (52) / 4 + 1 significant digit. Mean of 2 | |
| 281 // hexidecimal may have n + 1. | |
| 282 const int max_significant_digits = (52) / 4 + 2; | |
| 283 int buffer_pos = 0; | |
| 284 bool nonzero_digit_dropped = false; | |
| 285 | |
| 286 // Skip leading 0s. | |
| 287 while (*current == '0') { | |
| 288 leading_zero = true; | |
| 289 ++current; | |
| 290 if (current == end) return 0; | |
| 291 } | |
| 292 | |
| 293 int begin_pos = buffer_pos; | |
| 294 while ((*current >= '0' && *current <= '9') | |
| 295 || (*current >= 'a' && *current <= 'f') | |
| 296 || (*current >= 'A' && *current <= 'F')) { | |
| 297 if (significant_digits <= max_significant_digits) { | |
| 298 buffer[buffer_pos++] = static_cast<char>(*current); | |
| 299 significant_digits++; | |
| 300 } else { | |
| 301 insignificant_digits++; | |
| 302 nonzero_digit_dropped = nonzero_digit_dropped || *current != '0'; | |
| 303 } | |
| 304 ++current; | |
| 305 if (current == end) break; | |
| 306 } | |
| 307 | |
| 308 if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) { | |
| 309 return JUNK_STRING_VALUE; | |
| 310 } | |
| 311 | |
| 312 if (significant_digits == 0) { | |
| 313 return leading_zero ? 0 : JUNK_STRING_VALUE; | |
| 314 } | |
| 315 | |
| 316 if (nonzero_digit_dropped) { | |
| 317 ASSERT(insignificant_digits > 0); | |
| 318 insignificant_digits--; | |
| 319 buffer[buffer_pos++] = '1'; | |
| 320 } | |
| 321 | |
| 322 buffer[buffer_pos] = '\0'; | |
| 323 | |
| 324 double result; | |
| 325 StringToInt(buffer, begin_pos, 16, &result); | |
| 326 if (insignificant_digits > 0) { | |
| 327 // Multiplying by power of 2 doesn't cause a loss of precision. | |
| 328 result *= pow(16.0, insignificant_digits); | |
| 329 } | |
| 330 return result; | |
| 331 } | |
| 332 | |
| 333 | |
| 334 // Converts a string to a double value. Assumes the Iterator supports | |
| 335 // the following operations: | |
| 336 // 1. current == end (other ops are not allowed), current != end. | |
| 337 // 2. *current - gets the current character in the sequence. | |
| 338 // 3. ++current (advances the position). | |
| 339 template <class Iterator, class EndMark> | |
| 340 static double InternalStringToDouble(Iterator current, | |
| 341 EndMark end, | |
| 342 int flags, | |
| 343 double empty_string_val) { | |
| 344 // To make sure that iterator unreferencing is valid the following | |
| 345 // convention is used: | |
| 346 // 1. Each '++current' statement is followed by check for equality to 'end'. | |
| 347 // 2. If AdvanceToNonspace returned false then current == end. | |
| 348 // 3. If 'current' becomes be equal to 'end' the function returns or goes to | |
| 349 // 'parsing_done'. | |
| 350 // 4. 'current' is not unreferenced after the 'parsing_done' label. | |
| 351 // 5. Code before 'parsing_done' may rely on 'current != end'. | |
| 352 if (!AdvanceToNonspace(¤t, end)) return empty_string_val; | |
| 353 | |
| 354 const bool allow_trailing_junk = (flags & ALLOW_TRAILING_JUNK) != 0; | |
| 355 | |
| 356 // Insignificant digits will be removed. | |
| 357 const int max_significant_digits = 772; | |
| 358 // The longest form of simplified number is: "-<significant digits>'.1eXXX\0". | |
| 359 const int buffer_size = max_significant_digits + 10; | |
| 360 char buffer[buffer_size]; // NOLINT: size is known at compile time. | |
| 361 int buffer_pos = 0; | |
| 362 | |
| 363 // Exponent will be adjusted if insignificant digits of the integer part | |
| 364 // or insignificant leading zeros of the fractional part are dropped. | |
| 365 int exponent = 0; | |
| 366 int significant_digits = 0; | |
| 367 int insignificant_digits = 0; | |
| 368 bool nonzero_digit_dropped = false; | |
| 369 | |
| 370 double signed_zero = 0.0; | |
| 371 | |
| 372 if (*current == '+') { | |
| 373 // Ignore leading sign; Skip following spaces. | |
| 374 ++current; | |
| 375 if (!AdvanceToNonspace(¤t, end)) return JUNK_STRING_VALUE; | |
| 376 } else if (*current == '-') { | |
| 377 buffer[buffer_pos++] = '-'; | |
| 378 ++current; | |
| 379 if (!AdvanceToNonspace(¤t, end)) return JUNK_STRING_VALUE; | |
| 380 signed_zero = -0.0; | |
| 381 } | |
| 382 | |
| 383 static const char infinity_symbol[] = "Infinity"; | |
| 384 if (*current == infinity_symbol[0]) { | |
| 385 if (!SubStringEquals(¤t, end, infinity_symbol)) { | |
| 386 return JUNK_STRING_VALUE; | |
| 387 } | |
| 388 | |
| 389 if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) { | |
| 390 return JUNK_STRING_VALUE; | |
| 391 } | |
| 392 | |
| 393 return (buffer_pos > 0 && buffer[0] == '-') ? -V8_INFINITY : V8_INFINITY; | |
| 394 } | |
| 395 | |
| 396 bool leading_zero = false; | |
| 397 if (*current == '0') { | |
| 398 ++current; | |
| 399 if (current == end) return signed_zero; | |
| 400 | |
| 401 leading_zero = true; | |
| 402 | |
| 403 // It could be hexadecimal value. | |
| 404 if ((flags & ALLOW_HEX) && (*current == 'x' || *current == 'X')) { | |
| 405 ++current; | |
| 406 if (current == end) return JUNK_STRING_VALUE; // "0x". | |
| 407 | |
| 408 double result = InternalHexidecimalStringToDouble(current, | |
| 409 end, | |
| 410 buffer + buffer_pos, | |
| 411 allow_trailing_junk); | |
| 412 return (buffer_pos > 0 && buffer[0] == '-') ? -result : result; | |
| 413 } | |
| 414 | |
| 415 // Ignore leading zeros in the integer part. | |
| 416 while (*current == '0') { | |
| 417 ++current; | |
| 418 if (current == end) return signed_zero; | |
| 419 } | |
| 420 } | |
| 421 | |
| 422 bool octal = leading_zero && (flags & ALLOW_OCTALS) != 0; | |
| 423 | |
| 424 // Copy significant digits of the integer part (if any) to the buffer. | |
| 425 while (*current >= '0' && *current <= '9') { | |
| 426 if (significant_digits < max_significant_digits) { | |
| 427 ASSERT(buffer_pos < buffer_size); | |
| 428 buffer[buffer_pos++] = static_cast<char>(*current); | |
| 429 significant_digits++; | |
| 430 // Will later check if it's an octal in the buffer. | |
| 431 } else { | |
| 432 insignificant_digits++; // Move the digit into the exponential part. | |
| 433 nonzero_digit_dropped = nonzero_digit_dropped || *current != '0'; | |
| 434 } | |
| 435 octal = octal && *current < '8'; | |
| 436 ++current; | |
| 437 if (current == end) goto parsing_done; | |
| 438 } | |
| 439 | |
| 440 if (*current == '.') { | |
| 441 ASSERT(buffer_pos < buffer_size); | |
| 442 ++current; | |
| 443 if (current == end) { | |
| 444 if (significant_digits == 0 && !leading_zero) { | |
| 445 return JUNK_STRING_VALUE; | |
| 446 } else { | |
| 447 goto parsing_done; | |
| 448 } | |
| 449 } | |
| 450 buffer[buffer_pos++] = '.'; | |
| 451 | |
| 452 if (significant_digits == 0) { | |
| 453 octal = false; | |
| 454 // Integer part consists of 0 or is absent. Significant digits start after | |
| 455 // leading zeros (if any). | |
| 456 while (*current == '0') { | |
| 457 ++current; | |
| 458 if (current == end) return signed_zero; | |
| 459 exponent--; // Move this 0 into the exponent. | |
| 460 } | |
| 461 } | |
| 462 | |
| 463 // There is the fractional part. | |
| 464 while (*current >= '0' && *current <= '9') { | |
| 465 if (significant_digits < max_significant_digits) { | |
| 466 ASSERT(buffer_pos < buffer_size); | |
| 467 buffer[buffer_pos++] = static_cast<char>(*current); | |
| 468 significant_digits++; | |
| 469 } else { | |
| 470 // Ignore insignificant digits in the fractional part. | |
| 471 nonzero_digit_dropped = nonzero_digit_dropped || *current != '0'; | |
| 472 } | |
| 473 ++current; | |
| 474 if (current == end) goto parsing_done; | |
| 475 } | |
| 476 } | |
| 477 | |
| 478 if (!leading_zero && exponent == 0 && significant_digits == 0) { | |
| 479 // If leading_zeros is true then the string contains zeros. | |
| 480 // If exponent < 0 then string was [+-]\.0*... | |
| 481 // If significant_digits != 0 the string is not equal to 0. | |
| 482 // Otherwise there is no digits in the string. | |
| 483 return JUNK_STRING_VALUE; | |
| 484 } | |
| 485 | |
| 486 // Parse exponential part. | |
| 487 if (*current == 'e' || *current == 'E') { | |
| 488 if (octal) return JUNK_STRING_VALUE; | |
| 489 ++current; | |
| 490 if (current == end) { | |
| 491 if (allow_trailing_junk) { | |
| 492 goto parsing_done; | |
| 493 } else { | |
| 494 return JUNK_STRING_VALUE; | |
| 495 } | |
| 496 } | |
| 497 char sign = '+'; | |
| 498 if (*current == '+' || *current == '-') { | |
| 499 sign = static_cast<char>(*current); | |
| 500 ++current; | |
| 501 if (current == end) { | |
| 502 if (allow_trailing_junk) { | |
| 503 goto parsing_done; | |
| 504 } else { | |
| 505 return JUNK_STRING_VALUE; | |
| 506 } | |
| 507 } | |
| 508 } | |
| 509 | |
| 510 if (current == end || *current < '0' || *current > '9') { | |
| 511 if (allow_trailing_junk) { | |
| 512 goto parsing_done; | |
| 513 } else { | |
| 514 return JUNK_STRING_VALUE; | |
| 515 } | |
| 516 } | |
| 517 | |
| 518 const int max_exponent = INT_MAX / 2; | |
| 519 ASSERT(-max_exponent / 2 <= exponent && exponent <= max_exponent / 2); | |
| 520 int num = 0; | |
| 521 do { | |
| 522 // Check overflow. | |
| 523 int digit = *current - '0'; | |
| 524 if (num >= max_exponent / 10 | |
| 525 && !(num == max_exponent / 10 && digit <= max_exponent % 10)) { | |
| 526 num = max_exponent; | |
| 527 } else { | |
| 528 num = num * 10 + digit; | |
| 529 } | |
| 530 ++current; | |
| 531 } while (current != end && *current >= '0' && *current <= '9'); | |
| 532 | |
| 533 exponent += (sign == '-' ? -num : num); | |
| 534 } | |
| 535 | |
| 536 if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) { | |
| 537 return JUNK_STRING_VALUE; | |
| 538 } | |
| 539 | |
| 540 parsing_done: | |
| 541 exponent += insignificant_digits; | |
| 542 | |
| 543 if (octal) { | |
| 544 buffer[buffer_pos] = '\0'; | |
| 545 // ALLOW_OCTALS has set and there is no '8' and '9' in insignificant | |
| 546 // digits. Check significant digits now. | |
| 547 char sign = '+'; | |
| 548 const char* s = buffer; | |
| 549 if (*s == '-' || *s == '+') sign = *s++; | |
| 550 | |
| 551 double result; | |
| 552 s += StringToInt(s, 0, 8, &result); | |
| 553 if (!allow_trailing_junk && *s != '\0') return JUNK_STRING_VALUE; | |
| 554 | |
| 555 if (sign == '-') result = -result; | |
| 556 if (insignificant_digits > 0) { | |
| 557 result *= pow(8.0, insignificant_digits); | |
| 558 } | |
| 559 return result; | |
| 560 } | |
| 561 | |
| 562 if (nonzero_digit_dropped) { | |
| 563 if (insignificant_digits > 0) buffer[buffer_pos++] = '.'; | |
| 564 buffer[buffer_pos++] = '1'; | |
| 565 } | |
| 566 | |
| 567 if (exponent != 0) { | |
| 568 ASSERT(buffer_pos < buffer_size); | |
| 569 buffer[buffer_pos++] = 'e'; | |
| 570 if (exponent < 0) { | |
| 571 ASSERT(buffer_pos < buffer_size); | |
| 572 buffer[buffer_pos++] = '-'; | |
| 573 exponent = -exponent; | |
| 574 } | |
| 575 if (exponent > 999) exponent = 999; // Result will be Infinity or 0 or -0. | |
| 576 | |
| 577 const int exp_digits = 3; | |
| 578 for (int i = 0; i < exp_digits; i++) { | |
| 579 buffer[buffer_pos + exp_digits - 1 - i] = '0' + exponent % 10; | |
| 580 exponent /= 10; | |
| 581 } | |
| 582 ASSERT(exponent == 0); | |
| 583 buffer_pos += exp_digits; | |
| 584 } | |
| 585 | |
| 586 ASSERT(buffer_pos < buffer_size); | |
| 587 buffer[buffer_pos] = '\0'; | |
| 588 | |
| 589 return gay_strtod(buffer, NULL); | |
| 590 } | |
| 591 | |
| 592 double StringToDouble(String* str, int flags, double empty_string_val) { | 347 double StringToDouble(String* str, int flags, double empty_string_val) { |
| 593 StringShape shape(str); | 348 return InternalStringToDouble(str, flags, empty_string_val); |
| 594 if (shape.IsSequentialAscii()) { | |
| 595 const char* begin = SeqAsciiString::cast(str)->GetChars(); | |
| 596 const char* end = begin + str->length(); | |
| 597 return InternalStringToDouble(begin, end, flags, empty_string_val); | |
| 598 } else if (shape.IsSequentialTwoByte()) { | |
| 599 const uc16* begin = SeqTwoByteString::cast(str)->GetChars(); | |
| 600 const uc16* end = begin + str->length(); | |
| 601 return InternalStringToDouble(begin, end, flags, empty_string_val); | |
| 602 } else { | |
| 603 StringInputBuffer buffer(str); | |
| 604 return InternalStringToDouble(StringInputBufferIterator(&buffer), | |
| 605 StringInputBufferIterator::EndMarker(), | |
| 606 flags, | |
| 607 empty_string_val); | |
| 608 } | |
| 609 } | 349 } |
| 610 | 350 |
| 611 | 351 |
| 612 double StringToDouble(const char* str, int flags, double empty_string_val) { | 352 double StringToDouble(const char* str, int flags, double empty_string_val) { |
| 613 const char* end = str + StrLength(str); | 353 return InternalStringToDouble(str, flags, empty_string_val); |
| 614 | |
| 615 return InternalStringToDouble(str, end, flags, empty_string_val); | |
| 616 } | 354 } |
| 617 | 355 |
| 618 | 356 |
| 619 extern "C" char* dtoa(double d, int mode, int ndigits, | 357 extern "C" char* dtoa(double d, int mode, int ndigits, |
| 620 int* decpt, int* sign, char** rve); | 358 int* decpt, int* sign, char** rve); |
| 621 | 359 |
| 622 extern "C" void freedtoa(char* s); | 360 extern "C" void freedtoa(char* s); |
| 623 | 361 |
| 624 const char* DoubleToCString(double v, Vector<char> buffer) { | 362 const char* DoubleToCString(double v, Vector<char> buffer) { |
| 625 StringBuilder builder(buffer.start(), buffer.length()); | 363 StringBuilder builder(buffer.start(), buffer.length()); |
| (...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 972 // Allocate result and fill in the parts. | 710 // Allocate result and fill in the parts. |
| 973 StringBuilder builder(result_size + 1); | 711 StringBuilder builder(result_size + 1); |
| 974 builder.AddSubstring(integer_buffer + integer_pos + 1, integer_part_size); | 712 builder.AddSubstring(integer_buffer + integer_pos + 1, integer_part_size); |
| 975 if (decimal_pos > 0) builder.AddCharacter('.'); | 713 if (decimal_pos > 0) builder.AddCharacter('.'); |
| 976 builder.AddSubstring(decimal_buffer, decimal_pos); | 714 builder.AddSubstring(decimal_buffer, decimal_pos); |
| 977 return builder.Finalize(); | 715 return builder.Finalize(); |
| 978 } | 716 } |
| 979 | 717 |
| 980 | 718 |
| 981 } } // namespace v8::internal | 719 } } // namespace v8::internal |
| OLD | NEW |