aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Anderson <[email protected]>2011-04-16 19:43:29 -0400
committerBrian Anderson <[email protected]>2011-04-16 19:43:29 -0400
commit96e3e29e88fa877aa087b616a58b3492b036ee85 (patch)
treeb54b028626fe283016d5358438a22f3dffd15e3b
parentAdd another test for #fmt conversion widths (diff)
downloadrust-96e3e29e88fa877aa087b616a58b3492b036ee85.tar.xz
rust-96e3e29e88fa877aa087b616a58b3492b036ee85.zip
Support left-justification in #fmt conversions
-rw-r--r--src/comp/front/extfmt.rs65
-rw-r--r--src/lib/ExtFmt.rs32
-rw-r--r--src/test/run-pass/syntax-extension-fmt.rs10
3 files changed, 95 insertions, 12 deletions
diff --git a/src/comp/front/extfmt.rs b/src/comp/front/extfmt.rs
index 65917ade..241e71a8 100644
--- a/src/comp/front/extfmt.rs
+++ b/src/comp/front/extfmt.rs
@@ -78,6 +78,10 @@ fn expr_to_str(@ast.expr expr) -> str {
fail;
}
+// FIXME: A lot of these functions for producing expressions can probably
+// be factored out in common with other code that builds expressions.
+// FIXME: Probably should be using the parser's span functions
+// FIXME: Cleanup the naming of these functions
fn pieces_to_expr(vec[piece] pieces, vec[@ast.expr] args) -> @ast.expr {
fn make_new_lit(common.span sp, ast.lit_ lit) -> @ast.expr {
@@ -116,6 +120,12 @@ fn pieces_to_expr(vec[piece] pieces, vec[@ast.expr] args) -> @ast.expr {
ret sp_pathexpr;
}
+ fn make_vec_expr(common.span sp, vec[@ast.expr] exprs) -> @ast.expr {
+ auto vecexpr = ast.expr_vec(exprs, ast.imm, ast.ann_none);
+ auto sp_vecexpr = @rec(node=vecexpr, span=sp);
+ ret sp_vecexpr;
+ }
+
fn make_call(common.span sp, vec[ast.ident] fn_path,
vec[@ast.expr] args) -> @ast.expr {
auto pathexpr = make_path_expr(sp, fn_path);
@@ -149,13 +159,40 @@ fn pieces_to_expr(vec[piece] pieces, vec[@ast.expr] args) -> @ast.expr {
ret vec("std", "ExtFmt", "RT", ident);
}
+ fn make_rt_path_expr(common.span sp, str ident) -> @ast.expr {
+ auto path = make_path_vec(ident);
+ ret make_path_expr(sp, path);
+ }
+
+ // Produces an AST expression that represents a RT.conv record,
+ // which tells the RT.conv* functions how to perform the conversion
fn make_rt_conv_expr(common.span sp, &conv cnv) -> @ast.expr {
+ fn make_flags(common.span sp, vec[flag] flags) -> @ast.expr {
+ let vec[@ast.expr] flagexprs = vec();
+ for (flag f in flags) {
+ alt (f) {
+ case (flag_left_justify) {
+ auto fstr = "flag_left_justify";
+ flagexprs += vec(make_rt_path_expr(sp, fstr));
+ }
+ }
+ }
+
+ // FIXME: 0-length vectors can't have their type inferred
+ // through the rec that these flags are a member of, so
+ // this is a hack placeholder flag
+ if (_vec.len[@ast.expr](flagexprs) == 0u) {
+ flagexprs += vec(make_rt_path_expr(sp, "flag_none"));
+ }
+
+ ret make_vec_expr(sp, flagexprs);
+ }
+
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);
+ ret make_rt_path_expr(sp, "count_implied");
}
case (count_is(?c)) {
auto count_lit = make_new_int(sp, c);
@@ -191,19 +228,23 @@ fn pieces_to_expr(vec[piece] pieces, vec[@ast.expr] args) -> @ast.expr {
}
}
- auto idents = make_path_vec(rt_type);
- ret make_path_expr(sp, idents);
+ ret make_rt_path_expr(sp, rt_type);
}
- fn make_conv_rec(common.span sp, @ast.expr width_expr,
+ fn make_conv_rec(common.span sp,
+ @ast.expr flags_expr,
+ @ast.expr width_expr,
@ast.expr ty_expr) -> @ast.expr {
- ret make_rec_expr(sp, vec(tup("width", width_expr),
+ ret make_rec_expr(sp, vec(tup("flags", flags_expr),
+ tup("width", width_expr),
tup("ty", ty_expr)));
}
+ auto rt_conv_flags = make_flags(sp, cnv.flags);
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_flags,
rt_conv_width,
rt_conv_ty);
}
@@ -230,9 +271,15 @@ fn pieces_to_expr(vec[piece] pieces, vec[@ast.expr] args) -> @ast.expr {
}
}
- if (_vec.len[flag](cnv.flags) != 0u) {
- log unsupported;
- fail;
+ for (flag f in cnv.flags) {
+ alt (f) {
+ case (flag_left_justify) {
+ }
+ case (_) {
+ log unsupported;
+ fail;
+ }
+ }
}
alt (cnv.width) {
diff --git a/src/lib/ExtFmt.rs b/src/lib/ExtFmt.rs
index 1e9c53d9..432e936f 100644
--- a/src/lib/ExtFmt.rs
+++ b/src/lib/ExtFmt.rs
@@ -294,6 +294,14 @@ mod CT {
// implement it this way, I think.
mod RT {
+ tag flag {
+ flag_left_justify;
+ // 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
+ flag_none;
+ }
+
tag count {
count_is(int);
count_implied;
@@ -306,7 +314,10 @@ mod RT {
ty_hex_lower;
}
- type conv = rec(count width,
+ // FIXME: May not want to use a vector here for flags;
+ // instead just use a bool per flag
+ type conv = rec(vec[flag] flags,
+ count width,
ty ty);
fn conv_int(&conv cv, int i) -> str {
@@ -359,18 +370,33 @@ mod RT {
auto strlen = _str.char_len(s);
if (strlen < uwidth) {
auto diff = uwidth - strlen;
- // FIXME: Probably should be a _str fn for this
+ // FIXME: Probably should be a _str fn for
+ // initializing from n chars
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;
+
+ if (have_flag(cv.flags, flag_left_justify)) {
+ ret s + padstr;
+ } else {
+ ret padstr + s;
+ }
} else {
ret s;
}
}
}
}
+
+ fn have_flag(vec[flag] flags, flag f) -> bool {
+ for (flag candidate in flags) {
+ if (candidate == f) {
+ ret true;
+ }
+ }
+ ret false;
+ }
}
// Local Variables:
diff --git a/src/test/run-pass/syntax-extension-fmt.rs b/src/test/run-pass/syntax-extension-fmt.rs
index c4717724..2ffea946 100644
--- a/src/test/run-pass/syntax-extension-fmt.rs
+++ b/src/test/run-pass/syntax-extension-fmt.rs
@@ -43,4 +43,14 @@ fn main() {
test(#fmt("%10x", 0xff_u), " ff");
test(#fmt("%10X", 0xff_u), " FF");
test(#fmt("%10t", 0xff_u), " 11111111");
+
+ // Left justify
+ 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 ");
}