@@ -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 = 0 u;
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 += 1 u;
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 += 1 u;
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 + 1 u; // 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