about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-03-20 13:01:58 -0400
committerAlex Crichton <alex@alexcrichton.com>2013-03-22 11:49:45 -0400
commit1a0d212dd94c5d6c62d1cc2939da8ae2c895b65f (patch)
treea0304a11593b116c11095d84f5dd7f9be4ec37cf /src/libsyntax
parentd700500d0cc506f34dccdb8379cc1102becfd24f (diff)
downloadrust-1a0d212dd94c5d6c62d1cc2939da8ae2c895b65f.tar.gz
rust-1a0d212dd94c5d6c62d1cc2939da8ae2c895b65f.zip
Build up the result of fmt! in a buffer instead of a vector
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ext/build.rs3
-rw-r--r--src/libsyntax/ext/fmt.rs71
2 files changed, 44 insertions, 30 deletions
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 18c7cd3f861..c2f4cbf3db2 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -108,6 +108,9 @@ pub fn mk_access(cx: @ext_ctxt, sp: span, +p: ~[ast::ident], m: ast::ident)
 pub fn mk_addr_of(cx: @ext_ctxt, sp: span, e: @ast::expr) -> @ast::expr {
     return mk_expr(cx, sp, ast::expr_addr_of(ast::m_imm, e));
 }
+pub fn mk_mut_addr_of(cx: @ext_ctxt, sp: span, e: @ast::expr) -> @ast::expr {
+    return mk_expr(cx, sp, ast::expr_addr_of(ast::m_mutbl, e));
+}
 pub fn mk_call_(cx: @ext_ctxt, sp: span, fn_expr: @ast::expr,
                 +args: ~[@ast::expr]) -> @ast::expr {
     mk_expr(cx, sp, ast::expr_call(fn_expr, args, ast::NoSugar))
diff --git a/src/libsyntax/ext/fmt.rs b/src/libsyntax/ext/fmt.rs
index 9973c9558c9..4c7dd454983 100644
--- a/src/libsyntax/ext/fmt.rs
+++ b/src/libsyntax/ext/fmt.rs
@@ -221,6 +221,7 @@ fn pieces_to_expr(cx: @ext_ctxt, sp: span,
         }
     }
     fn log_conv(c: &Conv) {
+        debug!("Building conversion:");
         match c.param {
           Some(p) => { debug!("param: %s", p.to_str()); }
           _ => debug!("param: none")
@@ -268,49 +269,59 @@ fn pieces_to_expr(cx: @ext_ctxt, sp: span,
           TyPoly => debug!("type: poly")
         }
     }
+
+    /* Translate each piece (portion of the fmt expression) into a ~str
+       expression to be concatenated below */
     let fmt_sp = args[0].span;
     let mut n = 0u;
-    let mut piece_exprs = ~[];
     let nargs = args.len();
-    for pieces.each |pc| {
-        match *pc {
-          PieceString(ref s) => {
-            piece_exprs.push(mk_uniq_str(cx, fmt_sp, copy *s))
-          }
-          PieceConv(ref conv) => {
-            n += 1u;
-            if n >= nargs {
-                cx.span_fatal(sp,
-                              ~"not enough arguments to fmt! " +
+    let pieces = do vec::map_consume(pieces) |pc| {
+        match pc {
+            PieceString(s) => mk_uniq_str(cx, fmt_sp, s),
+            PieceConv(ref conv) => {
+                n += 1u;
+                if n >= nargs {
+                    cx.span_fatal(sp,
+                                  ~"not enough arguments to fmt! " +
                                   ~"for the given format string");
+                }
+                log_conv(conv);
+                make_new_conv(cx, fmt_sp, conv, args[n])
             }
-            debug!("Building conversion:");
-            log_conv(conv);
-            let arg_expr = args[n];
-            let c_expr = make_new_conv(
-                cx,
-                fmt_sp,
-                conv,
-                arg_expr
-            );
-            piece_exprs.push(c_expr);
-          }
         }
-    }
+    };
     let expected_nargs = n + 1u; // n conversions + the fmt string
-
     if expected_nargs < nargs {
         cx.span_fatal
             (sp, fmt!("too many arguments to fmt!. found %u, expected %u",
                            nargs, expected_nargs));
     }
 
-    let arg_vec = mk_fixed_vec_e(cx, fmt_sp, piece_exprs);
-    return mk_call_global(cx,
-                          fmt_sp,
-                          ~[cx.parse_sess().interner.intern(@~"str"),
-                            cx.parse_sess().interner.intern(@~"concat")],
-                          ~[arg_vec]);
+    /* Concatenate all of the strings together with str::push_str. This
+       involves storing the first piece into a local variable, and then
+       pushing each other piece onto the local. The local is contained in its
+       own block to not conflict with other names as much as possible */
+    let ident = cx.parse_sess().interner.intern(@~"__fmtbuf");
+    let buf = || mk_path(cx, fmt_sp, ~[ident]);
+    let str_ident = cx.parse_sess().interner.intern(@~"str");
+    let push_ident = cx.parse_sess().interner.intern(@~"push_str");
+
+    let mut first = true;
+    let stms = do vec::map_consume(pieces) |pc| {
+        if first {
+            first = false;
+            mk_local(cx, fmt_sp, true, ident, pc)
+        } else {
+            let call = mk_call_global(cx,
+                                      fmt_sp,
+                                      ~[str_ident, push_ident],
+                                      ~[mk_mut_addr_of(cx, fmt_sp, buf()),
+                                        pc]);
+            mk_stmt(cx, fmt_sp, call)
+        }
+    };
+
+    return mk_block(cx, fmt_sp, ~[], stms, Some(buf()));
 }
 //
 // Local Variables: