Reviewed by Sam.
authoreric@webkit.org <eric@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 30 Dec 2007 08:38:39 +0000 (08:38 +0000)
committereric@webkit.org <eric@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 30 Dec 2007 08:38:39 +0000 (08:38 +0000)
        Update Number.toString to properly throw exceptions.
        Cleanup code in Number.toString implementation.

        * kjs/number_object.cpp:
        (KJS::numberToString):
        * kjs/object.cpp:
        (KJS::Error::create): Remove bogus debug lines.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@29036 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
JavaScriptCore/ChangeLog
JavaScriptCore/kjs/number_object.cpp
JavaScriptCore/kjs/object.cpp
LayoutTests/ChangeLog
LayoutTests/fast/js/number-toExponential-expected.txt
LayoutTests/fast/js/number-toExponential.html [new file with mode: 0644]
LayoutTests/fast/js/number-toString-expected.txt
LayoutTests/fast/js/number-tofixed-expected.txt
LayoutTests/fast/js/number-toprecision-expected.txt
LayoutTests/fast/js/resources/number-toExponential.js
LayoutTests/fast/js/resources/number-toString.js
LayoutTests/fast/js/resources/number-tofixed.js
LayoutTests/fast/js/resources/number-toprecision.js

index 04a5414f695104a1669a28516490d52498033edb..aa577198b9080e5b3d51e955838858888be5b248 100644 (file)
@@ -1,3 +1,15 @@
+2007-12-30  Eric Seidel  <eric@webkit.org>
+
+        Reviewed by Sam.
+        
+        Update Number.toString to properly throw exceptions.
+        Cleanup code in Number.toString implementation.
+
+        * kjs/number_object.cpp:
+        (KJS::numberToString):
+        * kjs/object.cpp:
+        (KJS::Error::create): Remove bogus debug lines.
+
 2007-12-28  Eric Seidel  <eric@webkit.org>
 
         Reviewed by Oliver.
