@@ -56,78 +56,83 @@ struct Context<'a> {
56
56
next_arg : uint ,
57
57
}
58
58
59
- impl < ' a > Context < ' a > {
60
- /// Parses the arguments from the given list of tokens, returning None if
61
- /// there's a parse error so we can continue parsing other format! expressions.
62
- fn parse_args ( & mut self , sp : Span , tts : & [ ast:: TokenTree ] )
63
- -> ( @ast:: Expr , Option < @ast:: Expr > ) {
64
- let mut p = rsparse:: new_parser_from_tts ( self . ecx . parse_sess ( ) ,
65
- self . ecx . cfg ( ) ,
66
- tts. to_owned ( ) ) ;
67
- // Parse the leading function expression (maybe a block, maybe a path)
68
- let extra = p. parse_expr ( ) ;
69
- if !p. eat ( & token:: COMMA ) {
70
- self . ecx . span_err ( sp, "expected token: `,`" ) ;
71
- return ( extra, None ) ;
72
- }
59
+ /// Parses the arguments from the given list of tokens, returning None
60
+ /// if there's a parse error so we can continue parsing other format!
61
+ /// expressions.
62
+ ///
63
+ /// If parsing succeeds, the second return value is:
64
+ ///
65
+ /// Some((fmtstr, unnamed arguments, named arguments))
66
+ fn parse_args ( ecx : & mut ExtCtxt , sp : Span ,
67
+ tts : & [ ast:: TokenTree ] ) -> ( @ast:: Expr , Option < ( @ast:: Expr , ~[ @ast:: Expr ] ,
68
+ HashMap < ~str , @ast:: Expr > ) > ) {
69
+ let mut args = ~[ ] ;
70
+ let mut names = HashMap :: < ~str , @ast:: Expr > :: new ( ) ;
71
+
72
+ let mut p = rsparse:: new_parser_from_tts ( ecx. parse_sess ( ) ,
73
+ ecx. cfg ( ) ,
74
+ tts. to_owned ( ) ) ;
75
+ // Parse the leading function expression (maybe a block, maybe a path)
76
+ let extra = p. parse_expr ( ) ;
77
+ if !p. eat ( & token:: COMMA ) {
78
+ ecx. span_err ( sp, "expected token: `,`" ) ;
79
+ return ( extra, None ) ;
80
+ }
73
81
74
- if p. token == token:: EOF {
75
- self . ecx . span_err ( sp, "requires at least a format string argument" ) ;
82
+ if p. token == token:: EOF {
83
+ ecx. span_err ( sp, "requires at least a format string argument" ) ;
84
+ return ( extra, None ) ;
85
+ }
86
+ let fmtstr = p. parse_expr ( ) ;
87
+ let mut named = false ;
88
+ while p. token != token:: EOF {
89
+ if !p. eat ( & token:: COMMA ) {
90
+ ecx. span_err ( sp, "expected token: `,`" ) ;
76
91
return ( extra, None ) ;
77
92
}
78
- let fmtstr = p. parse_expr ( ) ;
79
- let mut named = false ;
80
- while p. token != token:: EOF {
81
- if !p. eat ( & token:: COMMA ) {
82
- self . ecx . span_err ( sp, "expected token: `,`" ) ;
83
- return ( extra, None ) ;
84
- }
85
- if p. token == token:: EOF { break } // accept trailing commas
86
- if named || ( token:: is_ident ( & p. token ) &&
87
- p. look_ahead ( 1 , |t| * t == token:: EQ ) ) {
88
- named = true ;
89
- let ident = match p. token {
90
- token:: IDENT ( i, _) => {
91
- p. bump ( ) ;
92
- i
93
- }
94
- _ if named => {
95
- self . ecx . span_err ( p. span ,
96
- "expected ident, positional arguments \
97
- cannot follow named arguments") ;
98
- return ( extra, None ) ;
99
- }
100
- _ => {
101
- self . ecx . span_err ( p. span ,
102
- format ! ( "expected ident for named \
103
- argument, but found `{}`",
104
- p. this_token_to_str( ) ) ) ;
105
- return ( extra, None ) ;
106
- }
107
- } ;
108
- let interned_name = token:: get_ident ( ident. name ) ;
109
- let name = interned_name. get ( ) ;
110
- p. expect ( & token:: EQ ) ;
111
- let e = p. parse_expr ( ) ;
112
- match self . names . find_equiv ( & name) {
113
- None => { }
114
- Some ( prev) => {
115
- self . ecx . span_err ( e. span , format ! ( "duplicate argument \
116
- named `{}`", name) ) ;
117
- self . ecx . parse_sess . span_diagnostic . span_note (
118
- prev. span , "previously here" ) ;
119
- continue
120
- }
93
+ if p. token == token:: EOF { break } // accept trailing commas
94
+ if named || ( token:: is_ident ( & p. token ) &&
95
+ p. look_ahead ( 1 , |t| * t == token:: EQ ) ) {
96
+ named = true ;
97
+ let ident = match p. token {
98
+ token:: IDENT ( i, _) => {
99
+ p. bump ( ) ;
100
+ i
101
+ }
102
+ _ if named => {
103
+ ecx. span_err ( p. span ,
104
+ "expected ident, positional arguments \
105
+ cannot follow named arguments") ;
106
+ return ( extra, None ) ;
107
+ }
108
+ _ => {
109
+ ecx. span_err ( p. span ,
110
+ format ! ( "expected ident for named argument, but found `{}`" ,
111
+ p. this_token_to_str( ) ) ) ;
112
+ return ( extra, None ) ;
113
+ }
114
+ } ;
115
+ let interned_name = token:: get_ident ( ident. name ) ;
116
+ let name = interned_name. get ( ) ;
117
+ p. expect ( & token:: EQ ) ;
118
+ let e = p. parse_expr ( ) ;
119
+ match names. find_equiv ( & name) {
120
+ None => { }
121
+ Some ( prev) => {
122
+ ecx. span_err ( e. span , format ! ( "duplicate argument named `{}`" , name) ) ;
123
+ ecx. parse_sess . span_diagnostic . span_note ( prev. span , "previously here" ) ;
124
+ continue
121
125
}
122
- self . names . insert ( name. to_str ( ) , e) ;
123
- } else {
124
- self . args . push ( p. parse_expr ( ) ) ;
125
- self . arg_types . push ( None ) ;
126
126
}
127
+ names. insert ( name. to_str ( ) , e) ;
128
+ } else {
129
+ args. push ( p. parse_expr ( ) ) ;
127
130
}
128
- return ( extra, Some ( fmtstr) ) ;
129
131
}
132
+ return ( extra, Some ( ( fmtstr, args, names) ) ) ;
133
+ }
130
134
135
+ impl < ' a > Context < ' a > {
131
136
/// Verifies one piece of a parse string. All errors are not emitted as
132
137
/// fatal so we can continue giving errors about this and possibly other
133
138
/// format strings.
@@ -758,11 +763,28 @@ impl<'a> Context<'a> {
758
763
759
764
pub fn expand_args ( ecx : & mut ExtCtxt , sp : Span ,
760
765
tts : & [ ast:: TokenTree ] ) -> base:: MacResult {
766
+
767
+ match parse_args ( ecx, sp, tts) {
768
+ ( extra, Some ( ( efmt, args, names) ) ) => {
769
+ MRExpr ( expand_preparsed_format_args ( ecx, sp, extra, efmt, args, names) )
770
+ }
771
+ ( _, None ) => MRExpr ( ecx. expr_uint ( sp, 2 ) )
772
+ }
773
+ }
774
+
775
+ /// Take the various parts of `format_args!(extra, efmt, args...,
776
+ /// name=names...)` and construct the appropriate formatting
777
+ /// expression.
778
+ pub fn expand_preparsed_format_args ( ecx : & mut ExtCtxt , sp : Span ,
779
+ extra : @ast:: Expr ,
780
+ efmt : @ast:: Expr , args : ~[ @ast:: Expr ] ,
781
+ names : HashMap < ~str , @ast:: Expr > ) -> @ast:: Expr {
782
+ let arg_types = vec:: from_fn ( args. len ( ) , |_| None ) ;
761
783
let mut cx = Context {
762
784
ecx : ecx,
763
- args : ~ [ ] ,
764
- arg_types : ~ [ ] ,
765
- names : HashMap :: new ( ) ,
785
+ args : args ,
786
+ arg_types : arg_types ,
787
+ names : names ,
766
788
name_positions : HashMap :: new ( ) ,
767
789
name_types : HashMap :: new ( ) ,
768
790
nest_level : 0 ,
@@ -771,10 +793,6 @@ pub fn expand_args(ecx: &mut ExtCtxt, sp: Span,
771
793
method_statics : ~[ ] ,
772
794
fmtsp : sp,
773
795
} ;
774
- let ( extra, efmt) = match cx. parse_args ( sp, tts) {
775
- ( extra, Some ( e) ) => ( extra, e) ,
776
- ( _, None ) => { return MRExpr ( cx. ecx . expr_uint ( sp, 2 ) ) ; }
777
- } ;
778
796
cx. fmtsp = efmt. span ;
779
797
// Be sure to recursively expand macros just in case the format string uses
780
798
// a macro to build the format expression.
@@ -783,7 +801,7 @@ pub fn expand_args(ecx: &mut ExtCtxt, sp: Span,
783
801
expr,
784
802
"format argument must be a string literal." ) {
785
803
Some ( ( fmt, _) ) => fmt,
786
- None => return MacResult :: dummy_expr ( )
804
+ None => return efmt
787
805
} ;
788
806
789
807
let mut parser = parse:: Parser :: new ( fmt. get ( ) ) ;
@@ -801,7 +819,7 @@ pub fn expand_args(ecx: &mut ExtCtxt, sp: Span,
801
819
match parser. errors . shift ( ) {
802
820
Some ( error) => {
803
821
cx. ecx . span_err ( efmt. span , "invalid format string: " + error) ;
804
- return MRExpr ( efmt) ;
822
+ return efmt;
805
823
}
806
824
None => { }
807
825
}
@@ -818,5 +836,5 @@ pub fn expand_args(ecx: &mut ExtCtxt, sp: Span,
818
836
}
819
837
}
820
838
821
- MRExpr ( cx. to_expr ( extra) )
839
+ cx. to_expr ( extra)
822
840
}
0 commit comments