@@ -123,8 +123,9 @@ pub struct ParseError {
123123 pub description : string:: String ,
124124 pub note : Option < string:: String > ,
125125 pub label : string:: String ,
126- pub start : usize ,
127- pub end : usize ,
126+ pub start : SpanIndex ,
127+ pub end : SpanIndex ,
128+ pub secondary_label : Option < ( string:: String , SpanIndex , SpanIndex ) > ,
128129}
129130
130131/// The parser structure for interpreting the input format string. This is
@@ -142,22 +143,39 @@ pub struct Parser<'a> {
142143 curarg : usize ,
143144 /// `Some(raw count)` when the string is "raw", used to position spans correctly
144145 style : Option < usize > ,
145- /// How many newlines have been seen in the string so far, to adjust the error spans
146- seen_newlines : usize ,
147146 /// Start and end byte offset of every successfully parsed argument
148147 pub arg_places : Vec < ( usize , usize ) > ,
148+ /// Characters that need to be shifted
149+ skips : Vec < usize > ,
150+ /// Span offset of the last opening brace seen, used for error reporting
151+ last_opening_brace_pos : Option < SpanIndex > ,
152+ /// Wether the source string is comes from `println!` as opposed to `format!` or `print!`
153+ append_newline : bool ,
154+ }
155+
156+ #[ derive( Clone , Copy , Debug ) ]
157+ pub struct SpanIndex ( usize ) ;
158+
159+ impl SpanIndex {
160+ pub fn unwrap ( self ) -> usize {
161+ self . 0
162+ }
149163}
150164
151165impl < ' a > Iterator for Parser < ' a > {
152166 type Item = Piece < ' a > ;
153167
154168 fn next ( & mut self ) -> Option < Piece < ' a > > {
155- let raw = self . style . map ( | raw| raw + self . seen_newlines ) . unwrap_or ( 0 ) ;
169+ let raw = self . raw ( ) ;
156170 if let Some ( & ( pos, c) ) = self . cur . peek ( ) {
157171 match c {
158172 '{' => {
173+ let curr_last_brace = self . last_opening_brace_pos ;
174+ self . last_opening_brace_pos = Some ( self . to_span_index ( pos) ) ;
159175 self . cur . next ( ) ;
160176 if self . consume ( '{' ) {
177+ self . last_opening_brace_pos = curr_last_brace;
178+
161179 Some ( String ( self . string ( pos + 1 ) ) )
162180 } else {
163181 let arg = self . argument ( ) ;
@@ -174,7 +192,7 @@ impl<'a> Iterator for Parser<'a> {
174192 if self . consume ( '}' ) {
175193 Some ( String ( self . string ( pos + 1 ) ) )
176194 } else {
177- let err_pos = pos + raw + 1 ;
195+ let err_pos = self . to_span_index ( pos) ;
178196 self . err_with_note (
179197 "unmatched `}` found" ,
180198 "unmatched `}`" ,
@@ -186,7 +204,6 @@ impl<'a> Iterator for Parser<'a> {
186204 }
187205 }
188206 '\n' => {
189- self . seen_newlines += 1 ;
190207 Some ( String ( self . string ( pos) ) )
191208 }
192209 _ => Some ( String ( self . string ( pos) ) ) ,
@@ -199,15 +216,22 @@ impl<'a> Iterator for Parser<'a> {
199216
200217impl < ' a > Parser < ' a > {
201218 /// Creates a new parser for the given format string
202- pub fn new ( s : & ' a str , style : Option < usize > ) -> Parser < ' a > {
219+ pub fn new (
220+ s : & ' a str ,
221+ style : Option < usize > ,
222+ skips : Vec < usize > ,
223+ append_newline : bool ,
224+ ) -> Parser < ' a > {
203225 Parser {
204226 input : s,
205227 cur : s. char_indices ( ) . peekable ( ) ,
206228 errors : vec ! [ ] ,
207229 curarg : 0 ,
208230 style,
209- seen_newlines : 0 ,
210231 arg_places : vec ! [ ] ,
232+ skips,
233+ last_opening_brace_pos : None ,
234+ append_newline,
211235 }
212236 }
213237
@@ -218,15 +242,16 @@ impl<'a> Parser<'a> {
218242 & mut self ,
219243 description : S1 ,
220244 label : S2 ,
221- start : usize ,
222- end : usize ,
245+ start : SpanIndex ,
246+ end : SpanIndex ,
223247 ) {
224248 self . errors . push ( ParseError {
225249 description : description. into ( ) ,
226250 note : None ,
227251 label : label. into ( ) ,
228252 start,
229253 end,
254+ secondary_label : None ,
230255 } ) ;
231256 }
232257
@@ -238,15 +263,16 @@ impl<'a> Parser<'a> {
238263 description : S1 ,
239264 label : S2 ,
240265 note : S3 ,
241- start : usize ,
242- end : usize ,
266+ start : SpanIndex ,
267+ end : SpanIndex ,
243268 ) {
244269 self . errors . push ( ParseError {
245270 description : description. into ( ) ,
246271 note : Some ( note. into ( ) ) ,
247272 label : label. into ( ) ,
248273 start,
249274 end,
275+ secondary_label : None ,
250276 } ) ;
251277 }
252278
@@ -266,47 +292,86 @@ impl<'a> Parser<'a> {
266292 }
267293 }
268294
295+ fn raw ( & self ) -> usize {
296+ self . style . map ( |raw| raw + 1 ) . unwrap_or ( 0 )
297+ }
298+
299+ fn to_span_index ( & self , pos : usize ) -> SpanIndex {
300+ let mut pos = pos;
301+ for skip in & self . skips {
302+ if pos > * skip {
303+ pos += 1 ;
304+ } else if pos == * skip && self . raw ( ) == 0 {
305+ pos += 1 ;
306+ } else {
307+ break ;
308+ }
309+ }
310+ SpanIndex ( self . raw ( ) + pos + 1 )
311+ }
312+
269313 /// Forces consumption of the specified character. If the character is not
270314 /// found, an error is emitted.
271315 fn must_consume ( & mut self , c : char ) -> Option < usize > {
272316 self . ws ( ) ;
273- let raw = self . style . unwrap_or ( 0 ) ;
274317
275- let padding = raw + self . seen_newlines ;
276318 if let Some ( & ( pos, maybe) ) = self . cur . peek ( ) {
277319 if c == maybe {
278320 self . cur . next ( ) ;
279321 Some ( pos)
280322 } else {
281- let pos = pos + raw + 1 ;
282- self . err ( format ! ( "expected `{:?}`, found `{:?}`" , c, maybe) ,
283- format ! ( "expected `{}`" , c) ,
284- pos,
285- pos) ;
323+ let pos = self . to_span_index ( pos) ;
324+ let description = format ! ( "expected `'}}'`, found `{:?}`" , maybe) ;
325+ let label = "expected `}`" . to_owned ( ) ;
326+ let ( note, secondary_label) = if c == '}' {
327+ ( Some ( "if you intended to print `{`, you can escape it using `{{`" . to_owned ( ) ) ,
328+ self . last_opening_brace_pos . map ( |pos| {
329+ ( "because of this opening brace" . to_owned ( ) , pos, pos)
330+ } ) )
331+ } else {
332+ ( None , None )
333+ } ;
334+ self . errors . push ( ParseError {
335+ description,
336+ note,
337+ label,
338+ start : pos,
339+ end : pos,
340+ secondary_label,
341+ } ) ;
286342 None
287343 }
288344 } else {
289- let msg = format ! ( "expected `{:?}` but string was terminated" , c) ;
290- // point at closing `"`, unless the last char is `\n` to account for `println`
291- let pos = match self . input . chars ( ) . last ( ) {
292- Some ( '\n' ) => self . input . len ( ) ,
293- _ => self . input . len ( ) + 1 ,
294- } ;
345+ let description = format ! ( "expected `{:?}` but string was terminated" , c) ;
346+ // point at closing `"`
347+ let pos = self . input . len ( ) - if self . append_newline { 1 } else { 0 } ;
348+ let pos = self . to_span_index ( pos) ;
295349 if c == '}' {
296- self . err_with_note ( msg,
297- format ! ( "expected `{:?}`" , c) ,
298- "if you intended to print `{`, you can escape it using `{{`" ,
299- pos + padding,
300- pos + padding) ;
350+ let label = format ! ( "expected `{:?}`" , c) ;
351+ let ( note, secondary_label) = if c == '}' {
352+ ( Some ( "if you intended to print `{`, you can escape it using `{{`" . to_owned ( ) ) ,
353+ self . last_opening_brace_pos . map ( |pos| {
354+ ( "because of this opening brace" . to_owned ( ) , pos, pos)
355+ } ) )
356+ } else {
357+ ( None , None )
358+ } ;
359+ self . errors . push ( ParseError {
360+ description,
361+ note,
362+ label,
363+ start : pos,
364+ end : pos,
365+ secondary_label,
366+ } ) ;
301367 } else {
302- self . err ( msg , format ! ( "expected `{:?}`" , c) , pos, pos) ;
368+ self . err ( description , format ! ( "expected `{:?}`" , c) , pos, pos) ;
303369 }
304370 None
305371 }
306372 }
307373
308- /// Consumes all whitespace characters until the first non-whitespace
309- /// character
374+ /// Consumes all whitespace characters until the first non-whitespace character
310375 fn ws ( & mut self ) {
311376 while let Some ( & ( _, c) ) = self . cur . peek ( ) {
312377 if c. is_whitespace ( ) {
@@ -334,8 +399,7 @@ impl<'a> Parser<'a> {
334399 & self . input [ start..self . input . len ( ) ]
335400 }
336401
337- /// Parses an Argument structure, or what's contained within braces inside
338- /// the format string
402+ /// Parses an Argument structure, or what's contained within braces inside the format string
339403 fn argument ( & mut self ) -> Argument < ' a > {
340404 let pos = self . position ( ) ;
341405 let format = self . format ( ) ;
@@ -371,8 +435,8 @@ impl<'a> Parser<'a> {
371435 self . err_with_note ( format ! ( "invalid argument name `{}`" , invalid_name) ,
372436 "invalid argument name" ,
373437 "argument names cannot start with an underscore" ,
374- pos + 1 , // add 1 to account for leading `{`
375- pos + 1 + invalid_name. len ( ) ) ;
438+ self . to_span_index ( pos) ,
439+ self . to_span_index ( pos + invalid_name. len ( ) ) ) ;
376440 Some ( ArgumentNamed ( invalid_name) )
377441 } ,
378442
@@ -553,7 +617,7 @@ mod tests {
553617 use super :: * ;
554618
555619 fn same ( fmt : & ' static str , p : & [ Piece < ' static > ] ) {
556- let parser = Parser :: new ( fmt, None ) ;
620+ let parser = Parser :: new ( fmt, None , vec ! [ ] , false ) ;
557621 assert ! ( parser. collect:: <Vec <Piece <' static >>>( ) == p) ;
558622 }
559623
@@ -569,7 +633,7 @@ mod tests {
569633 }
570634
571635 fn musterr ( s : & str ) {
572- let mut p = Parser :: new ( s, None ) ;
636+ let mut p = Parser :: new ( s, None , vec ! [ ] , false ) ;
573637 p. next ( ) ;
574638 assert ! ( !p. errors. is_empty( ) ) ;
575639 }
0 commit comments