@@ -56,6 +56,9 @@ struct Context<'a, 'b:'a> {
5656 pieces : Vec < Gc < ast:: Expr > > ,
5757 /// Collection of string literals
5858 str_pieces : Vec < Gc < ast:: Expr > > ,
59+ /// Stays `true` if all formatting parameters are default (as in "{}{}").
60+ all_pieces_simple : bool ,
61+
5962 name_positions : HashMap < String , uint > ,
6063 method_statics : Vec < Gc < ast:: Item > > ,
6164
@@ -383,7 +386,6 @@ impl<'a, 'b> Context<'a, 'b> {
383386 /// Translate a `parse::Piece` to a static `rt::Argument` or append
384387 /// to the `literal` string.
385388 fn trans_piece ( & mut self , piece : & parse:: Piece ) -> Option < Gc < ast:: Expr > > {
386- // let mut is_not_default = true;
387389 let sp = self . fmtsp ;
388390 match * piece {
389391 parse:: String ( s) => {
@@ -416,8 +418,25 @@ impl<'a, 'b> Context<'a, 'b> {
416418 }
417419 } ;
418420
419- // Translate the format
421+ let simple_arg = parse:: Argument {
422+ position : parse:: ArgumentNext ,
423+ format : parse:: FormatSpec {
424+ fill : arg. format . fill ,
425+ align : parse:: AlignUnknown ,
426+ flags : 0 ,
427+ precision : parse:: CountImplied ,
428+ width : parse:: CountImplied ,
429+ ty : arg. format . ty
430+ }
431+ } ;
432+
420433 let fill = match arg. format . fill { Some ( c) => c, None => ' ' } ;
434+
435+ if * arg != simple_arg || fill != ' ' {
436+ self . all_pieces_simple = false ;
437+ }
438+
439+ // Translate the format
421440 let fill = self . ecx . expr_lit ( sp, ast:: LitChar ( fill) ) ;
422441 let align = match arg. format . align {
423442 parse:: AlignLeft => {
@@ -453,6 +472,26 @@ impl<'a, 'b> Context<'a, 'b> {
453472 }
454473 }
455474
475+ fn item_static_array ( & self ,
476+ name : ast:: Ident ,
477+ piece_ty : Gc < ast:: Ty > ,
478+ pieces : Vec < Gc < ast:: Expr > > )
479+ -> ast:: Stmt
480+ {
481+ let pieces_len = self . ecx . expr_uint ( self . fmtsp , pieces. len ( ) ) ;
482+ let fmt = self . ecx . expr_vec ( self . fmtsp , pieces) ;
483+ let ty = ast:: TyFixedLengthVec (
484+ piece_ty,
485+ pieces_len
486+ ) ;
487+ let ty = self . ecx . ty ( self . fmtsp , ty) ;
488+ let st = ast:: ItemStatic ( ty, ast:: MutImmutable , fmt) ;
489+ let item = self . ecx . item ( self . fmtsp , name,
490+ self . static_attrs ( ) , st) ;
491+ let decl = respan ( self . fmtsp , ast:: DeclItem ( item) ) ;
492+ respan ( self . fmtsp , ast:: StmtDecl ( box ( GC ) decl, ast:: DUMMY_NODE_ID ) )
493+ }
494+
456495 /// Actually builds the expression which the iformat! block will be expanded
457496 /// to
458497 fn to_expr ( & self , invocation : Invocation ) -> Gc < ast:: Expr > {
@@ -471,54 +510,31 @@ impl<'a, 'b> Context<'a, 'b> {
471510
472511 // Next, build up the static array which will become our precompiled
473512 // format "string"
474- let fmt = self . ecx . expr_vec ( self . fmtsp , self . str_pieces . clone ( ) ) ;
475- let piece_ty = self . ecx . ty_rptr ( self . fmtsp ,
476- self . ecx . ty_ident ( self . fmtsp ,
477- self . ecx . ident_of ( "str" ) ) ,
478- Some ( self . ecx . lifetime ( self . fmtsp ,
479- self . ecx . ident_of (
480- "'static" ) . name ) ) ,
481- ast:: MutImmutable ) ;
482-
483- let ty = ast:: TyFixedLengthVec (
484- piece_ty,
485- self . ecx . expr_uint ( self . fmtsp , self . str_pieces . len ( ) )
486- ) ;
487- let ty = self . ecx . ty ( self . fmtsp , ty) ;
488- let st = ast:: ItemStatic ( ty, ast:: MutImmutable , fmt) ;
489513 let static_str_name = self . ecx . ident_of ( "__STATIC_FMTSTR" ) ;
490- let item = self . ecx . item ( self . fmtsp , static_str_name,
491- self . static_attrs ( ) , st) ;
492- let decl = respan ( self . fmtsp , ast:: DeclItem ( item) ) ;
493- lets. push ( box ( GC ) respan( self . fmtsp ,
494- ast:: StmtDecl ( box ( GC ) decl, ast:: DUMMY_NODE_ID ) ) ) ;
495-
496- // Then, build up the static array which will become our precompiled
497- // format "string"
498- let fmt = self . ecx . expr_vec ( self . fmtsp , self . pieces . clone ( ) ) ;
499- let piece_ty = self . ecx . ty_path ( self . ecx . path_all (
514+ let static_lifetime = self . ecx . lifetime ( self . fmtsp , self . ecx . ident_of ( "'static" ) . name ) ;
515+ let piece_ty = self . ecx . ty_rptr (
500516 self . fmtsp ,
501- true , vec ! (
502- self . ecx. ident_of( "std" ) ,
503- self . ecx. ident_of( "fmt" ) ,
504- self . ecx. ident_of( "rt" ) ,
505- self . ecx. ident_of( "Argument" ) ) ,
506- vec ! ( self . ecx. lifetime( self . fmtsp,
507- self . ecx. ident_of( "'static" ) . name) ) ,
508- Vec :: new ( )
509- ) , None ) ;
510- let ty = ast:: TyFixedLengthVec (
511- piece_ty,
512- self . ecx . expr_uint ( self . fmtsp , self . pieces . len ( ) )
513- ) ;
514- let ty = self . ecx . ty ( self . fmtsp , ty) ;
515- let st = ast:: ItemStatic ( ty, ast:: MutImmutable , fmt) ;
517+ self . ecx . ty_ident ( self . fmtsp , self . ecx . ident_of ( "str" ) ) ,
518+ Some ( static_lifetime) ,
519+ ast:: MutImmutable ) ;
520+ lets. push ( box ( GC ) self. item_static_array ( static_str_name,
521+ piece_ty,
522+ self . str_pieces . clone ( ) ) ) ;
523+
524+ // Then, build up the static array which will store our precompiled
525+ // nonstandard placeholders, if there are any.
516526 let static_args_name = self . ecx . ident_of ( "__STATIC_FMTARGS" ) ;
517- let item = self . ecx . item ( self . fmtsp , static_args_name,
518- self . static_attrs ( ) , st) ;
519- let decl = respan ( self . fmtsp , ast:: DeclItem ( item) ) ;
520- lets. push ( box ( GC ) respan( self . fmtsp ,
521- ast:: StmtDecl ( box ( GC ) decl, ast:: DUMMY_NODE_ID ) ) ) ;
527+ if !self . all_pieces_simple {
528+ let piece_ty = self . ecx . ty_path ( self . ecx . path_all (
529+ self . fmtsp ,
530+ true , self . rtpath ( "Argument" ) ,
531+ vec ! [ static_lifetime] ,
532+ vec ! [ ]
533+ ) , None ) ;
534+ lets. push ( box ( GC ) self. item_static_array ( static_args_name,
535+ piece_ty,
536+ self . pieces . clone ( ) ) ) ;
537+ }
522538
523539 // Right now there is a bug such that for the expression:
524540 // foo(bar(&1))
@@ -565,13 +581,20 @@ impl<'a, 'b> Context<'a, 'b> {
565581
566582 // Now create the fmt::Arguments struct with all our locals we created.
567583 let pieces = self . ecx . expr_ident ( self . fmtsp , static_str_name) ;
568- let fmt = self . ecx . expr_ident ( self . fmtsp , static_args_name) ;
569584 let args_slice = self . ecx . expr_ident ( self . fmtsp , slicename) ;
585+
586+ let ( fn_name, fn_args) = if self . all_pieces_simple {
587+ ( "new" , vec ! [ pieces, args_slice] )
588+ } else {
589+ let fmt = self . ecx . expr_ident ( self . fmtsp , static_args_name) ;
590+ ( "with_placeholders" , vec ! [ pieces, fmt, args_slice] )
591+ } ;
592+
570593 let result = self . ecx . expr_call_global ( self . fmtsp , vec ! (
571594 self . ecx. ident_of( "std" ) ,
572595 self . ecx. ident_of( "fmt" ) ,
573596 self . ecx. ident_of( "Arguments" ) ,
574- self . ecx. ident_of( "new" ) ) , vec ! ( pieces , fmt , args_slice ) ) ;
597+ self . ecx. ident_of( fn_name ) ) , fn_args ) ;
575598
576599 // We did all the work of making sure that the arguments
577600 // structure is safe, so we can safely have an unsafe block.
@@ -741,6 +764,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
741764 literal : String :: new ( ) ,
742765 pieces : Vec :: new ( ) ,
743766 str_pieces : Vec :: new ( ) ,
767+ all_pieces_simple : true ,
744768 method_statics : Vec :: new ( ) ,
745769 fmtsp : sp,
746770 } ;
0 commit comments