@@ -292,58 +292,102 @@ fn check_lhs_nt_follows(cx: &mut ExtCtxt, lhs: &NamedMatch, sp: Span) {
292292 _ => cx. span_bug ( sp, "wrong-structured lhs for follow check" )
293293 } ;
294294
295- check_matcher ( cx, matcher, & Eof ) ;
295+ check_matcher ( cx, matcher. iter ( ) , & Eof ) ;
296296 // we don't abort on errors on rejection, the driver will do that for us
297297 // after parsing/expansion. we can report every error in every macro this way.
298298}
299299
300- fn check_matcher ( cx : & mut ExtCtxt , matcher : & [ TokenTree ] , follow : & Token ) {
300+ // returns the last token that was checked, for TtSequence. this gets used later on.
301+ fn check_matcher < ' a , I > ( cx : & mut ExtCtxt , matcher : I , follow : & Token )
302+ -> Option < ( Span , Token ) > where I : Iterator < Item =& ' a TokenTree > {
301303 use print:: pprust:: token_to_string;
302304
303- // 1. If there are no tokens in M, accept
304- if matcher. is_empty ( ) {
305- return ;
306- }
305+ let mut last = None ;
307306
308307 // 2. For each token T in M:
309- let mut tokens = matcher. iter ( ) . peekable ( ) ;
308+ let mut tokens = matcher. peekable ( ) ;
310309 while let Some ( token) = tokens. next ( ) {
311- match * token {
310+ last = match * token {
312311 TtToken ( sp, MatchNt ( ref name, ref frag_spec, _, _) ) => {
313312 // ii. If T is a simple NT, look ahead to the next token T' in
314313 // M.
315314 let next_token = match tokens. peek ( ) {
316315 // If T' closes a complex NT, replace T' with F
317- Some ( & & TtToken ( _, CloseDelim ( _) ) ) => follow,
318- Some ( & & TtToken ( _, ref tok) ) => tok,
319- // T' is any NT (this catches complex NTs, the next
320- // iteration will die if it's a TtDelimited).
321- Some ( _) => continue ,
316+ Some ( & & TtToken ( _, CloseDelim ( _) ) ) => follow. clone ( ) ,
317+ Some ( & & TtToken ( _, ref tok) ) => tok. clone ( ) ,
318+ Some ( & & TtSequence ( sp, _) ) => {
319+ cx. span_err ( sp, format ! ( "`${0}:{1}` is followed by a sequence \
320+ repetition, which is not allowed for `{1}` \
321+ fragments", name. as_str( ) , frag_spec. as_str( ) ) [ ] ) ;
322+ Eof
323+ } ,
324+ // die next iteration
325+ Some ( & & TtDelimited ( _, ref delim) ) => delim. close_token ( ) ,
322326 // else, we're at the end of the macro or sequence
323- None => follow
327+ None => follow. clone ( )
324328 } ;
325329
330+ let tok = if let TtToken ( _, ref tok) = * token { tok } else { unreachable ! ( ) } ;
326331 // If T' is in the set FOLLOW(NT), continue. Else, reject.
327- match * next_token {
328- Eof | MatchNt ( ..) => continue ,
329- _ if is_in_follow ( cx, next_token, frag_spec. as_str ( ) ) => continue ,
330- ref tok => cx. span_err ( sp, format ! ( "`${0}:{1}` is followed by `{2}`, which \
331- is not allowed for `{1}` fragments",
332- name. as_str( ) , frag_spec. as_str( ) ,
333- token_to_string( tok) ) [ ] )
332+ match & next_token {
333+ & Eof => return Some ( ( sp, tok. clone ( ) ) ) ,
334+ _ if is_in_follow ( cx, & next_token, frag_spec. as_str ( ) ) => continue ,
335+ next => {
336+ cx. span_err ( sp, format ! ( "`${0}:{1}` is followed by `{2}`, which \
337+ is not allowed for `{1}` fragments",
338+ name. as_str( ) , frag_spec. as_str( ) ,
339+ token_to_string( next) ) [ ] ) ;
340+ continue
341+ } ,
334342 }
335343 } ,
336- TtSequence ( _ , ref seq) => {
344+ TtSequence ( sp , ref seq) => {
337345 // iii. Else, T is a complex NT.
338346 match seq. separator {
339347 // If T has the form $(...)U+ or $(...)U* for some token U,
340348 // run the algorithm on the contents with F set to U. If it
341349 // accepts, continue, else, reject.
342- Some ( ref u) => check_matcher ( cx, seq. tts [ ] , u) ,
343- // If T has the form $(...)+ or $(...)*, run the algorithm
344- // on the contents with F set to EOF. If it accepts,
345- // continue, else, reject.
346- None => check_matcher ( cx, seq. tts [ ] , & Eof )
350+ Some ( ref u) => {
351+ let last = check_matcher ( cx, seq. tts . iter ( ) , u) ;
352+ match last {
353+ // Since the delimiter isn't required after the last repetition, make
354+ // sure that the *next* token is sane. This doesn't actually compute
355+ // the FIRST of the rest of the matcher yet, it only considers single
356+ // tokens and simple NTs. This is imprecise, but conservatively
357+ // correct.
358+ Some ( ( span, tok) ) => {
359+ let fol = match tokens. peek ( ) {
360+ Some ( & & TtToken ( _, ref tok) ) => tok. clone ( ) ,
361+ Some ( & & TtDelimited ( _, ref delim) ) => delim. close_token ( ) ,
362+ Some ( _) => {
363+ cx. span_err ( sp, "sequence repetition followed by \
364+ another sequence repetition, which is not allowed") ;
365+ Eof
366+ } ,
367+ None => Eof
368+ } ;
369+ check_matcher ( cx, Some ( & TtToken ( span, tok. clone ( ) ) ) . into_iter ( ) ,
370+ & fol)
371+ } ,
372+ None => last,
373+ }
374+ } ,
375+ // If T has the form $(...)+ or $(...)*, run the algorithm on the contents with
376+ // F set to the token following the sequence. If it accepts, continue, else,
377+ // reject.
378+ None => {
379+ let fol = match tokens. peek ( ) {
380+ Some ( & & TtToken ( _, ref tok) ) => tok. clone ( ) ,
381+ Some ( & & TtDelimited ( _, ref delim) ) => delim. close_token ( ) ,
382+ Some ( _) => {
383+ cx. span_err ( sp, "sequence repetition followed by another \
384+ sequence repetition, which is not allowed") ;
385+ Eof
386+ } ,
387+ None => Eof
388+ } ;
389+ check_matcher ( cx, seq. tts . iter ( ) , & fol)
390+ }
347391 }
348392 } ,
349393 TtToken ( ..) => {
@@ -352,11 +396,12 @@ fn check_matcher(cx: &mut ExtCtxt, matcher: &[TokenTree], follow: &Token) {
352396 } ,
353397 TtDelimited ( _, ref tts) => {
354398 // if we don't pass in that close delimiter, we'll incorrectly consider the matcher
355- // `{ $foo:ty }` as having a follow that isn't `} `
356- check_matcher ( cx, tts. tts [ ] , & tts. close_token ( ) )
399+ // `{ $foo:ty }` as having a follow that isn't `RBrace `
400+ check_matcher ( cx, tts. tts . iter ( ) , & tts. close_token ( ) )
357401 }
358402 }
359403 }
404+ last
360405}
361406
362407fn is_in_follow ( cx : & ExtCtxt , tok : & Token , frag : & str ) -> bool {
0 commit comments