Support 0 flag in #fmt

This commit is contained in:
Brian Anderson 2011-04-18 20:58:45 -04:00
parent 4763cd39ca
commit d4f1a48111
3 changed files with 80 additions and 12 deletions

View file

@ -171,20 +171,25 @@ fn pieces_to_expr(vec[piece] pieces, vec[@ast.expr] args) -> @ast.expr {
fn make_flags(common.span sp, vec[flag] flags) -> @ast.expr {
let vec[@ast.expr] flagexprs = vec();
for (flag f in flags) {
auto fstr;
alt (f) {
case (flag_left_justify) {
auto fstr = "flag_left_justify";
flagexprs += vec(make_rt_path_expr(sp, fstr));
fstr = "flag_left_justify";
}
case (flag_sign_always) {
auto fstr = "flag_sign_always";
flagexprs += vec(make_rt_path_expr(sp, fstr));
case (flag_left_zero_pad) {
fstr = "flag_left_zero_pad";
}
case (flag_space_for_sign) {
auto fstr = "flag_space_for_sign";
flagexprs += vec(make_rt_path_expr(sp, fstr));
fstr = "flag_space_for_sign";
}
case (flag_sign_always) {
fstr = "flag_sign_always";
}
case (flag_alternate) {
fstr = "flag_alternate";
}
}
flagexprs += vec(make_rt_path_expr(sp, fstr));
}
// 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 {
fail;
}
}
case (flag_left_zero_pad) {
}
case (_) {
log unsupported;
fail;

View file

@ -306,8 +306,10 @@ mod RT {
tag flag {
flag_left_justify;
flag_left_zero_pad;
flag_space_for_sign;
flag_sign_always;
flag_alternate;
// FIXME: This is a hack to avoid creating 0-length vec exprs,
// which have some difficulty typechecking currently. See
// comments in front.extfmt.make_flags
@ -344,7 +346,7 @@ mod RT {
s = " " + s;
}
}
ret pad(cv, s);
ret pad(cv, s, pad_signed);
}
fn conv_uint(&conv cv, uint u) -> str {
@ -364,7 +366,7 @@ mod RT {
res = uint_to_str_prec(u, 2u, prec);
}
}
ret pad(cv, res);
ret pad(cv, res, pad_unsigned);
}
fn conv_bool(&conv cv, bool b) -> str {
@ -396,7 +398,7 @@ mod RT {
}
}
}
ret pad(cv, unpadded);
ret pad(cv, unpadded, pad_nozero);
}
// Convert an int to string with minimum number of digits. If precision is
@ -449,7 +451,13 @@ mod RT {
ret _str.unsafe_from_bytes(svec);
}
fn pad(&conv cv, str s) -> str {
tag pad_type {
pad_signed;
pad_unsigned;
pad_nozero;
}
fn pad(&conv cv, str s, pad_type pt) -> str {
alt (cv.width) {
case (count_implied) {
ret s;
@ -459,11 +467,47 @@ mod RT {
auto uwidth = width as uint;
auto strlen = _str.char_len(s);
if (strlen < uwidth) {
auto zero_padding = false;
auto signed = false;
auto padchar = ' ';
alt (pt) {
case (pad_nozero) {
// fallthrough
}
case (pad_signed) {
signed = true;
if (have_flag(cv.flags, flag_left_zero_pad)) {
padchar = '0';
zero_padding = true;
}
}
case (pad_unsigned) {
if (have_flag(cv.flags, flag_left_zero_pad)) {
padchar = '0';
zero_padding = true;
}
}
}
auto diff = uwidth - strlen;
auto padstr = str_init_elt(' ', diff);
auto padstr = str_init_elt(padchar, diff);
if (have_flag(cv.flags, flag_left_justify)) {
ret s + padstr;
} else {
// This is completely heinous. If we have a signed
// value then potentially rip apart the intermediate
// result and insert some zeros. It may make sense
// to convert zero padding to a precision instead.
if (signed
&& zero_padding
&& _str.byte_len(s) > 0u
&& s.(0) == '-' as u8) {
auto bytelen = _str.byte_len(s);
auto numpart = _str.substr(s, 1u, bytelen - 1u);
ret "-" + padstr + numpart;
}
ret padstr + s;
}
} else {

View file

@ -126,4 +126,21 @@ fn main() {
// Plus overrides space
test(#fmt("% +d", 0), "+0");
test(#fmt("%+ d", 0), "+0");
// 0-padding
test(#fmt("%05d", 0), "00000");
test(#fmt("%05d", 1), "00001");
test(#fmt("%05d", -1), "-0001");
test(#fmt("%05u", 1u), "00001");
test(#fmt("%05x", 127u), "0007f");
test(#fmt("%05X", 127u), "0007F");
test(#fmt("%05t", 3u), "00011");
// 0-padding a string is undefined but glibc does this:
test(#fmt("%05s", "test"), " test");
test(#fmt("%05b", true), " true");
// TODO: Left-justify overrides 0-padding
// TODO: Precision overrides 0-padding
// TODO: Padding and +
// TODO: Padding and ' '
}