00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <stdarg.h>
00029
00030 #include "v8.h"
00031
00032 #include "conversions-inl.h"
00033 #include "factory.h"
00034 #include "scanner.h"
00035
00036 namespace v8 { namespace internal {
00037
00038 int HexValue(uc32 c) {
00039 if ('0' <= c && c <= '9')
00040 return c - '0';
00041 if ('a' <= c && c <= 'f')
00042 return c - 'a' + 10;
00043 if ('A' <= c && c <= 'F')
00044 return c - 'A' + 10;
00045 return -1;
00046 }
00047
00048
00049
00050
00051 static inline int GetChar(const char* str, int index) {
00052 ASSERT(index >= 0 && index < static_cast<int>(strlen(str)));
00053 return str[index];
00054 }
00055
00056
00057 static inline int GetChar(String* str, int index) {
00058 return str->Get(index);
00059 }
00060
00061
00062 static inline int GetLength(const char* str) {
00063 return strlen(str);
00064 }
00065
00066
00067 static inline int GetLength(String* str) {
00068 return str->length();
00069 }
00070
00071
00072 static inline const char* GetCString(const char* str, int index) {
00073 return str + index;
00074 }
00075
00076
00077 static inline const char* GetCString(String* str, int index) {
00078 char* result = NewArray<char>(str->length() + 1);
00079 for (int i = index; i < str->length(); i++) {
00080 if (str->Get(i) <= 127) {
00081 result[i - index] = static_cast<char>(str->Get(i));
00082 } else {
00083 result[i - index] = 127;
00084 }
00085 }
00086 result[str->length() - index] = '\0';
00087 return result;
00088 }
00089
00090
00091 static inline void ReleaseCString(const char* original, const char* str) {
00092 }
00093
00094
00095 static inline void ReleaseCString(String* original, const char* str) {
00096 DeleteArray(const_cast<char *>(str));
00097 }
00098
00099
00100 static inline bool IsSpace(const char* str, int index) {
00101 ASSERT(index >= 0 && index < static_cast<int>(strlen(str)));
00102 return Scanner::kIsWhiteSpace.get(str[index]);
00103 }
00104
00105
00106 static inline bool IsSpace(String* str, int index) {
00107 return Scanner::kIsWhiteSpace.get(str->Get(index));
00108 }
00109
00110
00111 static inline bool SubStringEquals(const char* str,
00112 int index,
00113 const char* other) {
00114 return strncmp(str + index, other, strlen(other)) != 0;
00115 }
00116
00117
00118 static inline bool SubStringEquals(String* str, int index, const char* other) {
00119 HandleScope scope;
00120 int len = strlen(other);
00121 int end = index + len < str->length() ? index + len : str->length();
00122 Handle<String> slice =
00123 Factory::NewStringSlice(Handle<String>(str), index, end);
00124 return slice->IsEqualTo(Vector<const char>(other, len));
00125 }
00126
00127
00128
00129
00130 template<class S>
00131 static bool ShouldParseOctal(S* s, int i) {
00132 int index = i;
00133 int len = GetLength(s);
00134 if (index < len && GetChar(s, index) != '0') return false;
00135
00136
00137
00138
00139
00140 index++;
00141 if (index < len) {
00142 int d = GetChar(s, index) - '0';
00143 if (d < 0 || d > 7) return false;
00144 } else {
00145 return false;
00146 }
00147
00148
00149
00150
00151 while (index < len) {
00152 int d = GetChar(s, index++) - '0';
00153 if (d == 8 || d == 9) return false;
00154 if (d < 0 || d > 7) return true;
00155 }
00156 return true;
00157 }
00158
00159
00160 extern "C" double gay_strtod(const char* s00, const char** se);
00161
00162
00163
00164
00165 template <class S>
00166 static int InternalStringToInt(S* s, int i, int radix, double* value) {
00167 int len = GetLength(s);
00168
00169
00170 ASSERT(2 <= radix && radix <= 36);
00171 int lim_0 = '0' + (radix < 10 ? radix : 10);
00172 int lim_a = 'a' + (radix - 10);
00173 int lim_A = 'A' + (radix - 10);
00174
00175
00176
00177
00178
00179 double v = 0.0;
00180 int j;
00181 for (j = i; j < len;) {
00182
00183
00184
00185 uint32_t part = 0, multiplier = 1;
00186 int k;
00187 for (k = j; k < len; k++) {
00188 int c = GetChar(s, k);
00189 if (c >= '0' && c < lim_0) {
00190 c = c - '0';
00191 } else if (c >= 'a' && c < lim_a) {
00192 c = c - 'a' + 10;
00193 } else if (c >= 'A' && c < lim_A) {
00194 c = c - 'A' + 10;
00195 } else {
00196 break;
00197 }
00198
00199
00200
00201
00202
00203 static const uint32_t kMaximumMultiplier = 0xffffffffU / 36;
00204 uint32_t m = multiplier * radix;
00205 if (m > kMaximumMultiplier) break;
00206 part = part * radix + c;
00207 multiplier = m;
00208 ASSERT(multiplier > part);
00209 }
00210
00211
00212
00213 int digits = k - j;
00214 if (digits == 0) break;
00215
00216
00217 ASSERT(multiplier ==
00218 pow(static_cast<double>(radix), static_cast<double>(digits)));
00219 v = v * multiplier + part;
00220 j = k;
00221 }
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232 static const double kPreciseConversionLimit = 9007199254740992.0;
00233 if (radix == 10 && v > kPreciseConversionLimit) {
00234 const char* cstr = GetCString(s, i);
00235 const char* end;
00236 v = gay_strtod(cstr, &end);
00237 ReleaseCString(s, cstr);
00238 }
00239
00240 *value = v;
00241 return j;
00242 }
00243
00244
00245 int StringToInt(String* str, int index, int radix, double* value) {
00246 return InternalStringToInt(str, index, radix, value);
00247 }
00248
00249
00250 int StringToInt(const char* str, int index, int radix, double* value) {
00251 return InternalStringToInt(const_cast<char*>(str), index, radix, value);
00252 }
00253
00254
00255 static const double JUNK_STRING_VALUE = OS::nan_value();
00256
00257
00258
00259
00260 template<class S>
00261 static double InternalStringToDouble(S* str,
00262 int flags,
00263 double empty_string_val) {
00264 double result = 0.0;
00265 int index = 0;
00266
00267 int len = GetLength(str);
00268
00269
00270 while ((index < len) && IsSpace(str, index)) index++;
00271
00272
00273 if (index >= len) return empty_string_val;
00274
00275
00276 uint16_t first = GetChar(str, index);
00277
00278
00279 if (first != '-' && first != '+' && first != '.' && first != 'I' &&
00280 (first > '9' || first < '0')) {
00281 return JUNK_STRING_VALUE;
00282 }
00283
00284
00285 int sign = 1;
00286 if (first == '-') {
00287 sign = -1;
00288 index++;
00289
00290 if (index == len) return JUNK_STRING_VALUE;
00291 }
00292
00293
00294
00295 if ((flags & ALLOW_HEX) != 0 &&
00296 (index + 1) < len &&
00297 GetChar(str, index) == '0' &&
00298 (GetChar(str, index + 1) == 'x' || GetChar(str, index + 1) == 'X')) {
00299 index += 2;
00300 index = StringToInt(str, index, 16, &result);
00301 } else if ((flags & ALLOW_OCTALS) != 0 && ShouldParseOctal(str, index)) {
00302
00303
00304
00305
00306 index = StringToInt(str, index, 8, &result);
00307 } else {
00308 const char* cstr = GetCString(str, index);
00309 const char* end;
00310
00311
00312 result = gay_strtod(cstr, &end);
00313 ReleaseCString(str, cstr);
00314 if (result != 0.0 || end != cstr) {
00315
00316 index += end - cstr;
00317 } else {
00318
00319 bool is_negative = (GetChar(str, index) == '-');
00320 if (GetChar(str, index) == '+' || GetChar(str, index) == '-')
00321 index++;
00322 if (!SubStringEquals(str, index, "Infinity"))
00323 return JUNK_STRING_VALUE;
00324 result = is_negative ? -INFINITY : INFINITY;
00325 index += 8;
00326 }
00327 }
00328
00329 if ((flags & ALLOW_TRAILING_JUNK) == 0) {
00330
00331 while ((index < len) && IsSpace(str, index)) index++;
00332
00333 if (index < len) return JUNK_STRING_VALUE;
00334 }
00335
00336 return sign * result;
00337 }
00338
00339
00340 double StringToDouble(String* str, int flags, double empty_string_val) {
00341 return InternalStringToDouble(str, flags, empty_string_val);
00342 }
00343
00344
00345 double StringToDouble(const char* str, int flags, double empty_string_val) {
00346 return InternalStringToDouble(str, flags, empty_string_val);
00347 }
00348
00349
00350 extern "C" char* dtoa(double d, int mode, int ndigits,
00351 int* decpt, int* sign, char** rve);
00352
00353 extern "C" void freedtoa(char* s);
00354
00355 const char* DoubleToCString(double v, Vector<char> buffer) {
00356 StringBuilder builder(buffer.start(), buffer.length());
00357
00358 switch (fpclassify(v)) {
00359 case FP_NAN:
00360 builder.AddString("NaN");
00361 break;
00362
00363 case FP_INFINITE:
00364 if (v < 0.0) {
00365 builder.AddString("-Infinity");
00366 } else {
00367 builder.AddString("Infinity");
00368 }
00369 break;
00370
00371 case FP_ZERO:
00372 builder.AddCharacter('0');
00373 break;
00374
00375 default: {
00376 int decimal_point;
00377 int sign;
00378
00379 char* decimal_rep = dtoa(v, 0, 0, &decimal_point, &sign, NULL);
00380 int length = strlen(decimal_rep);
00381
00382 if (sign) builder.AddCharacter('-');
00383
00384 if (length <= decimal_point && decimal_point <= 21) {
00385
00386 builder.AddString(decimal_rep);
00387 builder.AddPadding('0', decimal_point - length);
00388
00389 } else if (0 < decimal_point && decimal_point <= 21) {
00390
00391 builder.AddSubstring(decimal_rep, decimal_point);
00392 builder.AddCharacter('.');
00393 builder.AddString(decimal_rep + decimal_point);
00394
00395 } else if (decimal_point <= 0 && decimal_point > -6) {
00396
00397 builder.AddString("0.");
00398 builder.AddPadding('0', -decimal_point);
00399 builder.AddString(decimal_rep);
00400
00401 } else {
00402
00403 builder.AddCharacter(decimal_rep[0]);
00404 if (length != 1) {
00405 builder.AddCharacter('.');
00406 builder.AddString(decimal_rep + 1);
00407 }
00408 builder.AddCharacter('e');
00409 builder.AddCharacter((decimal_point >= 0) ? '+' : '-');
00410 int exponent = decimal_point - 1;
00411 if (exponent < 0) exponent = -exponent;
00412 builder.AddFormatted("%d", exponent);
00413 }
00414
00415 freedtoa(decimal_rep);
00416 }
00417 }
00418 return builder.Finalize();
00419 }
00420
00421
00422 const char* IntToCString(int n, Vector<char> buffer) {
00423 bool negative = false;
00424 if (n < 0) {
00425
00426 if (n == kMinInt) return DoubleToCString(n, buffer);
00427 negative = true;
00428 n = -n;
00429 }
00430
00431 int i = buffer.length();
00432 buffer[--i] = '\0';
00433 do {
00434 buffer[--i] = '0' + (n % 10);
00435 n /= 10;
00436 } while (n);
00437 if (negative) buffer[--i] = '-';
00438 return buffer.start() + i;
00439 }
00440
00441
00442 char* DoubleToFixedCString(double value, int f) {
00443 ASSERT(f >= 0);
00444
00445 bool negative = false;
00446 double abs_value = value;
00447 if (value < 0) {
00448 abs_value = -value;
00449 negative = true;
00450 }
00451
00452 if (abs_value >= 1e21) {
00453 char arr[100];
00454 Vector<char> buffer(arr, ARRAY_SIZE(arr));
00455 return StrDup(DoubleToCString(value, buffer));
00456 }
00457
00458
00459 int decimal_point;
00460 int sign;
00461 char* decimal_rep = dtoa(abs_value, 3, f, &decimal_point, &sign, NULL);
00462 int decimal_rep_length = strlen(decimal_rep);
00463
00464
00465 int zero_prefix_length = 0;
00466 int zero_postfix_length = 0;
00467
00468 if (decimal_point <= 0) {
00469 zero_prefix_length = -decimal_point + 1;
00470 decimal_point = 1;
00471 }
00472
00473 if (zero_prefix_length + decimal_rep_length < decimal_point + f) {
00474 zero_postfix_length = decimal_point + f - decimal_rep_length -
00475 zero_prefix_length;
00476 }
00477
00478 unsigned rep_length =
00479 zero_prefix_length + decimal_rep_length + zero_postfix_length;
00480 StringBuilder rep_builder(rep_length + 1);
00481 rep_builder.AddPadding('0', zero_prefix_length);
00482 rep_builder.AddString(decimal_rep);
00483 rep_builder.AddPadding('0', zero_postfix_length);
00484 char* rep = rep_builder.Finalize();
00485 freedtoa(decimal_rep);
00486
00487
00488
00489 unsigned result_size = decimal_point + f + 2;
00490 StringBuilder builder(result_size + 1);
00491 if (negative) builder.AddCharacter('-');
00492 builder.AddSubstring(rep, decimal_point);
00493 if (f > 0) {
00494 builder.AddCharacter('.');
00495 builder.AddSubstring(rep + decimal_point, f);
00496 }
00497 DeleteArray(rep);
00498 return builder.Finalize();
00499 }
00500
00501
00502 static char* CreateExponentialRepresentation(char* decimal_rep,
00503 int exponent,
00504 bool negative,
00505 int significant_digits) {
00506 bool negative_exponent = false;
00507 if (exponent < 0) {
00508 negative_exponent = true;
00509 exponent = -exponent;
00510 }
00511
00512
00513
00514
00515 unsigned result_size = significant_digits + 7;
00516 StringBuilder builder(result_size + 1);
00517
00518 if (negative) builder.AddCharacter('-');
00519 builder.AddCharacter(decimal_rep[0]);
00520 if (significant_digits != 1) {
00521 builder.AddCharacter('.');
00522 builder.AddString(decimal_rep + 1);
00523 builder.AddPadding('0', significant_digits - strlen(decimal_rep));
00524 }
00525
00526 builder.AddCharacter('e');
00527 builder.AddCharacter(negative_exponent ? '-' : '+');
00528 builder.AddFormatted("%d", exponent);
00529 return builder.Finalize();
00530 }
00531
00532
00533
00534 char* DoubleToExponentialCString(double value, int f) {
00535
00536 ASSERT(f >= -1 && f <= 20);
00537
00538 bool negative = false;
00539 if (value < 0) {
00540 value = -value;
00541 negative = true;
00542 }
00543
00544
00545 int decimal_point;
00546 int sign;
00547 char* decimal_rep = NULL;
00548 if (f == -1) {
00549 decimal_rep = dtoa(value, 0, 0, &decimal_point, &sign, NULL);
00550 f = strlen(decimal_rep) - 1;
00551 } else {
00552 decimal_rep = dtoa(value, 2, f + 1, &decimal_point, &sign, NULL);
00553 }
00554 int decimal_rep_length = strlen(decimal_rep);
00555 ASSERT(decimal_rep_length > 0);
00556 ASSERT(decimal_rep_length <= f + 1);
00557 USE(decimal_rep_length);
00558
00559 int exponent = decimal_point - 1;
00560 char* result =
00561 CreateExponentialRepresentation(decimal_rep, exponent, negative, f+1);
00562
00563 freedtoa(decimal_rep);
00564
00565 return result;
00566 }
00567
00568
00569 char* DoubleToPrecisionCString(double value, int p) {
00570 ASSERT(p >= 1 && p <= 21);
00571
00572 bool negative = false;
00573 if (value < 0) {
00574 value = -value;
00575 negative = true;
00576 }
00577
00578
00579 int decimal_point;
00580 int sign;
00581 char* decimal_rep = dtoa(value, 2, p, &decimal_point, &sign, NULL);
00582 int decimal_rep_length = strlen(decimal_rep);
00583 ASSERT(decimal_rep_length <= p);
00584
00585 int exponent = decimal_point - 1;
00586
00587 char* result = NULL;
00588
00589 if (exponent < -6 || exponent >= p) {
00590 result =
00591 CreateExponentialRepresentation(decimal_rep, exponent, negative, p);
00592 } else {
00593
00594
00595
00596
00597
00598 unsigned result_size = (decimal_point <= 0)
00599 ? -decimal_point + p + 3
00600 : p + 2;
00601 StringBuilder builder(result_size + 1);
00602 if (negative) builder.AddCharacter('-');
00603 if (decimal_point <= 0) {
00604 builder.AddString("0.");
00605 builder.AddPadding('0', -decimal_point);
00606 builder.AddString(decimal_rep);
00607 builder.AddPadding('0', p - decimal_rep_length);
00608 } else {
00609 const int m = Min(decimal_rep_length, decimal_point);
00610 builder.AddSubstring(decimal_rep, m);
00611 builder.AddPadding('0', decimal_point - decimal_rep_length);
00612 if (decimal_point < p) {
00613 builder.AddCharacter('.');
00614 const int extra = negative ? 2 : 1;
00615 if (decimal_rep_length > decimal_point) {
00616 const int len = strlen(decimal_rep + decimal_point);
00617 const int n = Min(len, p - (builder.position() - extra));
00618 builder.AddSubstring(decimal_rep + decimal_point, n);
00619 }
00620 builder.AddPadding('0', extra + (p - builder.position()));
00621 }
00622 }
00623 result = builder.Finalize();
00624 }
00625
00626 freedtoa(decimal_rep);
00627 return result;
00628 }
00629
00630
00631 char* DoubleToRadixCString(double value, int radix) {
00632 ASSERT(radix >= 2 && radix <= 36);
00633
00634
00635 static const char chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
00636
00637
00638
00639 static const int kBufferSize = 1100;
00640 char integer_buffer[kBufferSize];
00641 integer_buffer[kBufferSize - 1] = '\0';
00642
00643
00644
00645 char decimal_buffer[kBufferSize];
00646 decimal_buffer[kBufferSize - 1] = '\0';
00647
00648
00649 bool is_negative = value < 0.0;
00650 if (is_negative) value = -value;
00651
00652
00653 double integer_part = floor(value);
00654 double decimal_part = value - integer_part;
00655
00656
00657
00658 int integer_pos = kBufferSize - 2;
00659 do {
00660 integer_buffer[integer_pos--] =
00661 chars[static_cast<int>(fmod(integer_part, radix))];
00662 integer_part /= radix;
00663 } while (integer_part >= 1.0);
00664
00665 ASSERT(integer_pos > 0);
00666
00667 if (is_negative) integer_buffer[integer_pos--] = '-';
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678 int decimal_pos = 0;
00679 while ((decimal_part > 0.0) && (decimal_pos < kBufferSize - 1)) {
00680 decimal_part *= radix;
00681 decimal_buffer[decimal_pos++] =
00682 chars[static_cast<int>(floor(decimal_part))];
00683 decimal_part -= floor(decimal_part);
00684 }
00685 decimal_buffer[decimal_pos] = '\0';
00686
00687
00688 int integer_part_size = kBufferSize - 2 - integer_pos;
00689
00690 unsigned result_size = integer_part_size + decimal_pos;
00691
00692 if (decimal_pos > 0) result_size++;
00693
00694 StringBuilder builder(result_size + 1);
00695 builder.AddSubstring(integer_buffer + integer_pos + 1, integer_part_size);
00696 if (decimal_pos > 0) builder.AddCharacter('.');
00697 builder.AddSubstring(decimal_buffer, decimal_pos);
00698 return builder.Finalize();
00699 }
00700
00701
00702 } }