index b7ef41c2881fc063fd02f300dc8400e59b43ca08..c88bcbc57ba8f6149510a80ecb7bad736f479361 100644 (file)
@@ -142,54 +142,62 @@ static double intPow10(int e)
 
 static JSValue* numberToString(ExecState* exec, JSValue* v, const List& args)
 {
-    double dradix = 10;
-    if (!args.isEmpty())
-        dradix = args[0]->toIntegerPreserveNaN(exec);
-    if (dradix >= 2 && dradix <= 36 && dradix != 10) { // false for NaN
-        int radix = static_cast<int>(dradix);
-        const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
-        // INT_MAX results in 1024 characters left of the dot with radix 2
-        // give the same space on the right side. safety checks are in place
-        // unless someone finds a precise rule.
-        char s[2048 + 3];
-        double x = v->toNumber(exec);
-        if (isnan(x) || isinf(x))
-            return jsString(UString::from(x));
-        
-        // apply algorithm on absolute value. add sign later.
-        bool neg = false;
-        if (x < 0.0) {
-            neg = true;
-            x = -x;
-        }
-        // convert integer portion
-        double f = floor(x);
-        double d = f;
-        char* dot = s + sizeof(s) / 2;
-        char* p = dot;
-        *p = '\0';
+    double radixAsDouble = args[0]->toInteger(exec); // nan -> 0
+    if (radixAsDouble == 10 || args[0]->isUndefined())
+        return jsString(v->toString(exec));
+
+    if (radixAsDouble < 2 || radixAsDouble > 36)
+        return throwError(exec, RangeError, "toString() radix argument must be between 2 and 36");
+
+    int radix = static_cast<int>(radixAsDouble);
+    const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+    // INT_MAX results in 1024 characters left of the dot with radix 2
+    // give the same space on the right side. safety checks are in place
+    // unless someone finds a precise rule.
+    char s[2048 + 3];
+    const char* lastCharInString = s + sizeof(s) - 1;
+    double x = v->toNumber(exec);
+    if (isnan(x) || isinf(x))
+        return jsString(UString::from(x));
+
+    bool isNegative = x < 0.0;
+    if (isNegative)
+        x = -x;
+
+    double integerPart = floor(x);
+    char* decimalPoint = s + sizeof(s) / 2;
+
+    // convert integer portion
+    char* p = decimalPoint;
+    double d = integerPart;
+    do {
+        int remainderDigit = static_cast<int>(fmod(d, radix));
+        *--p = digits[remainderDigit];
+        d /= radix;
+    } while ((d <= -1.0 || d >= 1.0) && s < p);
+
+    if (isNegative)
+        *--p = '-';
+    char* startOfResultString = p;
+    ASSERT(s <= startOfResultString);
+
+    d = x - integerPart;
+    p = decimalPoint;
+    const double epsilon = 0.001; // TODO: guessed. base on radix ?
+    bool hasFractionalPart = (d < -epsilon || d > epsilon);
+    if (hasFractionalPart) {
+        *p++ = '.';
         do {
-            *--p = digits[static_cast<int>(fmod(d, radix))];
-            d /= radix;
-        } while ((d <= -1.0 || d >= 1.0) && p > s);
-        // any decimal fraction ?
-        d = x - f;
-        const double eps = 0.001; // TODO: guessed. base on radix ?
-        if (d < -eps || d > eps) {
-            *dot++ = '.';
-            do {
-                d *= radix;
-                *dot++ = digits[static_cast<int>(d)];
-                d -= static_cast<int>(d);
-            } while ((d < -eps || d > eps) && dot - s < static_cast<int>(sizeof(s)) - 1);
-            *dot = '\0';
-        }
-        // add sign if negative
-        if (neg)
-            *--p = '-';
-        return jsString(p);
+            d *= radix;
+            const int digit = static_cast<int>(d);
+            *p++ = digits[digit];
+            d -= digit;
+        } while ((d < -epsilon || d > epsilon) && p < lastCharInString);
     }
-    return jsString(v->toString(exec));
+    *p = '\0';
+    ASSERT(p < s + sizeof(s));
+
+    return jsString(startOfResultString);
 }
 
 static JSValue* numberToFixed(ExecState* exec, JSValue* v, const List& args)
index 697b56a8ebc6044dc594f4501266c46a36420a84..2d7261b1f8680ac2bb9042d4a05f6aee1298d0ab 100644 (file)
@@ -646,18 +646,6 @@ JSObject *Error::create(ExecState *exec, ErrorType errtype, const UString &messa
     err->put(exec, "sourceURL", jsString(sourceURL));
  
   return err;
-
-/*
-#ifndef NDEBUG
-  const char *msg = err->get(messagePropertyName)->toString().value().ascii();
-  if (l >= 0)
-      fprintf(stderr, "KJS: %s at line %d. %s\n", estr, l, msg);
-  else
-      fprintf(stderr, "KJS: %s. %s\n", estr, msg);
-#endif
-
-  return err;
-*/
 }
 
 JSObject *Error::create(ExecState *exec, ErrorType type, const char *message)
index 8d5000dc5371fa1d317f72469eb65098ff7870d1..acf4daa34a3d8d20e5c12e4f6d9666bc1881d46b 100644 (file)
@@ -1,3 +1,16 @@
+2007-12-30  Eric Seidel  <eric@webkit.org>
+
+        Reviewed by Sam.
+        
+        Add missing fast/js/number-toExponential.html file and correct results.
+        Add missing number.toString(2) test which also was missing.
+        Update toString results now that we're properly throwing exceptions.
+
+        * fast/js/number-toExponential-expected.txt:
+        * fast/js/number-toExponential.html: Added.
+        * fast/js/number-toString-expected.txt:
+        * fast/js/resources/number-toString.js:
+
 2007-12-29  Alexey Proskuryakov  <ap@webkit.org>
 
         Reviewed by Darin.
