about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJosh Matthews <josh@joshmatthews.net>2011-11-10 06:31:42 -0500
committerBrian Anderson <banderson@mozilla.com>2011-11-10 11:40:34 -0800
commit43cb74b830110693e4e54c5670033cbae5c87e24 (patch)
tree76a893d796791953a34ed75d519f0e1f0362f2ad
parent599baf93257c5fef6600d4c10dbf256965e37fdc (diff)
downloadrust-43cb74b830110693e4e54c5670033cbae5c87e24.tar.gz
rust-43cb74b830110693e4e54c5670033cbae5c87e24.zip
Add float support to #fmt. Fix #1014.
-rw-r--r--src/comp/syntax/ext/fmt.rs3
-rw-r--r--src/lib/extfmt.rs18
-rw-r--r--src/lib/float.rs41
-rw-r--r--src/test/run-pass/syntax-extension-fmt.rs14
4 files changed, 72 insertions, 4 deletions
diff --git a/src/comp/syntax/ext/fmt.rs b/src/comp/syntax/ext/fmt.rs
index f3fb25acaf9..575d49e15a6 100644
--- a/src/comp/syntax/ext/fmt.rs
+++ b/src/comp/syntax/ext/fmt.rs
@@ -196,6 +196,7 @@ fn pieces_to_expr(cx: ext_ctxt, sp: span, pieces: [piece], args: [@ast::expr])
               ty_int(s) {
                 alt s { signed. { ret true; } unsigned. { ret false; } }
               }
+              ty_float. { ret true; }
               _ { ret false; }
             }
         }
@@ -250,6 +251,7 @@ fn pieces_to_expr(cx: ext_ctxt, sp: span, pieces: [piece], args: [@ast::expr])
           ty_hex(_) { ret make_conv_call(cx, arg.span, "uint", cnv, arg); }
           ty_bits. { ret make_conv_call(cx, arg.span, "uint", cnv, arg); }
           ty_octal. { ret make_conv_call(cx, arg.span, "uint", cnv, arg); }
+          ty_float. { ret make_conv_call(cx, arg.span, "float", cnv, arg); }
           _ { cx.span_unimpl(sp, unsupported); }
         }
     }
@@ -301,6 +303,7 @@ fn pieces_to_expr(cx: ext_ctxt, sp: span, pieces: [piece], args: [@ast::expr])
             }
           }
           ty_octal. { log "type: octal"; }
+          ty_float. { log "type: float"; }
         }
     }
     let fmt_sp = args[0].span;
diff --git a/src/lib/extfmt.rs b/src/lib/extfmt.rs
index b6d04397711..460ceee5cff 100644
--- a/src/lib/extfmt.rs
+++ b/src/lib/extfmt.rs
@@ -49,6 +49,7 @@ mod ct {
         ty_bits;
         ty_hex(caseness);
         ty_octal;
+        ty_float;
         // FIXME: More types
     }
     tag flag {
@@ -246,6 +247,8 @@ mod ct {
                 ty_bits
             } else if str::eq(tstr, "o") {
                 ty_octal
+            } else if str::eq(tstr, "f") {
+                ty_float
             } else { error("unknown type in conversion: " + tstr) };
         ret {ty: t, next: i + 1u};
     }
@@ -328,6 +331,21 @@ mod rt {
             };
         ret pad(cv, unpadded, pad_nozero);
     }
+    fn conv_float(cv: conv, f: float) -> str {
+        let (to_str, digits) = alt cv.precision {
+              count_is(c) { (float::to_str_exact, c as uint) }
+              count_implied. { (float::to_str, 6u) }
+        };
+        let s = to_str(f, digits);
+        if 0.0 <= f {
+            if have_flag(cv.flags, flag_sign_always) {
+                s = "+" + s;
+            } else if have_flag(cv.flags, flag_space_for_sign) {
+                s = " " + s;
+            }
+        }
+        ret pad(cv, s, pad_signed);
+    }
 
     // Convert an int to string with minimum number of digits. If precision is
     // 0 and num is 0 then the result is the empty string.
diff --git a/src/lib/float.rs b/src/lib/float.rs
index 0b8a701e7aa..faa71b4ed56 100644
--- a/src/lib/float.rs
+++ b/src/lib/float.rs
@@ -7,16 +7,17 @@ Module: float
  */
 
 /*
-Function: to_str
+Function: to_str_common
 
 Converts a float to a string
 
 Parameters:
 
 num - The float value
-digits: The number of significant digits
+digits - The number of significant digits
+exact - Whether to enforce the exact number of significant digits
 */
