@@ -139,19 +139,17 @@ fn pieces_to_expr(cx: @ext_ctxt, sp: span,
139139 make_conv_struct ( cx, sp, rt_conv_flags, rt_conv_width,
140140 rt_conv_precision, rt_conv_ty)
141141 }
142- fn make_conv_call ( cx : @ext_ctxt , sp : span , conv_type : ~ str , cnv : & Conv ,
143- arg : @ast:: expr ) -> @ast:: expr {
142+ fn make_conv_call ( cx : @ext_ctxt , sp : span , conv_type : & str , cnv : & Conv ,
143+ arg : @ast:: expr , buf : @ast :: expr ) -> @ast:: expr {
144144 let fname = ~"conv_" + conv_type;
145145 let path = make_path_vec ( cx, @fname) ;
146146 let cnv_expr = make_rt_conv_expr ( cx, sp, cnv) ;
147- let args = ~[ cnv_expr, arg] ;
147+ let args = ~[ cnv_expr, arg, buf ] ;
148148 return mk_call_global ( cx, arg. span , path, args) ;
149149 }
150150
151- fn make_new_conv ( cx : @ext_ctxt , sp : span , cnv : & Conv , arg : @ast:: expr ) ->
152- @ast:: expr {
153- // FIXME: Move validation code into core::extfmt (Issue #2249)
154-
151+ fn make_new_conv ( cx : @ext_ctxt , sp : span , cnv : & Conv ,
152+ arg : @ast:: expr , buf : @ast:: expr ) -> @ast:: expr {
155153 fn is_signed_type ( cnv : & Conv ) -> bool {
156154 match cnv. ty {
157155 TyInt ( s) => match s {
@@ -198,27 +196,17 @@ fn pieces_to_expr(cx: @ext_ctxt, sp: span,
198196 CountIs ( _) => ( ) ,
199197 _ => cx. span_unimpl ( sp, unsupported)
200198 }
201- match cnv. ty {
202- TyStr => return make_conv_call ( cx, arg. span , ~"str", cnv, arg) ,
203- TyInt ( sign) => match sign {
204- Signed => return make_conv_call ( cx, arg. span , ~"int", cnv, arg) ,
205- Unsigned => {
206- return make_conv_call ( cx, arg. span , ~"uint", cnv, arg)
207- }
208- } ,
209- TyBool => return make_conv_call ( cx, arg. span , ~"bool", cnv, arg) ,
210- TyChar => return make_conv_call ( cx, arg. span , ~"char", cnv, arg) ,
211- TyHex ( _) => {
212- return make_conv_call ( cx, arg. span , ~"uint", cnv, arg) ;
213- }
214- TyBits => return make_conv_call ( cx, arg. span , ~"uint", cnv, arg) ,
215- TyOctal => return make_conv_call ( cx, arg. span , ~"uint", cnv, arg) ,
216- TyFloat => {
217- return make_conv_call ( cx, arg. span , ~"float", cnv, arg) ;
218- }
219- TyPoly => return make_conv_call ( cx, arg. span , ~"poly", cnv,
220- mk_addr_of ( cx, sp, arg) )
221- }
199+ let ( name, actual_arg) = match cnv. ty {
200+ TyStr => ( "str" , arg) ,
201+ TyInt ( Signed ) => ( "int" , arg) ,
202+ TyBool => ( "bool" , arg) ,
203+ TyChar => ( "char" , arg) ,
204+ TyBits | TyOctal | TyHex ( _) | TyInt ( Unsigned ) => ( "uint" , arg) ,
205+ TyFloat => ( "float" , arg) ,
206+ TyPoly => ( "poly" , mk_addr_of ( cx, sp, arg) )
207+ } ;
208+ return make_conv_call ( cx, arg. span , name, cnv, actual_arg,
209+ mk_mut_addr_of ( cx, arg. span , buf) ) ;
222210 }
223211 fn log_conv ( c : & Conv ) {
224212 debug ! ( "Building conversion:" ) ;
@@ -270,57 +258,70 @@ fn pieces_to_expr(cx: @ext_ctxt, sp: span,
270258 }
271259 }
272260
273- /* Translate each piece (portion of the fmt expression) into a ~str
274- expression to be concatenated below */
275261 let fmt_sp = args[ 0 ] . span ;
276262 let mut n = 0 u;
277263 let nargs = args. len ( ) ;
278- let pieces = do vec:: map_consume ( pieces) |pc| {
264+
265+ /* 'ident' is the local buffer building up the result of fmt! */
266+ let ident = cx. parse_sess ( ) . interner . intern ( @~"__fmtbuf") ;
267+ let buf = || mk_path ( cx, fmt_sp, ~[ ident] ) ;
268+ let str_ident = cx. parse_sess ( ) . interner . intern ( @~"str") ;
269+ let push_ident = cx. parse_sess ( ) . interner . intern ( @~"push_str") ;
270+ let mut stms = ~[ ] ;
271+
272+ /* Translate each piece (portion of the fmt expression) by invoking the
273+ corresponding function in core::unstable::extfmt. Each function takes a
274+ buffer to insert data into along with the data being formatted. */
275+ do vec:: consume ( pieces) |i, pc| {
279276 match pc {
280- PieceString ( s) => mk_uniq_str ( cx, fmt_sp, s) ,
277+ /* Raw strings get appended via str::push_str */
278+ PieceString ( s) => {
279+ let portion = mk_uniq_str ( cx, fmt_sp, s) ;
280+
281+ /* If this is the first portion, then initialize the local
282+ buffer with it directly */
283+ if i == 0 {
284+ stms. push ( mk_local ( cx, fmt_sp, true , ident, portion) ) ;
285+ } else {
286+ let args = ~[ mk_mut_addr_of ( cx, fmt_sp, buf ( ) ) , portion] ;
287+ let call = mk_call_global ( cx,
288+ fmt_sp,
289+ ~[ str_ident, push_ident] ,
290+ args) ;
291+ stms. push ( mk_stmt ( cx, fmt_sp, call) ) ;
292+ }
293+ }
294+
295+ /* Invoke the correct conv function in extfmt */
281296 PieceConv ( ref conv) => {
282297 n += 1 u;
283298 if n >= nargs {
284299 cx. span_fatal ( sp,
285300 ~"not enough arguments to fmt! " +
286301 ~" for the given format string") ;
287302 }
303+
288304 log_conv( conv) ;
289- make_new_conv( cx, fmt_sp, conv, args[ n] )
305+ /* If the first portion is a conversion, then the local buffer
306+ must be initialized as an empty string */
307+ if i == 0 {
308+ stms. push ( mk_local ( cx, fmt_sp, true , ident,
309+ mk_uniq_str ( cx, fmt_sp, ~"") ) ) ;
310+ }
311+ stms. push ( mk_stmt ( cx, fmt_sp,
312+ make_new_conv ( cx, fmt_sp, conv,
313+ args[ n] , buf ( ) ) ) ) ;
290314 }
291315 }
292- } ;
316+ }
317+
293318 let expected_nargs = n + 1 u; // n conversions + the fmt string
294319 if expected_nargs < nargs {
295320 cx. span_fatal
296321 ( sp, fmt ! ( "too many arguments to fmt!. found %u, expected %u" ,
297322 nargs, expected_nargs) ) ;
298323 }
299324
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-
324325 return mk_block( cx, fmt_sp, ~[ ] , stms, Some ( buf ( ) ) ) ;
325326}
326327//
0 commit comments