index f7ed3005a9ff080eb9b163ab73a4bd913a45c3b3..7d30eba7c633c601a0629a7c7ae0d60de2c7f63b 100644 (file)
@@ -4,20 +4,25 @@ PASS (0.0).toExponential() is "0e+0"
 PASS (-0.0).toExponential() is "0e+0"
 PASS (123.456).toExponential() is "1.23456e+2"
 PASS (123.456).toExponential(0) is "1e+2"
+PASS (123.456).toExponential(null) is "1e+2"
+PASS (123.456).toExponential(false) is "1e+2"
+PASS (123.456).toExponential('foo') is "1e+2"
+PASS (123.456).toExponential(nan) is "1e+2"
 PASS (123.456).toExponential(1) is "1.2e+2"
+PASS (123.456).toExponential(true) is "1.2e+2"
+PASS (123.456).toExponential('1') is "1.2e+2"
 PASS (123.456).toExponential(2) is "1.23e+2"
+PASS (123.456).toExponential(2.9) is "1.23e+2"
 PASS (123.456).toExponential(3) is "1.235e+2"
+PASS (123.456).toExponential(5) is "1.23456e+2"
+PASS (123.456).toExponential(6) is "1.234560e+2"
 FAIL (123.456).toExponential(20) should be 1.23456000000000003070e+2. Was 1.23456000000000000000e+2.
 FAIL (123.456).toExponential(21) should be 1.234560000000000030695e+2. Threw exception RangeError: toExponential() argument must between 0 and 20
 FAIL (123.456).toExponential(100) should be 1.2345600000000000306954461848363280296325683593750000000000000000000000000000000000000000000000000000e+2. Threw exception RangeError: toExponential() argument must between 0 and 20
 PASS (123.456).toExponential(101) threw exception RangeError: toExponential() argument must between 0 and 20.
 PASS (123.456).toExponential(-1) threw exception RangeError: toExponential() argument must between 0 and 20.
-PASS (123.456).toExponential('foo') is "1e+2"
-PASS (1.).toExponential(10) is "1.0000000000e+0"
 PASS (1234.567).toExponential(posInf) threw exception RangeError: toExponential() argument must between 0 and 20.
 PASS (1234.567).toExponential(negInf) threw exception RangeError: toExponential() argument must between 0 and 20.
-PASS (123.456).toExponential(0) is "1e+2"
-PASS (123.456).toExponential(nan) is "1e+2"
 PASS posInf.toExponential() is "Infinity"
 PASS negInf.toExponential() is "-Infinity"
 PASS nan.toExponential() is "NaN"
diff --git a/LayoutTests/fast/js/number-toExponential.html b/LayoutTests/fast/js/number-toExponential.html
new file mode 100644 (file)
index 0000000..e6805a2
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="resources/js-test-style.css">
+<script src="resources/js-test-pre.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script src="resources/number-toExponential.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
index 07c7687c0c1893a55b4d63684de19ce87bfa4370..98effe0a4b48fe657a033f7af0739467b7870cfb 100644 (file)
@@ -3,16 +3,18 @@ PASS (-0.0).toString(4) is "0"
 PASS (0.0).toString() is "0"
 PASS (-0.0).toString() is "0"
 PASS (1234.567).toString() is "1234.567"
