@@ -123,8 +123,9 @@ pub struct ParseError {
123
123
pub description : string:: String ,
124
124
pub note : Option < string:: String > ,
125
125
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 ) > ,
128
129
}
129
130
130
131
/// The parser structure for interpreting the input format string. This is
@@ -142,22 +143,39 @@ pub struct Parser<'a> {
142
143
curarg : usize ,
143
144
/// `Some(raw count)` when the string is "raw", used to position spans correctly
144
145
style : Option < usize > ,
145
- /// How many newlines have been seen in the string so far, to adjust the error spans
146
- seen_newlines : usize ,
147
146
/// Start and end byte offset of every successfully parsed argument
148
147
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
+ }
149
163
}
150
164
151
165
impl < ' a > Iterator for Parser < ' a > {
152
166
type Item = Piece < ' a > ;
153
167
154
168
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 ( ) ;
156
170
if let Some ( & ( pos, c) ) = self . cur . peek ( ) {
157
171
match c {
158
172
'{' => {
173
+ let curr_last_brace = self . last_opening_brace_pos ;
174
+ self . last_opening_brace_pos = Some ( self . to_span_index ( pos) ) ;
159
175
self . cur . next ( ) ;
160
176
if self . consume ( '{' ) {
177
+ self . last_opening_brace_pos = curr_last_brace;
178
+
161
179
Some ( String ( self . string ( pos + 1 ) ) )
162
180
} else {
163
181
let arg = self . argument ( ) ;
@@ -174,7 +192,7 @@ impl<'a> Iterator for Parser<'a> {
174
192
if self . consume ( '}' ) {
175
193
Some ( String ( self . string ( pos + 1 ) ) )
176
194
} else {
177
- let err_pos = pos + raw + 1 ;
195
+ let err_pos = self . to_span_index ( pos) ;
178
196
self . err_with_note (
179
197
"unmatched `}` found" ,
180
198
"unmatched `}`" ,
@@ -186,7 +204,6 @@ impl<'a> Iterator for Parser<'a> {
186
204
}
187
205
}
188
206
'\n' => {
189
- self . seen_newlines += 1 ;
190
207
Some ( String ( self . string ( pos) ) )
191
208
}
192
209
_ => Some ( String ( self . string ( pos) ) ) ,
@@ -199,15 +216,22 @@ impl<'a> Iterator for Parser<'a> {
199
216
200
217
impl < ' a > Parser < ' a > {
201
218
/// 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 > {
203
225
Parser {
204
226
input : s,
205
227
cur : s. char_indices ( ) . peekable ( ) ,
206
228
errors : vec ! [ ] ,
207
229
curarg : 0 ,
208
230
style,
209
- seen_newlines : 0 ,
210
231
arg_places : vec ! [ ] ,
232
+ skips,
233
+ last_opening_brace_pos : None ,
234
+ append_newline,
211
235
}
212
236
}
213
237
@@ -218,15 +242,16 @@ impl<'a> Parser<'a> {
218
242
& mut self ,
219
243
description : S1 ,
220
244
label : S2 ,
221
- start : usize ,
222
- end : usize ,
245
+ start : SpanIndex ,
246
+ end : SpanIndex ,
223
247
) {
224
248
self . errors . push ( ParseError {
225
249
description : description. into ( ) ,
226
250
note : None ,
227
251
label : label. into ( ) ,
228
252
start,
229
253
end,
254
+ secondary_label : None ,
230
255
} ) ;
231
256
}
232
257
@@ -238,15 +263,16 @@ impl<'a> Parser<'a> {
238
263
description : S1 ,
239
264
label : S2 ,
240
265
note : S3 ,
241
- start : usize ,
242
- end : usize ,
266
+ start : SpanIndex ,
267
+ end : SpanIndex ,
243
268
) {
244
269
self . errors . push ( ParseError {
245
270
description : description. into ( ) ,
246
271
note : Some ( note. into ( ) ) ,
247
272
label : label. into ( ) ,
248
273
start,
249
274
end,
275
+ secondary_label : None ,
250
276
} ) ;
251
277
}
252
278
@@ -266,47 +292,86 @@ impl<'a> Parser<'a> {
266
292
}
267
293
}
268
294
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
+
269
313
/// Forces consumption of the specified character. If the character is not
270
314
/// found, an error is emitted.
271
315
fn must_consume ( & mut self , c : char ) -> Option < usize > {
272
316
self . ws ( ) ;
273
- let raw = self . style . unwrap_or ( 0 ) ;
274
317
275
- let padding = raw + self . seen_newlines ;
276
318
if let Some ( & ( pos, maybe) ) = self . cur . peek ( ) {
277
319
if c == maybe {
278
320
self . cur . next ( ) ;
279
321
Some ( pos)
280
322
} 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
+ } ) ;
286
342
None
287
343
}
288
344
} 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) ;
295
349
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
+ } ) ;
301
367
} else {
302
- self . err ( msg , format ! ( "expected `{:?}`" , c) , pos, pos) ;
368
+ self . err ( description , format ! ( "expected `{:?}`" , c) , pos, pos) ;
303
369
}
304
370
None
305
371
}
306
372
}
307
373
308
- /// Consumes all whitespace characters until the first non-whitespace
309
- /// character
374
+ /// Consumes all whitespace characters until the first non-whitespace character
310
375
fn ws ( & mut self ) {
311
376
while let Some ( & ( _, c) ) = self . cur . peek ( ) {
312
377
if c. is_whitespace ( ) {
@@ -334,8 +399,7 @@ impl<'a> Parser<'a> {
334
399
& self . input [ start..self . input . len ( ) ]
335
400
}
336
401
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
339
403
fn argument ( & mut self ) -> Argument < ' a > {
340
404
let pos = self . position ( ) ;
341
405
let format = self . format ( ) ;
@@ -371,8 +435,8 @@ impl<'a> Parser<'a> {
371
435
self . err_with_note ( format ! ( "invalid argument name `{}`" , invalid_name) ,
372
436
"invalid argument name" ,
373
437
"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 ( ) ) ) ;
376
440
Some ( ArgumentNamed ( invalid_name) )
377
441
} ,
378
442
@@ -553,7 +617,7 @@ mod tests {
553
617
use super :: * ;
554
618
555
619
fn same ( fmt : & ' static str , p : & [ Piece < ' static > ] ) {
556
- let parser = Parser :: new ( fmt, None ) ;
620
+ let parser = Parser :: new ( fmt, None , vec ! [ ] , false ) ;
557
621
assert ! ( parser. collect:: <Vec <Piece <' static >>>( ) == p) ;
558
622
}
559
623
@@ -569,7 +633,7 @@ mod tests {
569
633
}
570
634
571
635
fn musterr ( s : & str ) {
572
- let mut p = Parser :: new ( s, None ) ;
636
+ let mut p = Parser :: new ( s, None , vec ! [ ] , false ) ;
573
637
p. next ( ) ;
574
638
assert ! ( !p. errors. is_empty( ) ) ;
575
639
}
0 commit comments