@@ -325,42 +325,55 @@ fn check_matcher<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token)
325
325
last = match * token {
326
326
TtToken ( sp, MatchNt ( ref name, ref frag_spec, _, _) ) => {
327
327
// ii. If T is a simple NT, look ahead to the next token T' in
328
- // M.
329
- let next_token = match tokens. peek ( ) {
330
- // If T' closes a complex NT, replace T' with F
331
- Some ( & & TtToken ( _, CloseDelim ( _) ) ) => follow. clone ( ) ,
332
- Some ( & & TtToken ( _, ref tok) ) => tok. clone ( ) ,
333
- Some ( & & TtSequence ( sp, _) ) => {
334
- cx. span_err ( sp,
335
- & format ! ( "`${0}:{1}` is followed by a \
336
- sequence repetition, which is not \
337
- allowed for `{1}` fragments",
338
- name. as_str( ) , frag_spec. as_str( ) )
328
+ // M. If T' is in the set FOLLOW(NT), continue. Else; reject.
329
+ if can_be_followed_by_any ( frag_spec. as_str ( ) ) {
330
+ continue
331
+ } else {
332
+ let next_token = match tokens. peek ( ) {
333
+ // If T' closes a complex NT, replace T' with F
334
+ Some ( & & TtToken ( _, CloseDelim ( _) ) ) => follow. clone ( ) ,
335
+ Some ( & & TtToken ( _, ref tok) ) => tok. clone ( ) ,
336
+ Some ( & & TtSequence ( sp, _) ) => {
337
+ // Be conservative around sequences: to be
338
+ // more specific, we would need to
339
+ // consider FIRST sets, but also the
340
+ // possibility that the sequence occurred
341
+ // zero times (in which case we need to
342
+ // look at the token that follows the
343
+ // sequence, which may itself a sequence,
344
+ // and so on).
345
+ cx. span_err ( sp,
346
+ & format ! ( "`${0}:{1}` is followed by a \
347
+ sequence repetition, which is not \
348
+ allowed for `{1}` fragments",
349
+ name. as_str( ) , frag_spec. as_str( ) )
339
350
) ;
340
- Eof
341
- } ,
342
- // die next iteration
343
- Some ( & & TtDelimited ( _, ref delim) ) => delim. close_token ( ) ,
344
- // else, we're at the end of the macro or sequence
345
- None => follow. clone ( )
346
- } ;
347
-
348
- let tok = if let TtToken ( _, ref tok) = * token { tok } else { unreachable ! ( ) } ;
349
- // If T' is in the set FOLLOW(NT), continue. Else, reject.
350
- match ( & next_token, is_in_follow ( cx, & next_token, frag_spec. as_str ( ) ) ) {
351
- ( _, Err ( msg) ) => {
352
- cx. span_err ( sp, & msg) ;
353
- continue
351
+ Eof
352
+ } ,
353
+ // die next iteration
354
+ Some ( & & TtDelimited ( _, ref delim) ) => delim. close_token ( ) ,
355
+ // else, we're at the end of the macro or sequence
356
+ None => follow. clone ( )
357
+ } ;
358
+
359
+ let tok = if let TtToken ( _, ref tok) = * token { tok } else { unreachable ! ( ) } ;
360
+
361
+ // If T' is in the set FOLLOW(NT), continue. Else, reject.
362
+ match ( & next_token, is_in_follow ( cx, & next_token, frag_spec. as_str ( ) ) ) {
363
+ ( _, Err ( msg) ) => {
364
+ cx. span_err ( sp, & msg) ;
365
+ continue
366
+ }
367
+ ( & Eof , _) => return Some ( ( sp, tok. clone ( ) ) ) ,
368
+ ( _, Ok ( true ) ) => continue ,
369
+ ( next, Ok ( false ) ) => {
370
+ cx. span_err ( sp, & format ! ( "`${0}:{1}` is followed by `{2}`, which \
371
+ is not allowed for `{1}` fragments",
372
+ name. as_str( ) , frag_spec. as_str( ) ,
373
+ token_to_string( next) ) ) ;
374
+ continue
375
+ } ,
354
376
}
355
- ( & Eof , _) => return Some ( ( sp, tok. clone ( ) ) ) ,
356
- ( _, Ok ( true ) ) => continue ,
357
- ( next, Ok ( false ) ) => {
358
- cx. span_err ( sp, & format ! ( "`${0}:{1}` is followed by `{2}`, which \
359
- is not allowed for `{1}` fragments",
360
- name. as_str( ) , frag_spec. as_str( ) ,
361
- token_to_string( next) ) ) ;
362
- continue
363
- } ,
364
377
}
365
378
} ,
366
379
TtSequence ( sp, ref seq) => {
@@ -427,8 +440,39 @@ fn check_matcher<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token)
427
440
last
428
441
}
429
442
443
+ /// True if a fragment of type `frag` can be followed by any sort of
444
+ /// token. We use this (among other things) as a useful approximation
445
+ /// for when `frag` can be followed by a repetition like `$(...)*` or
446
+ /// `$(...)+`. In general, these can be a bit tricky to reason about,
447
+ /// so we adopt a conservative position that says that any fragment
448
+ /// specifier which consumes at most one token tree can be followed by
449
+ /// a fragment specifier (indeed, these fragments can be followed by
450
+ /// ANYTHING without fear of future compatibility hazards).
451
+ fn can_be_followed_by_any ( frag : & str ) -> bool {
452
+ match frag {
453
+ "item" | // always terminated by `}` or `;`
454
+ "block" | // exactly one token tree
455
+ "ident" | // exactly one token tree
456
+ "meta" | // exactly one token tree
457
+ "tt" => // exactly one token tree
458
+ true ,
459
+
460
+ _ =>
461
+ false ,
462
+ }
463
+ }
464
+
465
+ /// True if `frag` can legally be followed by the token `tok`. For
466
+ /// fragments that can consume an unbounded numbe of tokens, `tok`
467
+ /// must be within a well-defined follow set. This is intended to
468
+ /// guarantee future compatibility: for example, without this rule, if
469
+ /// we expanded `expr` to include a new binary operator, we might
470
+ /// break macros that were relying on that binary operator as a
471
+ /// separator.
430
472
fn is_in_follow ( _: & ExtCtxt , tok : & Token , frag : & str ) -> Result < bool , String > {
431
473
if let & CloseDelim ( _) = tok {
474
+ // closing a token tree can never be matched by any fragment;
475
+ // iow, we always require that `(` and `)` match, etc.
432
476
Ok ( true )
433
477
} else {
434
478
match frag {
0 commit comments