-FAIL (1234.567).toString(0) should throw exception undefined. Was 1234.567.
-FAIL (1234.567).toString(null) should throw exception undefined. Was 1234.567.
-FAIL (1234.567).toString(false) should throw exception undefined. Was 1234.567.
-FAIL (1234.567).toString('foo') should throw exception undefined. Was 1234.567.
-FAIL (1234.567).toString(nan) should throw exception undefined. Was 1234.567.
-FAIL (1234.567).toString(1) should throw exception undefined. Was 1234.567.
-FAIL (1234.567).toString(true) should throw exception undefined. Was 1234.567.
-FAIL (1234.567).toString('1') should throw exception undefined. Was 1234.567.
+PASS (1234.567).toString(0) threw exception RangeError: toString() radix argument must be between 2 and 36.
+PASS (1234.567).toString(null) threw exception RangeError: toString() radix argument must be between 2 and 36.
+PASS (1234.567).toString(false) threw exception RangeError: toString() radix argument must be between 2 and 36.
+PASS (1234.567).toString('foo') threw exception RangeError: toString() radix argument must be between 2 and 36.
+PASS (1234.567).toString(nan) threw exception RangeError: toString() radix argument must be between 2 and 36.
+PASS (1234.567).toString(1) threw exception RangeError: toString() radix argument must be between 2 and 36.
+PASS (1234.567).toString(true) threw exception RangeError: toString() radix argument must be between 2 and 36.
+PASS (1234.567).toString('1') threw exception RangeError: toString() radix argument must be between 2 and 36.
+PASS (1234.567).toString(2) is "10011010010.1001000100100110111010010111100011010101"
 FAIL (1234.567).toString(3) should be 1200201.120022100021001021021002202. Was 1200201.1200221000210010210210022012001102222001211021211122102120100010210200200010021222011100022102111111220000120121020202022222012221002020211012221122112000100011101001001002222022012020010220022122022110202002002202222202212010021201212012220021121111000000211200200222000112012112202111102102221120000212111202201022111021100221120010011220020100220021221110002212111200002212221102221002020220001110120021210211010221211001220011121210110000101120102000202011022002220222101010221211000120010022102002210021221002122211021120201111101202110100001121111120122120122110201201222020221011002121022200201210122000022020200001000000221221112200220100222120210020001201202121010200011210020001210210121202022102101110122020100020021222102012012222212121111121121121101212122021001010222201200221200011220111121111111102022222110022222112200020021100202210020012212001001102111111221201020222201000210220121000100220121111222121011110101102001002022021011201200101200001210210121000020121110102110210201010021122012201111111201102.
 PASS (1234.567).toString(4) is "103102.21010212322113203111"
+PASS (1234.567).toString(4.9) is "103102.21010212322113203111"
 FAIL (1234.567).toString(5) should be 14414.240414141414141414. Was 14414.240414141414141414200133011442434031040124330244023124200011304312311324100320310322232334401241444023301301424311402410343440440144234121221004042313214433223312340344421433303403212012234210130444410021313022131212430231.
 FAIL (1234.567).toString(6) should be 5414.32224554134430233. Was 5414.3222455413443023323355441432422515541513.
 FAIL (1234.567).toString(7) should be 3412.365323661111653. Was 3412.36532366111165250030063220011062625264235022366031355006423562400353351033514604443661233126306354466066240662520033312110222004612542216364300525534333221304150444203141210500162302516210434315152234340326603635461501336242116203314153354651126532105365415116500340501505534144156652030554012465625565161332645334223651145104425554526302023034654600066564512123012525546404216112020364120610144012434116162201243325036164040215120665415201320221662333526204360066016546153511426052250513314566552656441054644406206121320041026316114014115253630016446423605405142254165214403262552251626030533313033165104611045024555541606452033416313565234306516501564212144644341243233643122051150155434522302224566623136452416322220322431013335605243531535621413652665133652130062451466235302643446415425055454112014335430303211500136666226012454111006151346436341034352626526044063562543341162200323461022054312415062224634155133626554162431544055412201624614356014312604122500301.
