@@ -139,19 +139,17 @@ fn pieces_to_expr(cx: @ext_ctxt, sp: span,
139
139
make_conv_struct ( cx, sp, rt_conv_flags, rt_conv_width,
140
140
rt_conv_precision, rt_conv_ty)
141
141
}
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 {
144
144
let fname = ~"conv_" + conv_type;
145
145
let path = make_path_vec ( cx, @fname) ;
146
146
let cnv_expr = make_rt_conv_expr ( cx, sp, cnv) ;
147
- let args = ~[ cnv_expr, arg] ;
147
+ let args = ~[ cnv_expr, arg, buf ] ;
148
148
return mk_call_global ( cx, arg. span , path, args) ;
149
149
}
150
150
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 {
155
153
fn is_signed_type ( cnv : & Conv ) -> bool {
156
154
match cnv. ty {
157
155
TyInt ( s) => match s {
@@ -198,27 +196,17 @@ fn pieces_to_expr(cx: @ext_ctxt, sp: span,
198
196
CountIs ( _) => ( ) ,
199
197
_ => cx. span_unimpl ( sp, unsupported)
200
198
}
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) ) ;
222
210
}
223
211
fn log_conv ( c : & Conv ) {
224
212
debug ! ( "Building conversion:" ) ;
@@ -270,57 +258,70 @@ fn pieces_to_expr(cx: @ext_ctxt, sp: span,
270
258
}
271
259
}
272
260
273
- /* Translate each piece (portion of the fmt expression) into a ~str
274
- expression to be concatenated below */
275
261
let fmt_sp = args[ 0 ] . span ;
276
262
let mut n = 0 u;
277
263
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| {
279
276
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 */
281
296
PieceConv ( ref conv) => {
282
297
n += 1 u;
283
298
if n >= nargs {
284
299
cx. span_fatal ( sp,
285
300
~"not enough arguments to fmt! " +
286
301
~" for the given format string") ;
287
302
}
303
+
288
304
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 ( ) ) ) ) ;
290
314
}
291
315
}
292
- } ;
316
+ }
317
+
293
318
let expected_nargs = n + 1 u; // n conversions + the fmt string
294
319
if expected_nargs < nargs {
295
320
cx. span_fatal
296
321
( sp, fmt ! ( "too many arguments to fmt!. found %u, expected %u" ,
297
322
nargs, expected_nargs) ) ;
298
323
}
299
324
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
325
return mk_block( cx, fmt_sp, ~[ ] , stms, Some ( buf ( ) ) ) ;
325
326
}
326
327
//
0 commit comments