-fn to_str(num: float, digits: uint) -> str {
+fn to_str_common(num: float, digits: uint, exact: bool) -> str {
     let (num, accum) = num < 0.0 ? (-num, "-") : (num, "");
     let trunc = num as uint;
     let frac = num - (trunc as float);
@@ -24,14 +25,46 @@ fn to_str(num: float, digits: uint) -> str {
     if frac == 0.0 || digits == 0u { ret accum; }
     accum += ".";
     let i = digits;
-    while i > 0u && frac > 0.0 {
+    let epsilon = 1. / pow_uint_to_uint_as_float(10u, i);
+    while i > 0u && (frac >= epsilon || exact) {
         frac *= 10.0;
+        epsilon *= 10.0;
         let digit = frac as uint;
         accum += uint::str(digit);
         frac -= digit as float;
         i -= 1u;
     }
     ret accum;
+
+}
+
+/*
+Function: to_str
+
+Converts a float to a string with exactly the number of provided significant
+digits
+
+Parameters:
+
+num - The float value
+digits - The number of significant digits
+*/
+fn to_str_exact(num: float, digits: uint) -> str {
+    to_str_common(num, digits, true)
+}
+
+/*
+Function: to_str
+
+Converts a float to a string with a maximum number of significant digits
+
+Parameters:
+
+num - The float value
+digits - The number of significant digits
+*/
+fn to_str(num: float, digits: uint) -> str {
+    to_str_common(num, digits, false)
 }
 
 /*
diff --git a/src/test/run-pass/syntax-extension-fmt.rs b/src/test/run-pass/syntax-extension-fmt.rs
index c241a68e7f1..93e18580c64 100644
--- a/src/test/run-pass/syntax-extension-fmt.rs
+++ b/src/test/run-pass/syntax-extension-fmt.rs
@@ -38,6 +38,7 @@ fn part1() {
     test(#fmt["%X", 0x12ab_u], "12AB");
     test(#fmt["%o", 10u], "12");
     test(#fmt["%t", 0b11010101_u], "11010101");
+    test(#fmt["%f", 5.82], "5.82");
     // 32-bit limits
 
     test(#fmt["%i", -2147483648], "-2147483648");
@@ -61,6 +62,7 @@ fn part2() {
     test(#fmt["%10o", 10u], "        12");
     test(#fmt["%10t", 0xff_u], "  11111111");
     test(#fmt["%10c", 'A'], "         A");
+    test(#fmt["%10f", 5.82], "      5.82");
     // Left justify
 
     test(#fmt["%-10d", 500], "500       ");
@@ -73,6 +75,7 @@ fn part2() {
     test(#fmt["%-10o", 10u], "12        ");
     test(#fmt["%-10t", 0xff_u], "11111111  ");
     test(#fmt["%-10c", 'A'], "A         ");
+    test(#fmt["%-10f", 5.82], "5.82      ");
 }
 
 fn part3() {
@@ -90,6 +93,7 @@ fn part3() {
     test(#fmt["%.o", 10u], "12");
     test(#fmt["%.t", 3u], "11");
     test(#fmt["%.c", 'A'], "A");
+    test(#fmt["%.f", 5.82], "5");
     test(#fmt["%.0d", 0], "");
     test(#fmt["%.0u", 0u], "");
     test(#fmt["%.0x", 0u], "");
@@ -102,6 +106,7 @@ fn part3() {
     test(#fmt["%.0o", 10u], "12");
     test(#fmt["%.0t", 3u], "11");
     test(#fmt["%.0c", 'A'], "A");
+    test(#fmt["%.0f", 5.892], "5");
     test(#fmt["%.1d", 0], "0");
     test(#fmt["%.1u", 0u], "0");
     test(#fmt["%.1x", 0u], "0");
@@ -114,6 +119,7 @@ fn part3() {
     test(#fmt["%.1o", 10u], "12");
     test(#fmt["%.1t", 3u], "11");
     test(#fmt["%.1c", 'A'], "A");
+    test(#fmt["%.1f", 5.82], "5.8");
 }
 fn part4() {
     test(#fmt["%.5d", 0], "00000");
@@ -128,6 +134,7 @@ fn part4() {
     test(#fmt["%.5o", 10u], "00012");
     test(#fmt["%.5t", 3u], "00011");
     test(#fmt["%.5c", 'A'], "A");
+    test(#fmt["%.5f", 5.82], "5.82000");
     // Bool precision. I'm not sure if it's good or bad to have bool
     // conversions support precision - it's not standard printf so we
     // can do whatever. For now I'm making it behave the same as string
@@ -144,15 +151,19 @@ fn part5() {
     test(#fmt["%+d", 0], "+0");
     test(#fmt["%+d", 1], "+1");
     test(#fmt["%+d", -1], "-1");
+    test(#fmt["%+f", 0.0], "+0");
     // Leave space for sign
 
     test(#fmt["% d", 0], " 0");
     test(#fmt["% d", 1], " 1");
     test(#fmt["% d", -1], "-1");
+    test(#fmt["% f", 0.0], " 0");
     // Plus overrides space
 
     test(#fmt["% +d", 0], "+0");
     test(#fmt["%+ d", 0], "+0");
+    test(#fmt["% +f", 0.0], "+0");
+    test(#fmt["%+ f", 0.0], "+0");
     // 0-padding
 
     test(#fmt["%05d", 0], "00000");
@@ -163,6 +174,7 @@ fn part5() {
     test(#fmt["%05X", 127u], "0007F");
     test(#fmt["%05o", 10u], "00012");
     test(#fmt["%05t", 3u], "00011");
+    test(#fmt["%05f", 5.82], "05.82");
     // 0-padding a string is undefined but glibc does this:
 
     test(#fmt["%05s", "test"], " test");
@@ -181,6 +193,7 @@ fn part5() {
     test(#fmt["%-05s", "test"], "test ");
     test(#fmt["%-05c", 'A'], "A    ");
     test(#fmt["%-05b", true], "true ");
+    test(#fmt["%-05f", 5.82], "5.82 ");
 }
 fn part6() {
     // Precision overrides 0-padding
@@ -196,6 +209,7 @@ fn part6() {
     test(#fmt["%06.5x", 127u], " 0007f");
     test(#fmt["%06.5X", 127u], " 0007F");
     test(#fmt["%06.5o", 10u], " 00012");
+    test(#fmt["%08.5f", 5.82], " 5.82000");
     // Signed combinations
 
     test(#fmt["% 5d", 1], "    1");