@@ -45,10 +47,10 @@ FAIL (1234.567).toString(33) should be 14d.inf96rdvm. Was 14d.inf96rdvlmnwci9088
 FAIL (1234.567).toString(34) should be 12a.j9fchdtm. Was 12a.j9fchdtm1i0e8edbf0vogn0it8vsx3r8s9s5al8h.
 FAIL (1234.567).toString(35) should be 109.jtk4d4d4e. Was 109.jtk4d4d4doflfe7xi169wd6oyjq01vqcl2f150bis1clidgo4vg3nybjteo1lmjwxvahfy6dqnwydgaympbcv0gpgka2bwejgn0u0gutj58og5m4ab2udlvxfofqyjor4tqqrg1ik6nc1elynjm0p43j43691y6cfxirrmynomfo0xt808yft9pevk3ljiwboaq0uyr6h989pn5aexskwpp8kb0hrwe45vomiv7phkl1msuk8tya7aagjndr5fhkia6illwtjqjv8kpg9j1cm9yh60x0udj60cwu5nd12d59p8vg0ws7qvmnwn47sdbxr97o60st8bussl2932ughjiitjna9p6s55bjdkgxeobvk9euc04gu79pna4oqoxcv4522ggbcgo852pn9jayroy86sf2q119hymgrct7gj7gidbi88iow66djcbqg1g5j6fc5umb5fssde5uq3rvc9x0g81eo5ursjb1ptwu18ljskttqiixfmthionnj7l5p7qemqtn9cdr4xnax361l60vistm8pmjifgbh0j9se6rnekyyekn1c80o95ivbpnmewa1ac1p2suh4dkt0p7jmshx5qb92cov6v12wn7dxdr8tit051nctry8yt7jpsfsex4683ywbtcx9cjul52scv1ud7c996cwa1ieshpa4g6ocyvwm786lhhkwsbt0ep0a088xuuomg2hqga2pk7ibsb457ui5cle42t7yj7ugfp2ynivha0bxqs868b5yq59hg3ri3v9b0akxg0xgk3fx4o5pcayb9gv0sm1vhget72g6lp20f1q3i6subc9qkvvytcli037h3w47x9j343wxe53vodb3dyo9q8a4aj4dcysx95k5ose36267be1mdli4tqw7hcj3oaewepe0livh58p1w1vjc3w31m5c4v1ke94qdaml45dulv8gj7k75bwpd97h9emvycbe7akuvjt1v5d37kshsrekjfodf957jnak4agnkbv9993ycb69im.
 FAIL (1234.567).toString(36) should be ya.kety9sifl. Was ya.kety9sifklzsakqhbyb9.
-FAIL (1234.567).toString(37) should throw exception undefined. Was 1234.567.
-FAIL (1234.567).toString(-1) should throw exception undefined. Was 1234.567.
-FAIL (1234.567).toString(posInf) should throw exception undefined. Was 1234.567.
-FAIL (1234.567).toString(negInf) should throw exception undefined. Was 1234.567.
+PASS (1234.567).toString(37) threw exception RangeError: toString() radix argument must be between 2 and 36.
+PASS (1234.567).toString(-1) threw exception RangeError: toString() radix argument must be between 2 and 36.
+PASS (1234.567).toString(posInf) threw exception RangeError: toString() radix argument must be between 2 and 36.
+PASS (1234.567).toString(negInf) threw exception RangeError: toString() radix argument must be between 2 and 36.
 PASS posInf.toString() is "Infinity"
 PASS negInf.toString() is "-Infinity"
 PASS nan.toString() is "NaN"
index 319dcc54a18643f8e757da0762b8da3fbe5b722d..8f053e30fd352d016f4275a1ab8c02e096c2c919 100644 (file)
@@ -39,6 +39,7 @@ PASS (1234.567).toFixed(1) is "1234.6"
 PASS (1234.567).toFixed(true) is "1234.6"
 PASS (1234.567).toFixed('1') is "1234.6"
 PASS (1234.567).toFixed(2) is "1234.57"
+PASS (1234.567).toFixed(2.9) is "1234.57"
 PASS (1234.567).toFixed(5) is "1234.56700"
 FAIL (1234.567).toFixed(20) should be 1234.56700000000000727596. Was 1234.56700000000000000000.
 FAIL (1234.567).toFixed(21) should be 1234.567000000000007275958. Threw exception RangeError: toFixed() digits argument must be between 0 and 20
index 2e623edf0a8bd07ad82dd0d10715430f7455ccbe..631fa8066106af18067f74a1f7bcd74aae066d48 100644 (file)
@@ -20,6 +20,7 @@ PASS (1234.567).toPrecision(1) is "1e+3"
 PASS (1234.567).toPrecision(true) is "1e+3"
 PASS (1234.567).toPrecision('1') is "1e+3"
 PASS (1234.567).toPrecision(2) is "1.2e+3"
