| Index: src/scanner.cc
|
| ===================================================================
|
| --- src/scanner.cc (revision 6629)
|
| +++ src/scanner.cc (working copy)
|
| @@ -25,11 +25,13 @@
|
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
| +#include <limits.h>
|
| #include "v8.h"
|
|
|
| #include "ast.h"
|
| #include "handles.h"
|
| #include "scanner.h"
|
| +#include "strtod.h"
|
| #include "unicode-inl.h"
|
|
|
| namespace v8 {
|
| @@ -420,6 +422,10 @@
|
| token = ScanJsonString();
|
| break;
|
| case '-':
|
| + Advance();
|
| + token = ScanJsonNumber();
|
| + number = -number;
|
| + break;
|
| case '0':
|
| case '1':
|
| case '2':
|
| @@ -515,35 +521,108 @@
|
|
|
|
|
| Token::Value JsonScanner::ScanJsonNumber() {
|
| - LiteralScope literal(this);
|
| - if (c0_ == '-') AddLiteralCharAdvance();
|
| + // Maximum number of significant digits in decimal representation.
|
| + // The longest possible double in decimal representation is
|
| + // (2^53 - 1) * 2 ^ -1074 that is (2 ^ 53 - 1) * 5 ^ 1074 / 10 ^ 1074
|
| + // (768 digits). If we parse a number whose first digits are equal to a
|
| + // mean of 2 adjacent doubles (that could have up to 769 digits) the result
|
| + // must be rounded to the bigger one unless the tail consists of zeros, so
|
| + // we don't need to preserve all the digits.
|
| + const int kMaxSignificantDigits = 772;
|
| + // The longest form of simplified number is: "-<significant digits>'.1eXXX\0".
|
| + const int kBufferSize = kMaxSignificantDigits + 10;
|
| + char buffer[kBufferSize]; // NOLINT: size is known at compile time.
|
| + int buffer_pos = 0;
|
| +
|
| + // Exponent will be adjusted if insignificant digits of the integer part
|
| + // or insignificant leading zeros of the fractional part are dropped.
|
| + int exponent = 0;
|
| + int significant_digits = 0;
|
| + int insignificant_digits = 0;
|
| + int i = 0;
|
| + bool nonzero_digit_dropped = false;
|
| if (c0_ == '0') {
|
| - AddLiteralCharAdvance();
|
| + Advance();
|
| // Prefix zero is only allowed if it's the only digit before
|
| // a decimal point or exponent.
|
| if ('0' <= c0_ && c0_ <= '9') return Token::ILLEGAL;
|
| } else {
|
| if (c0_ < '1' || c0_ > '9') return Token::ILLEGAL;
|
| do {
|
| - AddLiteralCharAdvance();
|
| + if (significant_digits < kMaxSignificantDigits) {
|
| + ASSERT(buffer_pos < kBufferSize);
|
| + buffer[buffer_pos++] = static_cast<char>(c0_);
|
| + significant_digits++;
|
| + i = i * 10 + c0_ - '0';
|
| + } else {
|
| + insignificant_digits++; // Move the digit into the exponential part.
|
| + nonzero_digit_dropped = nonzero_digit_dropped || c0_ != '0';
|
| + }
|
| + Advance();
|
| } while (c0_ >= '0' && c0_ <= '9');
|
| + if (c0_ != '.' && c0_ != 'e' && c0_ != 'E' && significant_digits < 10) {
|
| + number = i;
|
| + return Token::NUMBER;
|
| + }
|
| }
|
| if (c0_ == '.') {
|
| - AddLiteralCharAdvance();
|
| + Advance();
|
| if (c0_ < '0' || c0_ > '9') return Token::ILLEGAL;
|
| + if (significant_digits == 0) {
|
| + // Integer part consists of 0.
|
| + // Significant digits start after leading zero(s).
|
| + while (c0_ == '0') {
|
| + Advance();
|
| + exponent--; // Move this 0 into the exponent.
|
| + }
|
| + if (c0_ < '0' || c0_ > '9') {
|
| + number = 0.0;
|
| + return Token::NUMBER;
|
| + }
|
| + }
|
| do {
|
| - AddLiteralCharAdvance();
|
| + if (significant_digits < kMaxSignificantDigits) {
|
| + ASSERT(buffer_pos < kBufferSize);
|
| + buffer[buffer_pos++] = static_cast<char>(c0_);
|
| + significant_digits++;
|
| + exponent--;
|
| + } else {
|
| + // Ignore insignificant digits in the fractional part.
|
| + nonzero_digit_dropped = nonzero_digit_dropped || c0_ != '0';
|
| + }
|
| + Advance();
|
| } while (c0_ >= '0' && c0_ <= '9');
|
| }
|
| - if (AsciiAlphaToLower(c0_) == 'e') {
|
| - AddLiteralCharAdvance();
|
| - if (c0_ == '-' || c0_ == '+') AddLiteralCharAdvance();
|
| + if (c0_ == 'e' || c0_ == 'E') {
|
| + Advance();
|
| + bool expsign = (c0_ == '-');
|
| + if (expsign || c0_ == '+') Advance();
|
| if (c0_ < '0' || c0_ > '9') return Token::ILLEGAL;
|
| + const int max_exponent = INT_MAX / 2;
|
| + ASSERT(-max_exponent / 2 <= exponent && exponent <= max_exponent / 2);
|
| + int num = 0;
|
| do {
|
| - AddLiteralCharAdvance();
|
| + // Check overflow.
|
| + int digit = c0_ - '0';
|
| + if (num >= max_exponent / 10
|
| + && !(num == max_exponent / 10 && digit <= max_exponent % 10)) {
|
| + num = max_exponent;
|
| + } else {
|
| + num = num * 10 + digit;
|
| + }
|
| + Advance();
|
| } while (c0_ >= '0' && c0_ <= '9');
|
| + exponent += (expsign ? -num : num);
|
| }
|
| - literal.Complete();
|
| +
|
| + exponent += insignificant_digits;
|
| + if (nonzero_digit_dropped) {
|
| + buffer[buffer_pos++] = '1';
|
| + exponent--;
|
| + }
|
| + ASSERT(buffer_pos < kBufferSize);
|
| + buffer[buffer_pos] = '\0';
|
| + number = Strtod(Vector<const char>(buffer, buffer_pos), exponent);
|
| return Token::NUMBER;
|
| }
|
|
|
|
|