@@ -49,11 +49,13 @@ struct Context<'a, 'b:'a> {
4949 name_types : HashMap < String , ArgumentType > ,
5050 name_ordering : Vec < String > ,
5151
52- /// The latest consecutive literal strings
53- literal : Option < String > ,
52+ /// The latest consecutive literal strings, or empty if there weren't any.
53+ literal : String ,
5454
55- /// Collection of the compiled `rt::Piece ` structures
55+ /// Collection of the compiled `rt::Argument ` structures
5656 pieces : Vec < Gc < ast:: Expr > > ,
57+ /// Collection of string literals
58+ str_pieces : Vec < Gc < ast:: Expr > > ,
5759 name_positions : HashMap < String , uint > ,
5860 method_statics : Vec < Gc < ast:: Item > > ,
5961
@@ -370,28 +372,22 @@ impl<'a, 'b> Context<'a, 'b> {
370372 }
371373 }
372374
373- /// Translate the accumulated string literals to a static `rt::Piece`
374- fn trans_literal_string ( & mut self ) -> Option < Gc < ast:: Expr > > {
375+ /// Translate the accumulated string literals to a literal expression
376+ fn trans_literal_string ( & mut self ) -> Gc < ast:: Expr > {
375377 let sp = self . fmtsp ;
376- self . literal . take ( ) . map ( |s| {
377- let s = token:: intern_and_get_ident ( s. as_slice ( ) ) ;
378- self . ecx . expr_call_global ( sp,
379- self . rtpath ( "String" ) ,
380- vec ! (
381- self . ecx. expr_str( sp, s)
382- ) )
383- } )
378+ let s = token:: intern_and_get_ident ( self . literal . as_slice ( ) ) ;
379+ self . literal . clear ( ) ;
380+ self . ecx . expr_str ( sp, s)
384381 }
385382
386- /// Translate a `parse::Piece` to a static `rt::Piece`
383+ /// Translate a `parse::Piece` to a static `rt::Argument` or append
384+ /// to the `literal` string.
387385 fn trans_piece ( & mut self , piece : & parse:: Piece ) -> Option < Gc < ast:: Expr > > {
386+ // let mut is_not_default = true;
388387 let sp = self . fmtsp ;
389388 match * piece {
390389 parse:: String ( s) => {
391- match self . literal {
392- Some ( ref mut sb) => sb. push_str ( s) ,
393- ref mut empty => * empty = Some ( String :: from_str ( s) ) ,
394- }
390+ self . literal . push_str ( s) ;
395391 None
396392 }
397393 parse:: Argument ( ref arg) => {
@@ -450,10 +446,9 @@ impl<'a, 'b> Context<'a, 'b> {
450446 self . ecx. field_imm( sp, self . ecx. ident_of( "width" ) , width) ) ) ;
451447
452448 let path = self . ecx . path_global ( sp, self . rtpath ( "Argument" ) ) ;
453- let s = self . ecx . expr_struct ( sp, path, vec ! (
449+ Some ( self . ecx . expr_struct ( sp, path, vec ! (
454450 self . ecx. field_imm( sp, self . ecx. ident_of( "position" ) , pos) ,
455- self . ecx. field_imm( sp, self . ecx. ident_of( "format" ) , fmt) ) ) ;
456- Some ( self . ecx . expr_call_global ( sp, self . rtpath ( "Argument" ) , vec ! ( s) ) )
451+ self . ecx. field_imm( sp, self . ecx. ident_of( "format" ) , fmt) ) ) )
457452 }
458453 }
459454 }
@@ -476,14 +471,38 @@ impl<'a, 'b> Context<'a, 'b> {
476471
477472 // Next, build up the static array which will become our precompiled
478473 // 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) ;
489+ 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"
479498 let fmt = self . ecx . expr_vec ( self . fmtsp , self . pieces . clone ( ) ) ;
480499 let piece_ty = self . ecx . ty_path ( self . ecx . path_all (
481500 self . fmtsp ,
482501 true , vec ! (
483502 self . ecx. ident_of( "std" ) ,
484503 self . ecx. ident_of( "fmt" ) ,
485504 self . ecx. ident_of( "rt" ) ,
486- self . ecx. ident_of( "Piece " ) ) ,
505+ self . ecx. ident_of( "Argument " ) ) ,
487506 vec ! ( self . ecx. lifetime( self . fmtsp,
488507 self . ecx. ident_of( "'static" ) . name) ) ,
489508 Vec :: new ( )
@@ -494,8 +513,8 @@ impl<'a, 'b> Context<'a, 'b> {
494513 ) ;
495514 let ty = self . ecx . ty ( self . fmtsp , ty) ;
496515 let st = ast:: ItemStatic ( ty, ast:: MutImmutable , fmt) ;
497- let static_name = self . ecx . ident_of ( "__STATIC_FMTSTR " ) ;
498- let item = self . ecx . item ( self . fmtsp , static_name ,
516+ let static_args_name = self . ecx . ident_of ( "__STATIC_FMTARGS " ) ;
517+ let item = self . ecx . item ( self . fmtsp , static_args_name ,
499518 self . static_attrs ( ) , st) ;
500519 let decl = respan ( self . fmtsp , ast:: DeclItem ( item) ) ;
501520 lets. push ( box ( GC ) respan( self . fmtsp ,
@@ -545,13 +564,14 @@ impl<'a, 'b> Context<'a, 'b> {
545564 }
546565
547566 // Now create the fmt::Arguments struct with all our locals we created.
548- let fmt = self . ecx . expr_ident ( self . fmtsp , static_name) ;
567+ let pieces = self . ecx . expr_ident ( self . fmtsp , static_str_name) ;
568+ let fmt = self . ecx . expr_ident ( self . fmtsp , static_args_name) ;
549569 let args_slice = self . ecx . expr_ident ( self . fmtsp , slicename) ;
550570 let result = self . ecx . expr_call_global ( self . fmtsp , vec ! (
551571 self . ecx. ident_of( "std" ) ,
552572 self . ecx. ident_of( "fmt" ) ,
553573 self . ecx. ident_of( "Arguments" ) ,
554- self . ecx. ident_of( "new" ) ) , vec ! ( fmt, args_slice) ) ;
574+ self . ecx. ident_of( "new" ) ) , vec ! ( pieces , fmt, args_slice) ) ;
555575
556576 // We did all the work of making sure that the arguments
557577 // structure is safe, so we can safely have an unsafe block.
@@ -718,8 +738,9 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
718738 name_ordering : name_ordering,
719739 nest_level : 0 ,
720740 next_arg : 0 ,
721- literal : None ,
741+ literal : String :: new ( ) ,
722742 pieces : Vec :: new ( ) ,
743+ str_pieces : Vec :: new ( ) ,
723744 method_statics : Vec :: new ( ) ,
724745 fmtsp : sp,
725746 } ;
@@ -739,8 +760,8 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
739760 cx. verify_piece ( & piece) ;
740761 match cx. trans_piece ( & piece) {
741762 Some ( piece) => {
742- cx. trans_literal_string ( ) . map ( |piece|
743- cx. pieces . push ( piece ) ) ;
763+ let s = cx. trans_literal_string ( ) ;
764+ cx. str_pieces . push ( s ) ;
744765 cx. pieces . push ( piece) ;
745766 }
746767 None => { }
@@ -758,7 +779,10 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
758779 }
759780 None => { }
760781 }
761- cx. trans_literal_string ( ) . map ( |piece| cx. pieces . push ( piece) ) ;
782+ if !cx. literal . is_empty ( ) {
783+ let s = cx. trans_literal_string ( ) ;
784+ cx. str_pieces . push ( s) ;
785+ }
762786
763787 // Make sure that all arguments were used and all arguments have types.
764788 for ( i, ty) in cx. arg_types . iter ( ) . enumerate ( ) {
0 commit comments