Skip to content

Commit 43cb74b

Browse files
jdmbrson
authored andcommitted
Add float support to #fmt. Fix #1014.
1 parent 599baf9 commit 43cb74b

File tree

4 files changed

+72
-4
lines changed

4 files changed

+72
-4
lines changed

src/comp/syntax/ext/fmt.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ fn pieces_to_expr(cx: ext_ctxt, sp: span, pieces: [piece], args: [@ast::expr])
196196
ty_int(s) {
197197
alt s { signed. { ret true; } unsigned. { ret false; } }
198198
}
199+
ty_float. { ret true; }
199200
_ { ret false; }
200201
}
201202
}
@@ -250,6 +251,7 @@ fn pieces_to_expr(cx: ext_ctxt, sp: span, pieces: [piece], args: [@ast::expr])
250251
ty_hex(_) { ret make_conv_call(cx, arg.span, "uint", cnv, arg); }
251252
ty_bits. { ret make_conv_call(cx, arg.span, "uint", cnv, arg); }
252253
ty_octal. { ret make_conv_call(cx, arg.span, "uint", cnv, arg); }
254+
ty_float. { ret make_conv_call(cx, arg.span, "float", cnv, arg); }
253255
_ { cx.span_unimpl(sp, unsupported); }
254256
}
255257
}
@@ -301,6 +303,7 @@ fn pieces_to_expr(cx: ext_ctxt, sp: span, pieces: [piece], args: [@ast::expr])
301303
}
302304
}
303305
ty_octal. { log "type: octal"; }
306+
ty_float. { log "type: float"; }
304307
}
305308
}
306309
let fmt_sp = args[0].span;

src/lib/extfmt.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ mod ct {
4949
ty_bits;
5050
ty_hex(caseness);
5151
ty_octal;
52+
ty_float;
5253
// FIXME: More types
5354
}
5455
tag flag {
@@ -246,6 +247,8 @@ mod ct {
246247
ty_bits
247248
} else if str::eq(tstr, "o") {
248249
ty_octal
250+
} else if str::eq(tstr, "f") {
251+
ty_float
249252
} else { error("unknown type in conversion: " + tstr) };
250253
ret {ty: t, next: i + 1u};
251254
}
@@ -328,6 +331,21 @@ mod rt {
328331
};
329332
ret pad(cv, unpadded, pad_nozero);
330333
}
334+
fn conv_float(cv: conv, f: float) -> str {
335+
let (to_str, digits) = alt cv.precision {
336+
count_is(c) { (float::to_str_exact, c as uint) }
337+
count_implied. { (float::to_str, 6u) }
338+
};
339+
let s = to_str(f, digits);
340+
if 0.0 <= f {
341+
if have_flag(cv.flags, flag_sign_always) {
342+
s = "+" + s;
343+
} else if have_flag(cv.flags, flag_space_for_sign) {
344+
s = " " + s;
345+
}
346+
}
347+
ret pad(cv, s, pad_signed);
348+
}
331349

332350
// Convert an int to string with minimum number of digits. If precision is
333351
// 0 and num is 0 then the result is the empty string.

src/lib/float.rs

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,64 @@ Module: float
77
*/
88

