@@ -386,26 +386,72 @@ where
386
386
{
387
387
// We basically look at two token trees here, denoted as #1 and #2 below
388
388
let span = match parse_kleene_op ( input, span) {
389
- // #1 is any KleeneOp (`?`)
390
- Ok ( Ok ( op) ) if op == KleeneOp :: ZeroOrOne => {
391
- if !features. macro_at_most_once_rep
392
- && !attr:: contains_name ( attrs, "allow_internal_unstable" )
393
- {
394
- let explain = feature_gate:: EXPLAIN_MACRO_AT_MOST_ONCE_REP ;
395
- emit_feature_err (
396
- sess,
397
- "macro_at_most_once_rep" ,
398
- span,
399
- GateIssue :: Language ,
400
- explain,
401
- ) ;
389
+ // #1 is a `+` or `*` KleeneOp
390
+ //
391
+ // `?` is ambiguous: it could be a separator or a Kleene::ZeroOrOne, so we need to look
392
+ // ahead one more token to be sure.
393
+ Ok ( Ok ( op) ) if op != KleeneOp :: ZeroOrOne => return ( None , op) ,
394
+
395
+ // #1 is `?` token, but it could be a Kleene::ZeroOrOne without a separator or it could
396
+ // be a `?` separator followed by any Kleene operator. We need to look ahead 1 token to
397
+ // find out which.
398
+ Ok ( Ok ( op) ) => {
399
+ assert_eq ! ( op, KleeneOp :: ZeroOrOne ) ;
400
+
401
+ // Lookahead at #2. If it is a KleenOp, then #1 is a separator.
402
+ let is_1_sep = if let Some ( & tokenstream:: TokenTree :: Token ( _, ref tok2) ) = input. peek ( ) {
403
+ kleene_op ( tok2) . is_some ( )
404
+ } else {
405
+ false
406
+ } ;
407
+
408
+ if is_1_sep {
409
+ // #1 is a separator and #2 should be a KleepeOp::*
410
+ // (N.B. We need to advance the input iterator.)
411
+ match parse_kleene_op ( input, span) {
412
+ // #2 is a KleeneOp (this is the only valid option) :)
413
+ Ok ( Ok ( op) ) if op == KleeneOp :: ZeroOrOne => {
414
+ if !features. macro_at_most_once_rep
415
+ && !attr:: contains_name ( attrs, "allow_internal_unstable" )
416
+ {
417
+ let explain = feature_gate:: EXPLAIN_MACRO_AT_MOST_ONCE_REP ;
418
+ emit_feature_err (
419
+ sess,
420
+ "macro_at_most_once_rep" ,
421
+ span,
422
+ GateIssue :: Language ,
423
+ explain,
424
+ ) ;
425
+ }
426
+ return ( Some ( token:: Question ) , op) ;
427
+ }
428
+ Ok ( Ok ( op) ) => return ( Some ( token:: Question ) , op) ,
429
+
430
+ // #2 is a random token (this is an error) :(
431
+ Ok ( Err ( ( _, span) ) ) => span,
432
+
433
+ // #2 is not even a token at all :(
434
+ Err ( span) => span,
435
+ }
436
+ } else {
437
+ if !features. macro_at_most_once_rep
438
+ && !attr:: contains_name ( attrs, "allow_internal_unstable" )
439
+ {
440
+ let explain = feature_gate:: EXPLAIN_MACRO_AT_MOST_ONCE_REP ;
441
+ emit_feature_err (
442
+ sess,
443
+ "macro_at_most_once_rep" ,
444
+ span,
445
+ GateIssue :: Language ,
446
+ explain,
447
+ ) ;
448
+ }
449
+
450
+ // #2 is a random tree and #1 is KleeneOp::ZeroOrOne
451
+ return ( None , op) ;
402
452
}
403
- return ( None , op) ;
404
453
}
405
454
406
- // #1 is any KleeneOp (`+`, `*`)
407
- Ok ( Ok ( op) ) => return ( None , op) ,
408
-
409
455
// #1 is a separator followed by #2, a KleeneOp
410
456
Ok ( Err ( ( tok, span) ) ) => match parse_kleene_op ( input, span) {
411
457
// #2 is a KleeneOp :D
@@ -421,11 +467,8 @@ where
421
467
GateIssue :: Language ,
422
468
explain,
423
469
) ;
424
- } else {
425
- sess. span_diagnostic
426
- . span_err ( span, "`?` macro repetition does not allow a separator" ) ;
427
470
}
428
- return ( None , op) ;
471
+ return ( Some ( tok ) , op) ;
429
472
}
430
473
Ok ( Ok ( op) ) => return ( Some ( tok) , op) ,
431
474
@@ -440,7 +483,9 @@ where
440
483
Err ( span) => span,
441
484
} ;
442
485
443
- if !features. macro_at_most_once_rep && !attr:: contains_name ( attrs, "allow_internal_unstable" ) {
486
+ if !features. macro_at_most_once_rep
487
+ && !attr:: contains_name ( attrs, "allow_internal_unstable" )
488
+ {
444
489
sess. span_diagnostic
445
490
. span_err ( span, "expected one of: `*`, `+`, or `?`" ) ;
446
491
} else {
0 commit comments