@@ -16,6 +16,7 @@ use symbol::keywords;
16
16
use syntax_pos:: { BytePos , Span , DUMMY_SP } ;
17
17
use tokenstream;
18
18
19
+ use std:: iter:: Peekable ;
19
20
use std:: rc:: Rc ;
20
21
21
22
/// Contains the sub-token-trees of a "delimited" token tree, such as the contents of `(`. Note
@@ -78,6 +79,7 @@ pub enum KleeneOp {
78
79
ZeroOrMore ,
79
80
/// Kleene plus (`+`) for one or more repetitions
80
81
OneOrMore ,
82
+ ZeroOrOne ,
81
83
}
82
84
83
85
/// Similar to `tokenstream::TokenTree`, except that `$i`, `$i:ident`, and `$(...)`
@@ -183,7 +185,7 @@ pub fn parse(
183
185
184
186
// For each token tree in `input`, parse the token into a `self::TokenTree`, consuming
185
187
// additional trees if need be.
186
- let mut trees = input. trees ( ) ;
188
+ let mut trees = input. trees ( ) . peekable ( ) ;
187
189
while let Some ( tree) = trees. next ( ) {
188
190
let tree = parse_tree ( tree, & mut trees, expect_matchers, sess) ;
189
191
@@ -321,6 +323,34 @@ where
321
323
}
322
324
}
323
325
326
+ /// Takes a token and returns `Some(KleeneOp)` if the token is `+` `*` or `?`. Otherwise, return
327
+ /// `None`.
328
+ fn kleene_op ( token : & token:: Token ) -> Option < KleeneOp > {
329
+ match * token {
330
+ token:: BinOp ( token:: Star ) => Some ( KleeneOp :: ZeroOrMore ) ,
331
+ token:: BinOp ( token:: Plus ) => Some ( KleeneOp :: OneOrMore ) ,
332
+ token:: Question => Some ( KleeneOp :: ZeroOrOne ) ,
333
+ _ => None ,
334
+ }
335
+ }
336
+
337
+ /// Parse the next token tree of the input looking for a KleeneOp. Returns
338
+ ///
339
+ /// - Ok(Ok(op)) if the next token tree is a KleeneOp
340
+ /// - Ok(Err(tok, span)) if the next token tree is a token but not a KleeneOp
341
+ /// - Err(span) if the next token tree is not a token
342
+ fn parse_kleene_op < I > ( input : & mut I , span : Span ) -> Result < Result < KleeneOp , ( token:: Token , Span ) > , Span >
343
+ where I : Iterator < Item = tokenstream:: TokenTree > ,
344
+ {
345
+ match input. next ( ) {
346
+ Some ( tokenstream:: TokenTree :: Token ( span, tok) ) => match kleene_op ( & tok) {
347
+ Some ( op) => Ok ( Ok ( op) ) ,
348
+ None => Ok ( Err ( ( tok, span) ) ) ,
349
+ }
350
+ tree => Err ( tree. as_ref ( ) . map ( tokenstream:: TokenTree :: span) . unwrap_or ( span) ) ,
351
+ }
352
+ }
353
+
324
354
/// Attempt to parse a single Kleene star, possibly with a separator.
325
355
///
326
356
/// For example, in a pattern such as `$(a),*`, `a` is the pattern to be repeated, `,` is the
@@ -333,56 +363,64 @@ where
333
363
/// session `sess`. If the next one (or possibly two) tokens in `input` correspond to a Kleene
334
364
/// operator and separator, then a tuple with `(separator, KleeneOp)` is returned. Otherwise, an
335
365
/// error with the appropriate span is emitted to `sess` and a dummy value is returned.
336
- fn parse_sep_and_kleene_op < I > (
337
- input : & mut I ,
338
- span : Span ,
339
- sess : & ParseSess ,
340
- ) -> ( Option < token:: Token > , KleeneOp )
341
- where
342
- I : Iterator < Item = tokenstream:: TokenTree > ,
366
+ fn parse_sep_and_kleene_op < I > ( input : & mut Peekable < I > , span : Span , sess : & ParseSess )
367
+ -> ( Option < token:: Token > , KleeneOp )
368
+ where I : Iterator < Item = tokenstream:: TokenTree > ,
343
369
{
344
- fn kleene_op ( token : & token:: Token ) -> Option < KleeneOp > {
345
- match * token {
346
- token:: BinOp ( token:: Star ) => Some ( KleeneOp :: ZeroOrMore ) ,
347
- token:: BinOp ( token:: Plus ) => Some ( KleeneOp :: OneOrMore ) ,
348
- _ => None ,
370
+ // We basically look at two token trees here, denoted as #1 and #2 below
371
+ let span = match parse_kleene_op ( input, span) {
372
+ // #1 is a `+` or `*` KleeneOp
373
+ //
374
+ // `?` is ambiguous: it could be a separator or a Kleene::ZeroOrOne, so we need to look
375
+ // ahead one more token to be sure.
376
+ Ok ( Ok ( op) ) if op != KleeneOp :: ZeroOrOne => return ( None , op) ,
377
+
378
+ // #1 is `?` token, but it could be a Kleene::ZeroOrOne without a separator or it could
379
+ // be a `?` separator followed by any Kleene operator. We need to look ahead 1 token to
380
+ // find out which.
381
+ Ok ( Ok ( op) ) => {
382
+ // Lookahead at #2. If it is a KleenOp, then #1 is a separator.
383
+ let is_1_sep = if let Some ( & tokenstream:: TokenTree :: Token ( _, ref tok2) ) = input. peek ( ) {
384
+ kleene_op ( tok2) . is_some ( )
385
+ } else {
386
+ false
387
+ } ;
388
+
389
+ if is_1_sep {
390
+ // #1 is a separator and #2 should be a KleepeOp::*
391
+ // (N.B. We need to advance the input iterator.)
392
+ match parse_kleene_op ( input, span) {
393
+ // #2 is a KleeneOp (this is the only valid option) :)
394
+ Ok ( Ok ( op) ) => return ( Some ( token:: Question ) , op) ,
395
+
396
+ // #2 is a random token (this is an error) :(
397
+ Ok ( Err ( ( _, span) ) ) => span,
398
+
399
+ // #2 is not even a token at all :(
400
+ Err ( span) => span,
401
+ }
402
+ } else {
403
+ // #2 is a random tree and #1 is KleeneOp::ZeroOrOne
404
+ return ( None , op) ;
405
+ }
349
406
}
350
- }
351
407
352
- // We attempt to look at the next two token trees in `input`. I will call the first #1 and the
353
- // second #2. If #1 and #2 don't match a valid KleeneOp with/without separator, that is an
354
- // error, and we should emit an error on the most specific span possible.
355
- let span = match input. next ( ) {
356
- // #1 is a token
357
- Some ( tokenstream:: TokenTree :: Token ( span, tok) ) => match kleene_op ( & tok) {
358
- // #1 is a KleeneOp with no separator
359
- Some ( op) => return ( None , op) ,
360
-
361
- // #1 is not a KleeneOp, but may be a separator... need to look at #2
362
- None => match input. next ( ) {
363
- // #2 is a token
364
- Some ( tokenstream:: TokenTree :: Token ( span, tok2) ) => match kleene_op ( & tok2) {
365
- // #2 is a KleeneOp, so #1 must be a separator
366
- Some ( op) => return ( Some ( tok) , op) ,
367
-
368
- // #2 is not a KleeneOp... error
369
- None => span,
370
- } ,
371
-
372
- // #2 is not a token at all... error
373
- tree => tree. as_ref ( )
374
- . map ( tokenstream:: TokenTree :: span)
375
- . unwrap_or ( span) ,
376
- } ,
377
- } ,
408
+ // #1 is a separator followed by #2, a KleeneOp
409
+ Ok ( Err ( ( tok, span) ) ) => match parse_kleene_op ( input, span) {
410
+ // #2 is a KleeneOp :D
411
+ Ok ( Ok ( op) ) => return ( Some ( tok) , op) ,
412
+
413
+ // #2 is a random token :(
414
+ Ok ( Err ( ( _, span) ) ) => span,
415
+
416
+ // #2 is not a token at all :(
417
+ Err ( span) => span,
418
+ }
378
419
379
- // #1 is not a token at all... error
380
- tree => tree. as_ref ( )
381
- . map ( tokenstream:: TokenTree :: span)
382
- . unwrap_or ( span) ,
420
+ // #1 is not a token
421
+ Err ( span) => span,
383
422
} ;
384
423
385
- // Error...
386
- sess. span_diagnostic . span_err ( span, "expected `*` or `+`" ) ;
424
+ sess. span_diagnostic . span_err ( span, "expected one of: `*`, `+`, or `?`" ) ;
387
425
( None , KleeneOp :: ZeroOrMore )
388
426
}
0 commit comments