@@ -221,6 +221,7 @@ fn pieces_to_expr(cx: @ext_ctxt, sp: span,
221
221
}
222
222
}
223
223
fn log_conv ( c : & Conv ) {
224
+ debug ! ( "Building conversion:" ) ;
224
225
match c. param {
225
226
Some ( p) => { debug ! ( "param: %s" , p. to_str( ) ) ; }
226
227
_ => debug ! ( "param: none" )
@@ -268,49 +269,59 @@ fn pieces_to_expr(cx: @ext_ctxt, sp: span,
268
269
TyPoly => debug ! ( "type: poly" )
269
270
}
270
271
}
272
+
273
+ /* Translate each piece (portion of the fmt expression) into a ~str
274
+ expression to be concatenated below */
271
275
let fmt_sp = args[ 0 ] . span ;
272
276
let mut n = 0 u;
273
- let mut piece_exprs = ~[ ] ;
274
277
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! " +
285
286
~" for the given format string") ;
287
+ }
288
+ log_conv( conv) ;
289
+ make_new_conv( cx, fmt_sp, conv, args[ n] )
286
290
}
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
- }
298
291
}
299
- }
292
+ } ;
300
293
let expected_nargs = n + 1 u; // n conversions + the fmt string
301
-
302
294
if expected_nargs < nargs {
303
295
cx. span_fatal
304
296
( sp, fmt ! ( "too many arguments to fmt!. found %u, expected %u" ,
305
297
nargs, expected_nargs) ) ;
306
298
}
307
299
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 ( ) ) ) ;
314
325
}
315
326
//
316
327
// Local Variables:
0 commit comments