Skip to content

Commit d4f1a48

Browse files
committed
Support 0 flag in #fmt
1 parent 4763cd3 commit d4f1a48

File tree

3 files changed

+80
-12
lines changed

3 files changed

+80
-12
lines changed

src/comp/front/extfmt.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -171,20 +171,25 @@ fn pieces_to_expr(vec[piece] pieces, vec[@ast.expr] args) -> @ast.expr {
171171
fn make_flags(common.span sp, vec[flag] flags) -> @ast.expr {
172172
let vec[@ast.expr] flagexprs = vec();
173173
for (flag f in flags) {
174+
auto fstr;
174175
alt (f) {
175176
case (flag_left_justify) {
176-
auto fstr = "flag_left_justify";
177-
flagexprs += vec(make_rt_path_expr(sp, fstr));
177+
fstr = "flag_left_justify";
178178
}
179-
case (flag_sign_always) {
180-
auto fstr = "flag_sign_always";
181-
flagexprs += vec(make_rt_path_expr(sp, fstr));
179+
case (flag_left_zero_pad) {
180+
fstr = "flag_left_zero_pad";
182181
}
183182
case (flag_space_for_sign) {
184-
auto fstr = "flag_space_for_sign";
185-
flagexprs += vec(make_rt_path_expr(sp, fstr));
183+
fstr = "flag_space_for_sign";
184+
}
185+
case (flag_sign_always) {
186+
fstr = "flag_sign_always";
187+
}
188+
case (flag_alternate) {
189+
fstr = "flag_alternate";
186190
}
187191
}
192+
flagexprs += vec(make_rt_path_expr(sp, fstr));
188193
}
189194

190195
// FIXME: 0-length vectors can't have their type inferred
@@ -319,6 +324,8 @@ fn pieces_to_expr(vec[piece] pieces, vec[@ast.expr] args) -> @ast.expr {
319324
fail;
320325
}
321326
}
327+
case (flag_left_zero_pad) {
328+
}
322329
case (_) {
323330
log unsupported;
324331
fail;

src/lib/ExtFmt.rs

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -306,8 +306,10 @@ mod RT {
306306

307307
tag flag {
308308
flag_left_justify;
309+
flag_left_zero_pad;
309310
flag_space_for_sign;
310311
flag_sign_always;
312+
flag_alternate;
311313
// FIXME: This is a hack to avoid creating 0-length vec exprs,
312314
// which have some difficulty typechecking currently. See
313315
// comments in front.extfmt.make_flags
@@ -344,7 +346,7 @@ mod RT {
344346
s = " " + s;
345347
}
346348
}
347-
ret pad(cv, s);
349+
ret pad(cv, s, pad_signed);
348350
}
349351

350352
fn conv_uint(&conv cv, uint u) -> str {
@@ -364,7 +366,7 @@ mod RT {
364366
res = uint_to_str_prec(u, 2u, prec);
365367
}
366368
}
367-
ret pad(cv, res);
369+
ret pad(cv, res, pad_unsigned);
368370
}
369371

370372
fn conv_bool(&conv cv, bool b) -> str {
@@ -396,7 +398,7 @@ mod RT {
396398
}
397399
}
398400
}
399-
ret pad(cv, unpadded);
401+
ret pad(cv, unpadded, pad_nozero);
400402
}
401403

402404
// Convert an int to string with minimum number of digits. If precision is
@@ -449,7 +451,13 @@ mod RT {
449451
ret _str.unsafe_from_bytes(svec);
450452
}
451453

452-
fn pad(&conv cv, str s) -> str {
454+
tag pad_type {
455+
pad_signed;
456+
pad_unsigned;
457+
pad_nozero;
458+
}
459+
460+
fn pad(&conv cv, str s, pad_type pt) -> str {
453461
alt (cv.width) {
454462
case (count_implied) {
455463
ret s;
@@ -459,11 +467,47 @@ mod RT {
459467
auto uwidth = width as uint;
460468
auto strlen = _str.char_len(s);
461469
if (strlen < uwidth) {
470+
auto zero_padding = false;
471+
auto signed = false;
472+
auto padchar = ' ';
473+
alt (pt) {
474+
case (pad_nozero) {
475+
// fallthrough
476+
}
477+
case (pad_signed) {
478+
signed = true;
479+
if (have_flag(cv.flags, flag_left_zero_pad)) {
480+
padchar = '0';
481+
zero_padding = true;
482+
}
483+
}
484+
case (pad_unsigned) {
485+
if (have_flag(cv.flags, flag_left_zero_pad)) {
486+
padchar = '0';
487+
zero_padding = true;
488+
}
489+
}
490+
}
491+
462492
auto diff = uwidth - strlen;
463-
auto padstr = str_init_elt(' ', diff);
493+
auto padstr = str_init_elt(padchar, diff);
464494
if (have_flag(cv.flags, flag_left_justify)) {
465495
ret s + padstr;
466496
} else {
497+
// This is completely heinous. If we have a signed
498+
// value then potentially rip apart the intermediate
499+
// result and insert some zeros. It may make sense
500+
// to convert zero padding to a precision instead.
501+
if (signed
502+
&& zero_padding
503+
&& _str.byte_len(s) > 0u
504+
&& s.(0) == '-' as u8) {
505+
506+
auto bytelen = _str.byte_len(s);
507+
auto numpart = _str.substr(s, 1u, bytelen - 1u);
508+
ret "-" + padstr + numpart;
509+
}
510+
467511
ret padstr + s;
468512
}
469513
} else {

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,21 @@ fn main() {
126126
// Plus overrides space
127127
test(#fmt("% +d", 0), "+0");
128128
test(#fmt("%+ d", 0), "+0");
129+
130+
// 0-padding
131+
test(#fmt("%05d", 0), "00000");
132+
test(#fmt("%05d", 1), "00001");
133+
test(#fmt("%05d", -1), "-0001");
134+
test(#fmt("%05u", 1u), "00001");
135+
test(#fmt("%05x", 127u), "0007f");
136+
test(#fmt("%05X", 127u), "0007F");
137+
test(#fmt("%05t", 3u), "00011");
138+
// 0-padding a string is undefined but glibc does this:
139+
test(#fmt("%05s", "test"), " test");
140+
test(#fmt("%05b", true), " true");
141+
142+
// TODO: Left-justify overrides 0-padding
143+
// TODO: Precision overrides 0-padding
144+
// TODO: Padding and +
145+
// TODO: Padding and ' '
129146
}

0 commit comments

Comments
 (0)