+PASS (1234.567).toPrecision(2.9) is "1.2e+3"
 PASS (1234.567).toPrecision(5) is "1234.6"
 FAIL (1234.567).toPrecision(21) should be 1234.56700000000000728. Was 1234.56700000000000000.
 FAIL (1234.567).toPrecision(22) should be 1234.567000000000007276. Threw exception RangeError: toPrecision() argument must be between 1 and 21
index 13b395d6944b32f2b915b641580c6460c4a7ced6..b2698c6d3f7d9977b9c648d7e3a1be7b6d4b5b0e 100644 (file)
@@ -22,6 +22,7 @@ shouldBeEqualToString("(123.456).toExponential(true)", "1.2e+2"); // just like 1
 shouldBeEqualToString("(123.456).toExponential('1')", "1.2e+2");
 
 shouldBeEqualToString("(123.456).toExponential(2)", "1.23e+2");
+shouldBeEqualToString("(123.456).toExponential(2.9)", "1.23e+2");
 shouldBeEqualToString("(123.456).toExponential(3)", "1.235e+2");
 shouldBeEqualToString("(123.456).toExponential(5)", "1.23456e+2");
 shouldBeEqualToString("(123.456).toExponential(6)", "1.234560e+2");
index 1ef9b1379dae64971ba7fdb2ba74ae6941f1f391..f7ef73d9dfc9baffc0001d445aa363ab5a417290 100644 (file)
@@ -21,8 +21,10 @@ shouldThrow("(1234.567).toString(true)");
 shouldThrow("(1234.567).toString('1')");
 
 // These test for Firefox compatibility, the spec is "implementation defined"
+shouldBeEqualToString("(1234.567).toString(2)", "10011010010.1001000100100110111010010111100011010101");
 shouldBeEqualToString("(1234.567).toString(3)", "1200201.120022100021001021021002202");
 shouldBeEqualToString("(1234.567).toString(4)", "103102.21010212322113203111");
+shouldBeEqualToString("(1234.567).toString(4.9)", "103102.21010212322113203111");
 shouldBeEqualToString("(1234.567).toString(5)", "14414.240414141414141414");
 shouldBeEqualToString("(1234.567).toString(6)", "5414.32224554134430233");
 shouldBeEqualToString("(1234.567).toString(7)", "3412.365323661111653");
index 215f3d481d9a2375225731a02867a7b9c0d96bd9..99d356e98ba77e0851dd9239906435ef8160c6d1 100644 (file)
@@ -57,6 +57,7 @@ shouldBeEqualToString("(1234.567).toFixed(true)", "1234.6"); // just like 1
 shouldBeEqualToString("(1234.567).toFixed('1')", "1234.6"); // just like 1
 
 shouldBeEqualToString("(1234.567).toFixed(2)", "1234.57");
+shouldBeEqualToString("(1234.567).toFixed(2.9)", "1234.57");
 shouldBeEqualToString("(1234.567).toFixed(5)", "1234.56700");
 shouldBeEqualToString("(1234.567).toFixed(20)", "1234.56700000000000727596");
 
index cfe6c2d1537df87d9fa3d1754d5e96c903f944d9..ffc960f1c86941e8592b1700b9e3b0146e608e9f 100644 (file)
@@ -25,6 +25,7 @@ shouldBeEqualToString("(1234.567).toPrecision(1)", "1e+3");
 shouldBeEqualToString("(1234.567).toPrecision(true)", "1e+3"); // just like 1
 shouldBeEqualToString("(1234.567).toPrecision('1')", "1e+3"); // just like 1
 shouldBeEqualToString("(1234.567).toPrecision(2)", "1.2e+3");
+shouldBeEqualToString("(1234.567).toPrecision(2.9)", "1.2e+3");
 shouldBeEqualToString("(1234.567).toPrecision(5)", "1234.6");
 shouldBeEqualToString("(1234.567).toPrecision(21)", "1234.56700000000000728");
 // SpiderMonkey allows precision values 1 to 100, we only allow 1 to 21 currently