@@ -56,6 +56,9 @@ struct Context<'a, 'b:'a> {
56
56
pieces : Vec < Gc < ast:: Expr > > ,
57
57
/// Collection of string literals
58
58
str_pieces : Vec < Gc < ast:: Expr > > ,
59
+ /// Stays `true` if all formatting parameters are default (as in "{}{}").
60
+ all_pieces_simple : bool ,
61
+
59
62
name_positions : HashMap < String , uint > ,
60
63
method_statics : Vec < Gc < ast:: Item > > ,
61
64
@@ -383,7 +386,6 @@ impl<'a, 'b> Context<'a, 'b> {
383
386
/// Translate a `parse::Piece` to a static `rt::Argument` or append
384
387
/// to the `literal` string.
385
388
fn trans_piece ( & mut self , piece : & parse:: Piece ) -> Option < Gc < ast:: Expr > > {
386
- // let mut is_not_default = true;
387
389
let sp = self . fmtsp ;
388
390
match * piece {
389
391
parse:: String ( s) => {
@@ -416,8 +418,25 @@ impl<'a, 'b> Context<'a, 'b> {
416
418
}
417
419
} ;
418
420
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
+
420
433
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
421
440
let fill = self . ecx . expr_lit ( sp, ast:: LitChar ( fill) ) ;
422
441
let align = match arg. format . align {
423
442
parse:: AlignLeft => {
@@ -453,6 +472,26 @@ impl<'a, 'b> Context<'a, 'b> {
453
472
}
454
473
}
455
474
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
+
456
495
/// Actually builds the expression which the iformat! block will be expanded
457
496
/// to
458
497
fn to_expr ( & self , invocation : Invocation ) -> Gc < ast:: Expr > {
@@ -471,54 +510,31 @@ impl<'a, 'b> Context<'a, 'b> {
471
510
472
511
// Next, build up the static array which will become our precompiled
473
512
// 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
513
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 (
500
516
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.
516
526
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
+ }
522
538
523
539
// Right now there is a bug such that for the expression:
524
540
// foo(bar(&1))
@@ -565,13 +581,20 @@ impl<'a, 'b> Context<'a, 'b> {
565
581
566
582
// Now create the fmt::Arguments struct with all our locals we created.
567
583
let pieces = self . ecx . expr_ident ( self . fmtsp , static_str_name) ;
568
- let fmt = self . ecx . expr_ident ( self . fmtsp , static_args_name) ;
569
584
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
+
570
593
let result = self . ecx . expr_call_global ( self . fmtsp , vec ! (
571
594
self . ecx. ident_of( "std" ) ,
572
595
self . ecx. ident_of( "fmt" ) ,
573
596
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 ) ;
575
598
576
599
// We did all the work of making sure that the arguments
577
600
// 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,
741
764
literal : String :: new ( ) ,
742
765
pieces : Vec :: new ( ) ,
743
766
str_pieces : Vec :: new ( ) ,
767
+ all_pieces_simple : true ,
744
768
method_statics : Vec :: new ( ) ,
745
769
fmtsp : sp,
746
770
} ;
0 commit comments