99
/*
10-
Function: to_str
10+
Function: to_str_common
1111
1212
Converts a float to a string
1313
1414
Parameters:
1515
1616
num - The float value
17-
digits: The number of significant digits
17+
digits - The number of significant digits
18+
exact - Whether to enforce the exact number of significant digits
1819
*/
19-
fn to_str(num: float, digits: uint) -> str {
20+
fn to_str_common(num: float, digits: uint, exact: bool) -> str {
2021
let (num, accum) = num < 0.0 ? (-num, "-") : (num, "");
2122
let trunc = num as uint;
2223
let frac = num - (trunc as float);
2324
accum += uint::str(trunc);
2425
if frac == 0.0 || digits == 0u { ret accum; }
2526
accum += ".";
2627
let i = digits;
27-
while i > 0u && frac > 0.0 {
28+
let epsilon = 1. / pow_uint_to_uint_as_float(10u, i);
29+
while i > 0u && (frac >= epsilon || exact) {
2830
frac *= 10.0;
31+
epsilon *= 10.0;
2932
let digit = frac as uint;
3033
accum += uint::str(digit);
3134
frac -= digit as float;
3235
i -= 1u;
3336
}
3437
ret accum;
38+
39+
}
40+
41+
/*
42+
Function: to_str
43+
44+
Converts a float to a string with exactly the number of provided significant
45+
digits
46+
47+
Parameters:
48+
49+
num - The float value
50+
digits - The number of significant digits
51+
*/
52+
fn to_str_exact(num: float, digits: uint) -> str {
53+
to_str_common(num, digits, true)
54+
}
55+
56+
/*
57+
Function: to_str
58+
59+
Converts a float to a string with a maximum number of significant digits
60+
61+
Parameters:
62+
63+
num - The float value
64+
digits - The number of significant digits
65+
*/
66+
fn to_str(num: float, digits: uint) -> str {
67+
to_str_common(num, digits, false)
3568
}
3669

3770
/*

src/test/run-pass/syntax-extension-fmt.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ fn part1() {
3838
test(#fmt["%X", 0x12ab_u], "12AB");
3939
test(#fmt["%o", 10u], "12");
4040
test(#fmt["%t", 0b11010101_u], "11010101");
41+
test(#fmt["%f", 5.82], "5.82");
4142
// 32-bit limits
4243

4344
test(#fmt["%i", -2147483648], "-2147483648");
@@ -61,6 +62,7 @@ fn part2() {
6162
test(#fmt["%10o", 10u], " 12");
6263
test(#fmt["%10t", 0xff_u], " 11111111");
6364
test(#fmt["%10c", 'A'], " A");
65+
test(#fmt["%10f", 5.82], " 5.82");
6466
// Left justify
6567

6668
test(#fmt["%-10d", 500], "500 ");
@@ -73,6 +75,7 @@ fn part2() {
7375
test(#fmt["%-10o", 10u], "12 ");
7476
test(#fmt["%-10t", 0xff_u], "11111111 ");
7577
test(#fmt["%-10c", 'A'], "A ");
78+
test(#fmt["%-10f", 5.82], "5.82 ");
7679
}
7780

7881
fn part3() {
@@ -90,6 +93,7 @@ fn part3() {
9093
test(#fmt["%.o", 10u], "12");
9194
test(#fmt["%.t", 3u], "11");
9295
test(#fmt["%.c", 'A'], "A");
96+
test(#fmt["%.f", 5.82], "5");
9397
test(#fmt["%.0d", 0], "");
9498
test(#fmt["%.0u", 0u], "");
9599
test(#fmt["%.0x", 0u], "");
@@ -102,6 +106,7 @@ fn part3() {
102106
test(#fmt["%.0o", 10u], "12");
103107
test(#fmt["%.0t", 3u], "11");
104108
test(#fmt["%.0c", 'A'], "A");
109+
test(#fmt["%.0f", 5.892], "5");
105110
test(#fmt["%.1d", 0], "0");
106111
test(#fmt["%.1u", 0u], "0");
107112
test(#fmt["%.1x", 0u], "0");
@@ -114,6 +119,7 @@ fn part3() {
114119
test(#fmt["%.1o", 10u], "12");
115120
test(#fmt["%.1t", 3u], "11");
116121
test(#fmt["%.1c", 'A'], "A");
122+
test(#fmt["%.1f", 5.82], "5.8");
117123
}
118124
fn part4() {
119125
test(#fmt["%.5d", 0], "00000");
@@ -128,6 +134,7 @@ fn part4() {
128134
test(#fmt["%.5o", 10u], "00012");
129135
test(#fmt["%.5t", 3u], "00011");
130136
test(#fmt["%.5c", 'A'], "A");
137+
test(#fmt["%.5f", 5.82], "5.82000");
131138
// Bool precision. I'm not sure if it's good or bad to have bool
132139
// conversions support precision - it's not standard printf so we
133140
// can do whatever. For now I'm making it behave the same as string
@@ -144,15 +151,19 @@ fn part5() {
144151
test(#fmt["%+d", 0], "+0");
145152
test(#fmt["%+d", 1], "+1");
146153
test(#fmt["%+d", -1], "-1");
154+
test(#fmt["%+f", 0.0], "+0");
147155
// Leave space for sign
148156

149157
test(#fmt["% d", 0], " 0");
150158
test(#fmt["% d", 1], " 1");
151159
test(#fmt["% d", -1], "-1");
160+
test(#fmt["% f", 0.0], " 0");
152161
// Plus overrides space
153162

154163
test(#fmt["% +d", 0], "+0");
155164
test(#fmt["%+ d", 0], "+0");
165+
test(#fmt["% +f", 0.0], "+0");
166+
test(#fmt["%+ f", 0.0], "+0");
156167
// 0-padding
157168

158169
test(#fmt["%05d", 0], "00000");
@@ -163,6 +174,7 @@ fn part5() {
163174
test(#fmt["%05X", 127u], "0007F");
164175
test(#fmt["%05o", 10u], "00012");
165176
test(#fmt["%05t", 3u], "00011");
177+
test(#fmt["%05f", 5.82], "05.82");
166178
// 0-padding a string is undefined but glibc does this:
167179

168180
test(#fmt["%05s", "test"], " test");
@@ -181,6 +193,7 @@ fn part5() {
181193
test(#fmt["%-05s", "test"], "test ");
182194
test(#fmt["%-05c", 'A'], "A ");
183195
test(#fmt["%-05b", true], "true ");
196+
test(#fmt["%-05f", 5.82], "5.82 ");
184197
}
185198
fn part6() {
186199
// Precision overrides 0-padding
@@ -196,6 +209,7 @@ fn part6() {
196209
test(#fmt["%06.5x", 127u], " 0007f");
197210
test(#fmt["%06.5X", 127u], " 0007F");
198211
test(#fmt["%06.5o", 10u], " 00012");
212+
test(#fmt["%08.5f", 5.82], " 5.82000");
199213
// Signed combinations
200214

201215
test(#fmt["% 5d", 1], " 1");

0 commit comments

Comments
 (0)