Skip to content

Commit 1a0d212

Browse files
committed
Build up the result of fmt! in a buffer instead of a vector
1 parent d700500 commit 1a0d212

File tree

2 files changed

+44
-30
lines changed

2 files changed

+44
-30
lines changed

src/libsyntax/ext/build.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ pub fn mk_access(cx: @ext_ctxt, sp: span, +p: ~[ast::ident], m: ast::ident)
108108
pub fn mk_addr_of(cx: @ext_ctxt, sp: span, e: @ast::expr) -> @ast::expr {
109109
return mk_expr(cx, sp, ast::expr_addr_of(ast::m_imm, e));
110110
}
111+
pub fn mk_mut_addr_of(cx: @ext_ctxt, sp: span, e: @ast::expr) -> @ast::expr {
112+
return mk_expr(cx, sp, ast::expr_addr_of(ast::m_mutbl, e));
113+
}
111114
pub fn mk_call_(cx: @ext_ctxt, sp: span, fn_expr: @ast::expr,
112115
+args: ~[@ast::expr]) -> @ast::expr {
113116
mk_expr(cx, sp, ast::expr_call(fn_expr, args, ast::NoSugar))

src/libsyntax/ext/fmt.rs

Lines changed: 41 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ fn pieces_to_expr(cx: @ext_ctxt, sp: span,
221221
}
222222
}
223223
fn log_conv(c: &Conv) {
224+
debug!("Building conversion:");
224225
match c.param {
225226
Some(p) => { debug!("param: %s", p.to_str()); }
226227
_ => debug!("param: none")
@@ -268,49 +269,59 @@ fn pieces_to_expr(cx: @ext_ctxt, sp: span,
268269
TyPoly => debug!("type: poly")
269270
}
270271
}
272+
273+
/* Translate each piece (portion of the fmt expression) into a ~str
274+
expression to be concatenated below */
271275
let fmt_sp = args[0].span;
272276
let mut n = 0u;
273-
let mut piece_exprs = ~[];
274277
let nargs = args.len();
275-
for pieces.each |pc| {
276-
match *pc {
277-
PieceString(ref s) => {
278-
piece_exprs.push(mk_uniq_str(cx, fmt_sp, copy *s))
279-
}
280-
PieceConv(ref conv) => {
281-
n += 1u;
282-
if n >= nargs {
283-
cx.span_fatal(sp,
284-
~"not enough arguments to fmt! " +
278+
let pieces = do vec::map_consume(pieces) |pc| {
279+
match pc {
280+
PieceString(s) => mk_uniq_str(cx, fmt_sp, s),
281+
PieceConv(ref conv) => {
282+
n += 1u;
283+
if n >= nargs {
284+
cx.span_fatal(sp,
285+
~"not enough arguments to fmt! " +
285286
~"for the given format string");
287+
}
288+
log_conv(conv);
289+
make_new_conv(cx, fmt_sp, conv, args[n])
286290
}
287-
debug!("Building conversion:");
288-
log_conv(conv);
289-
let arg_expr = args[n];
290-
let c_expr = make_new_conv(
291-
cx,
292-
fmt_sp,
293-
conv,
294-
arg_expr
295-
);
296-
piece_exprs.push(c_expr);
297-
}
298291
}
299-
}
292+
};
300293
let expected_nargs = n + 1u; // n conversions + the fmt string
301-
302294
if expected_nargs < nargs {
303295
cx.span_fatal
304296
(sp, fmt!("too many arguments to fmt!. found %u, expected %u",
305297
nargs, expected_nargs));
306298
}
307299

308-
let arg_vec = mk_fixed_vec_e(cx, fmt_sp, piece_exprs);
309-
return mk_call_global(cx,
310-
fmt_sp,
311-
~[cx.parse_sess().interner.intern(@~"str"),
312-
cx.parse_sess().interner.intern(@~"concat")],
313-
~[arg_vec]);
300+
/* Concatenate all of the strings together with str::push_str. This
301+
involves storing the first piece into a local variable, and then
302+
pushing each other piece onto the local. The local is contained in its
303+
own block to not conflict with other names as much as possible */
304+
let ident = cx.parse_sess().interner.intern(@~"__fmtbuf");
305+
let buf = || mk_path(cx, fmt_sp, ~[ident]);
306+
let str_ident = cx.parse_sess().interner.intern(@~"str");
307+
let push_ident = cx.parse_sess().interner.intern(@~"push_str");
308+
309+
let mut first = true;
310+
let stms = do vec::map_consume(pieces) |pc| {
311+
if first {
312+
first = false;
313+
mk_local(cx, fmt_sp, true, ident, pc)
314+
} else {
315+
let call = mk_call_global(cx,
316+
fmt_sp,
317+
~[str_ident, push_ident],
318+
~[mk_mut_addr_of(cx, fmt_sp, buf()),
319+
pc]);
320+
mk_stmt(cx, fmt_sp, call)
321+
}
322+
};
323+
324+
return mk_block(cx, fmt_sp, ~[], stms, Some(buf()));
314325
}
315326
//
316327
// Local Variables:

0 commit comments

Comments
 (0)