@@ -46,15 +46,12 @@ struct Context<'a, 'b:'a> {
46
46
47
47
/// Parsed argument expressions and the types that we've found so far for
48
48
/// them.
49
+ /// Named expressions are resolved early, and are appended to the end of
50
+ /// argument expressions.
49
51
args : Vec < P < ast:: Expr > > ,
50
52
arg_types : Vec < Option < ArgumentType > > ,
51
- /// Parsed named expressions and the types that we've found for them so far.
52
- /// Note that we keep a side-array of the ordering of the named arguments
53
- /// found to be sure that we can translate them in the same order that they
54
- /// were declared in.
55
- names : HashMap < String , P < ast:: Expr > > ,
56
- name_types : HashMap < String , ArgumentType > ,
57
- name_ordering : Vec < String > ,
53
+ /// Map from named arguments to their resolved indices.
54
+ names : HashMap < String , usize > ,
58
55
59
56
/// The latest consecutive literal strings, or empty if there weren't any.
60
57
literal : String ,
@@ -66,8 +63,6 @@ struct Context<'a, 'b:'a> {
66
63
/// Stays `true` if all formatting parameters are default (as in "{}{}").
67
64
all_pieces_simple : bool ,
68
65
69
- name_positions : HashMap < String , usize > ,
70
-
71
66
/// Current position of the implicit positional arg pointer, as if it
72
67
/// still existed in this phase of processing.
73
68
/// Used only for `all_pieces_simple` tracking in `trans_piece`.
@@ -80,15 +75,12 @@ struct Context<'a, 'b:'a> {
80
75
///
81
76
/// If parsing succeeds, the return value is:
82
77
/// ```ignore
83
- /// Some((fmtstr, unnamed arguments, ordering of named arguments,
84
- /// named arguments))
78
+ /// Some((fmtstr, parsed arguments, index map for named arguments))
85
79
/// ```
86
80
fn parse_args ( ecx : & mut ExtCtxt , sp : Span , tts : & [ tokenstream:: TokenTree ] )
87
- -> Option < ( P < ast:: Expr > , Vec < P < ast:: Expr > > , Vec < String > ,
88
- HashMap < String , P < ast:: Expr > > ) > {
89
- let mut args = Vec :: new ( ) ;
90
- let mut names = HashMap :: < String , P < ast:: Expr > > :: new ( ) ;
91
- let mut order = Vec :: new ( ) ;
81
+ -> Option < ( P < ast:: Expr > , Vec < P < ast:: Expr > > , HashMap < String , usize > ) > {
82
+ let mut args = Vec :: < P < ast:: Expr > > :: new ( ) ;
83
+ let mut names = HashMap :: < String , usize > :: new ( ) ;
92
84
93
85
let mut p = ecx. new_parser_from_tts ( tts) ;
94
86
@@ -132,20 +124,45 @@ fn parse_args(ecx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree])
132
124
ecx. struct_span_err ( e. span ,
133
125
& format ! ( "duplicate argument named `{}`" ,
134
126
name) )
135
- . span_note ( prev. span , "previously here" )
127
+ . span_note ( args [ * prev] . span , "previously here" )
136
128
. emit ( ) ;
137
129
continue ;
138
130
}
139
- order. push ( name. to_string ( ) ) ;
140
- names. insert ( name. to_string ( ) , e) ;
131
+
132
+ // Resolve names into slots early.
133
+ // Since all the positional args are already seen at this point
134
+ // if the input is valid, we can simply append to the positional
135
+ // args. And remember the names.
136
+ let slot = args. len ( ) ;
137
+ names. insert ( name. to_string ( ) , slot) ;
138
+ args. push ( e) ;
141
139
} else {
142
140
args. push ( panictry ! ( p. parse_expr( ) ) ) ;
143
141
}
144
142
}
145
- Some ( ( fmtstr, args, order , names) )
143
+ Some ( ( fmtstr, args, names) )
146
144
}
147
145
148
146
impl < ' a , ' b > Context < ' a , ' b > {
147
+ fn resolve_name_inplace ( & self , p : & mut parse:: Piece ) {
148
+ let lookup = |s| * self . names . get ( s) . unwrap_or ( & 0 ) ;
149
+
150
+ match * p {
151
+ parse:: String ( _) => { }
152
+ parse:: NextArgument ( ref mut arg) => {
153
+ if let parse:: ArgumentNamed ( s) = arg. position {
154
+ arg. position = parse:: ArgumentIs ( lookup ( s) ) ;
155
+ }
156
+ if let parse:: CountIsName ( s) = arg. format . width {
157
+ arg. format . width = parse:: CountIsParam ( lookup ( s) ) ;
158
+ }
159
+ if let parse:: CountIsName ( s) = arg. format . precision {
160
+ arg. format . precision = parse:: CountIsParam ( lookup ( s) ) ;
161
+ }
162
+ }
163
+ }
164
+ }
165
+
149
166
/// Verifies one piece of a parse string. All errors are not emitted as
150
167
/// fatal so we can continue giving errors about this and possibly other
151
168
/// format strings.
@@ -214,24 +231,16 @@ impl<'a, 'b> Context<'a, 'b> {
214
231
}
215
232
216
233
Named ( name) => {
217
- let span = match self . names . get ( & name) {
218
- Some ( e) => e . span ,
234
+ let idx = match self . names . get ( & name) {
235
+ Some ( e) => * e ,
219
236
None => {
220
237
let msg = format ! ( "there is no argument named `{}`" , name) ;
221
238
self . ecx . span_err ( self . fmtsp , & msg[ ..] ) ;
222
239
return ;
223
240
}
224
241
} ;
225
- self . verify_same ( span, & ty, self . name_types . get ( & name) ) ;
226
- if !self . name_types . contains_key ( & name) {
227
- self . name_types . insert ( name. clone ( ) , ty) ;
228
- }
229
- // Assign this named argument a slot in the arguments array if
230
- // it hasn't already been assigned a slot.
231
- if !self . name_positions . contains_key ( & name) {
232
- let slot = self . name_positions . len ( ) ;
233
- self . name_positions . insert ( name, slot) ;
234
- }
242
+ // Treat as positional arg.
243
+ self . verify_arg_type ( Exact ( idx) , ty)
235
244
}
236
245
}
237
246
}
@@ -301,14 +310,8 @@ impl<'a, 'b> Context<'a, 'b> {
301
310
count ( "Param" , Some ( self . ecx . expr_usize ( sp, i) ) )
302
311
}
303
312
parse:: CountImplied => count ( "Implied" , None ) ,
304
- parse:: CountIsName ( n) => {
305
- let i = match self . name_positions . get ( n) {
306
- Some ( & i) => i,
307
- None => 0 , // error already emitted elsewhere
308
- } ;
309
- let i = i + self . args . len ( ) ;
310
- count ( "Param" , Some ( self . ecx . expr_usize ( sp, i) ) )
311
- }
313
+ // should never be the case, names are already resolved
314
+ parse:: CountIsName ( _) => panic ! ( "should never happen" ) ,
312
315
}
313
316
}
314
317
@@ -348,16 +351,9 @@ impl<'a, 'b> Context<'a, 'b> {
348
351
match arg. position {
349
352
parse:: ArgumentIs ( i) => pos ( "At" , Some ( i) ) ,
350
353
351
- // Named arguments are converted to positional arguments
352
- // at the end of the list of arguments
353
- parse:: ArgumentNamed ( n) => {
354
- let i = match self . name_positions . get ( n) {
355
- Some ( & i) => i,
356
- None => 0 , // error already emitted elsewhere
357
- } ;
358
- let i = i + self . args . len ( ) ;
359
- pos ( "At" , Some ( i) )
360
- }
354
+ // should never be the case, because names are already
355
+ // resolved.
356
+ parse:: ArgumentNamed ( _) => panic ! ( "should never happen" ) ,
361
357
}
362
358
} ;
363
359
@@ -448,7 +444,6 @@ impl<'a, 'b> Context<'a, 'b> {
448
444
/// to
449
445
fn into_expr ( mut self ) -> P < ast:: Expr > {
450
446
let mut locals = Vec :: new ( ) ;
451
- let mut names = vec ! [ None ; self . name_positions. len( ) ] ;
452
447
let mut pats = Vec :: new ( ) ;
453
448
let mut heads = Vec :: new ( ) ;
454
449
@@ -485,29 +480,11 @@ impl<'a, 'b> Context<'a, 'b> {
485
480
self . ecx . expr_ident ( e. span , name) ) ) ;
486
481
heads. push ( self . ecx . expr_addr_of ( e. span , e) ) ;
487
482
}
488
- for name in & self . name_ordering {
489
- let e = match self . names . remove ( name) {
490
- Some ( e) => e,
491
- None => continue
492
- } ;
493
- let arg_ty = match self . name_types . get ( name) {
494
- Some ( ty) => ty,
495
- None => continue
496
- } ;
497
-
498
- let lname = self . ecx . ident_of ( & format ! ( "__arg{}" ,
499
- * name) ) ;
500
- pats. push ( self . ecx . pat_ident ( DUMMY_SP , lname) ) ;
501
- names[ * self . name_positions . get ( name) . unwrap ( ) ] =
502
- Some ( Context :: format_arg ( self . ecx , self . macsp , e. span , arg_ty,
503
- self . ecx . expr_ident ( e. span , lname) ) ) ;
504
- heads. push ( self . ecx . expr_addr_of ( e. span , e) ) ;
505
- }
506
483
507
484
// Now create a vector containing all the arguments
508
- let args = locals. into_iter ( ) . chain ( names . into_iter ( ) . map ( |a| a . unwrap ( ) ) ) ;
485
+ let args = locals. into_iter ( ) . collect ( ) ;
509
486
510
- let args_array = self . ecx . expr_vec ( self . fmtsp , args. collect ( ) ) ;
487
+ let args_array = self . ecx . expr_vec ( self . fmtsp , args) ;
511
488
512
489
// Constructs an AST equivalent to:
513
490
//
@@ -605,9 +582,9 @@ pub fn expand_format_args<'cx>(ecx: &'cx mut ExtCtxt, sp: Span,
605
582
-> Box < base:: MacResult +' cx > {
606
583
607
584
match parse_args ( ecx, sp, tts) {
608
- Some ( ( efmt, args, order , names) ) => {
585
+ Some ( ( efmt, args, names) ) => {
609
586
MacEager :: expr ( expand_preparsed_format_args ( ecx, sp, efmt,
610
- args, order , names) )
587
+ args, names) )
611
588
}
612
589
None => DummyResult :: expr ( sp)
613
590
}
@@ -618,8 +595,7 @@ pub fn expand_format_args<'cx>(ecx: &'cx mut ExtCtxt, sp: Span,
618
595
pub fn expand_preparsed_format_args ( ecx : & mut ExtCtxt , sp : Span ,
619
596
efmt : P < ast:: Expr > ,
620
597
args : Vec < P < ast:: Expr > > ,
621
- name_ordering : Vec < String > ,
622
- names : HashMap < String , P < ast:: Expr > > )
598
+ names : HashMap < String , usize > )
623
599
-> P < ast:: Expr > {
624
600
let arg_types: Vec < _ > = ( 0 ..args. len ( ) ) . map ( |_| None ) . collect ( ) ;
625
601
let macsp = ecx. call_site ( ) ;
@@ -632,9 +608,6 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
632
608
args : args,
633
609
arg_types : arg_types,
634
610
names : names,
635
- name_positions : HashMap :: new ( ) ,
636
- name_types : HashMap :: new ( ) ,
637
- name_ordering : name_ordering,
638
611
curarg : 0 ,
639
612
literal : String :: new ( ) ,
640
613
pieces : Vec :: new ( ) ,
@@ -655,9 +628,10 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
655
628
656
629
loop {
657
630
match parser. next ( ) {
658
- Some ( piece) => {
631
+ Some ( mut piece) => {
659
632
if !parser. errors . is_empty ( ) { break }
660
633
cx. verify_piece ( & piece) ;
634
+ cx. resolve_name_inplace ( & mut piece) ;
661
635
pieces. push ( piece) ;
662
636
}
663
637
None => break
@@ -683,14 +657,17 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
683
657
}
684
658
685
659
// Make sure that all arguments were used and all arguments have types.
660
+ let num_pos_args = cx. args . len ( ) - cx. names . len ( ) ;
686
661
for ( i, ty) in cx. arg_types . iter ( ) . enumerate ( ) {
687
662
if ty. is_none ( ) {
688
- cx. ecx . span_err ( cx. args [ i] . span , "argument never used" ) ;
689
- }
690
- }
691
- for ( name, e) in & cx. names {
692
- if !cx. name_types . contains_key ( name) {
693
- cx. ecx . span_err ( e. span , "named argument never used" ) ;
663
+ let msg = if i >= num_pos_args {
664
+ // named argument
665
+ "named argument never used"
666
+ } else {
667
+ // positional argument
668
+ "argument never used"
669
+ } ;
670
+ cx. ecx . span_err ( cx. args [ i] . span , msg) ;
694
671
}
695
672
}
696
673
0 commit comments