@@ -54,20 +54,32 @@ impl Context {
54
54
/// Parses the arguments from the given list of tokens, returning None if
55
55
/// there's a parse error so we can continue parsing other fmt! expressions.
56
56
fn parse_args ( & mut self , sp : span ,
57
- tts : & [ ast:: token_tree ] ) -> Option < @ast:: expr > {
57
+ leading_expr : bool ,
58
+ tts : & [ ast:: token_tree ] ) -> ( Option < @ast:: expr > ,
59
+ Option < @ast:: expr > ) {
58
60
let p = rsparse:: new_parser_from_tts ( self . ecx . parse_sess ( ) ,
59
61
self . ecx . cfg ( ) ,
60
62
tts. to_owned ( ) ) ;
63
+ // If we want a leading expression (for ifmtf), parse it here
64
+ let extra = if leading_expr {
65
+ let e = Some ( p. parse_expr ( ) ) ;
66
+ if !p. eat ( & token:: COMMA ) {
67
+ self . ecx . span_err ( sp, "expected token: `,`" ) ;
68
+ return ( e, None ) ;
69
+ }
70
+ e
71
+ } else { None } ;
72
+
61
73
if * p. token == token:: EOF {
62
- self . ecx . span_err ( sp, "ifmt! expects at least one argument" ) ;
63
- return None ;
74
+ self . ecx . span_err ( sp, "requires at least a format string argument" ) ;
75
+ return ( extra , None ) ;
64
76
}
65
77
let fmtstr = p. parse_expr ( ) ;
66
78
let mut named = false ;
67
79
while * p. token != token:: EOF {
68
80
if !p. eat ( & token:: COMMA ) {
69
81
self . ecx . span_err ( sp, "expected token: `,`" ) ;
70
- return None ;
82
+ return ( extra , None ) ;
71
83
}
72
84
if named || ( token:: is_ident ( p. token ) &&
73
85
p. look_ahead ( 1 , |t| * t == token:: EQ ) ) {
@@ -81,14 +93,14 @@ impl Context {
81
93
self . ecx . span_err ( * p. span ,
82
94
"expected ident, positional arguments \
83
95
cannot follow named arguments") ;
84
- return None ;
96
+ return ( extra , None ) ;
85
97
}
86
98
_ => {
87
99
self . ecx . span_err ( * p. span ,
88
100
fmt ! ( "expected ident for named \
89
101
argument, but found `%s`",
90
102
p. this_token_to_str( ) ) ) ;
91
- return None ;
103
+ return ( extra , None ) ;
92
104
}
93
105
} ;
94
106
let name = self . ecx . str_of ( ident) ;
@@ -110,7 +122,7 @@ impl Context {
110
122
self . arg_types . push ( None ) ;
111
123
}
112
124
}
113
- return Some ( fmtstr) ;
125
+ return ( extra , Some ( fmtstr) ) ;
114
126
}
115
127
116
128
/// Verifies one piece of a parse string. All errors are not emitted as
@@ -530,7 +542,7 @@ impl Context {
530
542
531
543
/// Actually builds the expression which the ifmt! block will be expanded
532
544
/// to
533
- fn to_expr ( & self ) -> @ast:: expr {
545
+ fn to_expr ( & self , extra : Option < @ast :: expr > , f : & str ) -> @ast:: expr {
534
546
let mut lets = ~[ ] ;
535
547
let mut locals = ~[ ] ;
536
548
let mut names = vec:: from_fn ( self . name_positions . len ( ) , |_| None ) ;
@@ -596,15 +608,18 @@ impl Context {
596
608
let args = names. move_iter ( ) . map ( |a| a. unwrap ( ) ) ;
597
609
let mut args = locals. move_iter ( ) . chain ( args) ;
598
610
599
- // Next, build up the actual call to the sprintf function.
611
+ let mut fmt_args = match extra {
612
+ Some ( e) => ~[ e] , None => ~[ ]
613
+ } ;
614
+ fmt_args. push ( self . ecx . expr_ident ( self . fmtsp , static_name) ) ;
615
+ fmt_args. push ( self . ecx . expr_vec ( self . fmtsp , args. collect ( ) ) ) ;
616
+
617
+ // Next, build up the actual call to the {s,f}printf function.
600
618
let result = self . ecx . expr_call_global ( self . fmtsp , ~[
601
619
self . ecx . ident_of ( "std" ) ,
602
620
self . ecx . ident_of ( "fmt" ) ,
603
- self . ecx . ident_of ( "sprintf" ) ,
604
- ] , ~[
605
- self . ecx . expr_ident ( self . fmtsp , static_name) ,
606
- self . ecx . expr_vec ( self . fmtsp , args. collect ( ) ) ,
607
- ] ) ;
621
+ self . ecx . ident_of ( f) ,
622
+ ] , fmt_args) ;
608
623
609
624
// sprintf is unsafe, but we just went through a lot of work to
610
625
// validate that our call is save, so inject the unsafe block for the
@@ -682,8 +697,19 @@ impl Context {
682
697
}
683
698
}
684
699
685
- pub fn expand_syntax_ext ( ecx : @ExtCtxt , sp : span ,
686
- tts : & [ ast:: token_tree ] ) -> base:: MacResult {
700
+ pub fn expand_sprintf ( ecx : @ExtCtxt , sp : span ,
701
+ tts : & [ ast:: token_tree ] ) -> base:: MacResult {
702
+ expand_ifmt ( ecx, sp, tts, false , "sprintf" )
703
+ }
704
+
705
+ pub fn expand_fprintf ( ecx : @ExtCtxt , sp : span ,
706
+ tts : & [ ast:: token_tree ] ) -> base:: MacResult {
707
+ expand_ifmt ( ecx, sp, tts, true , "fprintf" )
708
+ }
709
+
710
+
711
+ fn expand_ifmt ( ecx : @ExtCtxt , sp : span , tts : & [ ast:: token_tree ] ,
712
+ leading_arg : bool , function : & str ) -> base:: MacResult {
687
713
let mut cx = Context {
688
714
ecx : ecx,
689
715
args : ~[ ] ,
@@ -697,13 +723,13 @@ pub fn expand_syntax_ext(ecx: @ExtCtxt, sp: span,
697
723
method_statics : ~[ ] ,
698
724
fmtsp : sp,
699
725
} ;
700
- let efmt = match cx. parse_args ( sp, tts) {
701
- Some ( e) => e ,
702
- None => { return MRExpr ( ecx. expr_uint ( sp, 2 ) ) ; }
726
+ let ( extra , efmt) = match cx. parse_args ( sp, leading_arg , tts) {
727
+ ( extra , Some ( e) ) => ( extra , e ) ,
728
+ ( _ , None ) => { return MRExpr ( ecx. expr_uint ( sp, 2 ) ) ; }
703
729
} ;
704
730
cx. fmtsp = efmt. span ;
705
731
let fmt = expr_to_str ( ecx, efmt,
706
- "first argument to ifmt! must be a string literal." ) ;
732
+ "format argument must be a string literal." ) ;
707
733
708
734
let mut err = false ;
709
735
do parse:: parse_error:: cond. trap ( |m| {
@@ -734,5 +760,5 @@ pub fn expand_syntax_ext(ecx: @ExtCtxt, sp: span,
734
760
}
735
761
}
736
762
737
- MRExpr ( cx. to_expr ( ) )
763
+ MRExpr ( cx. to_expr ( extra , function ) )
738
764
}
0 commit comments