From dcfdb02fabc3f640dac2873c365acdd9d979008e Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 16 Apr 2011 18:00:52 -0400 Subject: Make #fmt support explicit conversion widths --- src/comp/front/extfmt.rs | 40 ++++++++++++++++++++--- src/lib/ExtFmt.rs | 54 +++++++++++++++++++++++++------ src/test/run-pass/syntax-extension-fmt.rs | 10 ++++++ 3 files changed, 91 insertions(+), 13 deletions(-) diff --git a/src/comp/front/extfmt.rs b/src/comp/front/extfmt.rs index bd5fc433..65917ade 100644 --- a/src/comp/front/extfmt.rs +++ b/src/comp/front/extfmt.rs @@ -91,6 +91,11 @@ fn pieces_to_expr(vec[piece] pieces, vec[@ast.expr] args) -> @ast.expr { ret make_new_lit(sp, lit); } + fn make_new_int(common.span sp, int i) -> @ast.expr { + auto lit = ast.lit_int(i); + ret make_new_lit(sp, lit); + } + fn make_new_uint(common.span sp, uint u) -> @ast.expr { auto lit = ast.lit_uint(u); ret make_new_lit(sp, lit); @@ -145,6 +150,26 @@ fn pieces_to_expr(vec[piece] pieces, vec[@ast.expr] args) -> @ast.expr { } fn make_rt_conv_expr(common.span sp, &conv cnv) -> @ast.expr { + + fn make_count(common.span sp, &count cnt) -> @ast.expr { + alt (cnt) { + case (count_implied) { + auto idents = make_path_vec("count_implied"); + ret make_path_expr(sp, idents); + } + case (count_is(?c)) { + auto count_lit = make_new_int(sp, c); + auto count_is_path = make_path_vec("count_is"); + auto count_is_args = vec(count_lit); + ret make_call(sp, count_is_path, count_is_args); + } + case (_) { + log "not implemented"; + fail; + } + } + } + fn make_ty(common.span sp, &ty t) -> @ast.expr { auto rt_type; alt (t) { @@ -170,12 +195,17 @@ fn pieces_to_expr(vec[piece] pieces, vec[@ast.expr] args) -> @ast.expr { ret make_path_expr(sp, idents); } - fn make_conv_rec(common.span sp, &@ast.expr ty_expr) -> @ast.expr { - ret make_rec_expr(sp, vec(tup("ty", ty_expr))); + fn make_conv_rec(common.span sp, @ast.expr width_expr, + @ast.expr ty_expr) -> @ast.expr { + ret make_rec_expr(sp, vec(tup("width", width_expr), + tup("ty", ty_expr))); } + auto rt_conv_width = make_count(sp, cnv.width); auto rt_conv_ty = make_ty(sp, cnv.ty); - ret make_conv_rec(sp, rt_conv_ty); + ret make_conv_rec(sp, + rt_conv_width, + rt_conv_ty); } fn make_conv_call(common.span sp, str conv_type, @@ -208,6 +238,8 @@ fn pieces_to_expr(vec[piece] pieces, vec[@ast.expr] args) -> @ast.expr { alt (cnv.width) { case (count_implied) { } + case (count_is(_)) { + } case (_) { log unsupported; fail; @@ -225,7 +257,7 @@ fn pieces_to_expr(vec[piece] pieces, vec[@ast.expr] args) -> @ast.expr { alt (cnv.ty) { case (ty_str) { - ret arg; + ret make_conv_call(arg.span, "str", cnv, arg); } case (ty_int(?sign)) { alt (sign) { diff --git a/src/lib/ExtFmt.rs b/src/lib/ExtFmt.rs index e15fa462..1e9c53d9 100644 --- a/src/lib/ExtFmt.rs +++ b/src/lib/ExtFmt.rs @@ -294,6 +294,11 @@ mod CT { // implement it this way, I think. mod RT { + tag count { + count_is(int); + count_implied; + } + tag ty { ty_default; ty_bits; @@ -301,39 +306,70 @@ mod RT { ty_hex_lower; } - type conv = rec(ty ty); + type conv = rec(count width, + ty ty); fn conv_int(&conv cv, int i) -> str { - ret _int.to_str(i, 10u); + ret pad(cv, _int.to_str(i, 10u)); } fn conv_uint(&conv cv, uint u) -> str { + auto res; alt (cv.ty) { case (ty_default) { - ret _uint.to_str(u, 10u); + res = _uint.to_str(u, 10u); } case (ty_hex_lower) { - ret _uint.to_str(u, 16u); + res = _uint.to_str(u, 16u); } case (ty_hex_upper) { - ret _str.to_upper(_uint.to_str(u, 16u)); + res = _str.to_upper(_uint.to_str(u, 16u)); } case (ty_bits) { - ret _uint.to_str(u, 2u); + res = _uint.to_str(u, 2u); } } + ret pad(cv, res); } fn conv_bool(&conv cv, bool b) -> str { if (b) { - ret "true"; + ret pad(cv, "true"); } else { - ret "false"; + ret pad(cv, "false"); } } fn conv_char(&conv cv, char c) -> str { - ret _str.from_char(c); + ret pad(cv, _str.from_char(c)); + } + + fn conv_str(&conv cv, str s) -> str { + ret pad(cv, s); + } + + fn pad(&conv cv, str s) -> str { + alt (cv.width) { + case (count_implied) { + ret s; + } + case (count_is(?width)) { + // FIXME: Maybe width should be uint + auto uwidth = width as uint; + auto strlen = _str.char_len(s); + if (strlen < uwidth) { + auto diff = uwidth - strlen; + // FIXME: Probably should be a _str fn for this + auto padvec = _vec.init_elt[u8](' ' as u8, diff); + // FIXME: Using unsafe_from_bytes because rustboot + // can't figure out the is_utf8 predicate on from_bytes? + auto padstr = _str.unsafe_from_bytes(padvec); + ret padstr + s; + } else { + ret s; + } + } + } } } diff --git a/src/test/run-pass/syntax-extension-fmt.rs b/src/test/run-pass/syntax-extension-fmt.rs index 86ac9bdc..7598fee1 100644 --- a/src/test/run-pass/syntax-extension-fmt.rs +++ b/src/test/run-pass/syntax-extension-fmt.rs @@ -32,4 +32,14 @@ fn main() { test(#fmt("%u", 4294967295u), "4294967295"); test(#fmt("%x", 0xffffffff_u), "ffffffff"); test(#fmt("%t", 0xffffffff_u), "11111111111111111111111111111111"); + + // Widths + test(#fmt("%10d", 500), " 500"); + test(#fmt("%10d", -500), " -500"); + test(#fmt("%10u", 500u), " 500"); + test(#fmt("%10s", "test"), " test"); + test(#fmt("%10b", true), " true"); + test(#fmt("%10x", 0xff_u), " ff"); + test(#fmt("%10X", 0xff_u), " FF"); + test(#fmt("%10t", 0xff_u), " 11111111"); } -- cgit v1.2.3