88// option. This file may not be copied, modified, or distributed
99// except according to those terms.
1010
11- use ast;
11+ use { ast, attr } ;
1212use ext:: tt:: macro_parser;
13+ use feature_gate:: { self , emit_feature_err, Features , GateIssue } ;
1314use parse:: { token, ParseSess } ;
1415use print:: pprust;
1516use symbol:: keywords;
1617use syntax_pos:: { BytePos , Span , DUMMY_SP } ;
1718use tokenstream;
1819
20+ use std:: cell:: RefCell ;
21+ use std:: iter:: Peekable ;
1922use std:: rc:: Rc ;
2023
2124/// Contains the sub-token-trees of a "delimited" token tree, such as the contents of `(`. Note
@@ -78,6 +81,7 @@ pub enum KleeneOp {
7881 ZeroOrMore ,
7982 /// Kleene plus (`+`) for one or more repetitions
8083 OneOrMore ,
84+ ZeroOrOne ,
8185}
8286
8387/// Similar to `tokenstream::TokenTree`, except that `$i`, `$i:ident`, and `$(...)`
@@ -169,6 +173,8 @@ impl TokenTree {
169173/// `ident` are "matchers". They are not present in the body of a macro rule -- just in the
170174/// pattern, so we pass a parameter to indicate whether to expect them or not.
171175/// - `sess`: the parsing session. Any errors will be emitted to this session.
176+ /// - `features`, `attrs`: language feature flags and attributes so that we know whether to use
177+ /// unstable features or not.
172178///
173179/// # Returns
174180///
@@ -177,18 +183,19 @@ pub fn parse(
177183 input : tokenstream:: TokenStream ,
178184 expect_matchers : bool ,
179185 sess : & ParseSess ,
186+ features : & RefCell < Features > ,
187+ attrs : & [ ast:: Attribute ] ,
180188) -> Vec < TokenTree > {
181189 // Will contain the final collection of `self::TokenTree`
182190 let mut result = Vec :: new ( ) ;
183191
184192 // For each token tree in `input`, parse the token into a `self::TokenTree`, consuming
185193 // additional trees if need be.
186- let mut trees = input. trees ( ) ;
194+ let mut trees = input. trees ( ) . peekable ( ) ;
187195 while let Some ( tree) = trees. next ( ) {
188- let tree = parse_tree ( tree, & mut trees, expect_matchers, sess) ;
189-
190196 // Given the parsed tree, if there is a metavar and we are expecting matchers, actually
191197 // parse out the matcher (i.e. in `$id:ident` this would parse the `:` and `ident`).
198+ let tree = parse_tree ( tree, & mut trees, expect_matchers, sess, features, attrs) ;
192199 match tree {
193200 TokenTree :: MetaVar ( start_sp, ident) if expect_matchers => {
194201 let span = match trees. next ( ) {
@@ -237,11 +244,15 @@ pub fn parse(
237244/// converting `tree`
238245/// - `expect_matchers`: same as for `parse` (see above).
239246/// - `sess`: the parsing session. Any errors will be emitted to this session.
247+ /// - `features`, `attrs`: language feature flags and attributes so that we know whether to use
248+ /// unstable features or not.
240249fn parse_tree < I > (
241250 tree : tokenstream:: TokenTree ,
242- trees : & mut I ,
251+ trees : & mut Peekable < I > ,
243252 expect_matchers : bool ,
244253 sess : & ParseSess ,
254+ features : & RefCell < Features > ,
255+ attrs : & [ ast:: Attribute ] ,
245256) -> TokenTree
246257where
247258 I : Iterator < Item = tokenstream:: TokenTree > ,
@@ -260,9 +271,9 @@ where
260271 sess. span_diagnostic . span_err ( span, & msg) ;
261272 }
262273 // Parse the contents of the sequence itself
263- let sequence = parse ( delimited. tts . into ( ) , expect_matchers, sess) ;
274+ let sequence = parse ( delimited. tts . into ( ) , expect_matchers, sess, features , attrs ) ;
264275 // Get the Kleene operator and optional separator
265- let ( separator, op) = parse_sep_and_kleene_op ( trees, span, sess) ;
276+ let ( separator, op) = parse_sep_and_kleene_op ( trees, span, sess, features , attrs ) ;
266277 // Count the number of captured "names" (i.e. named metavars)
267278 let name_captures = macro_parser:: count_names ( & sequence) ;
268279 TokenTree :: Sequence (
@@ -315,12 +326,46 @@ where
315326 span,
316327 Rc :: new ( Delimited {
317328 delim : delimited. delim ,
318- tts : parse ( delimited. tts . into ( ) , expect_matchers, sess) ,
329+ tts : parse ( delimited. tts . into ( ) , expect_matchers, sess, features , attrs ) ,
319330 } ) ,
320331 ) ,
321332 }
322333}
323334
335+ /// Takes a token and returns `Some(KleeneOp)` if the token is `+` `*` or `?`. Otherwise, return
336+ /// `None`.
337+ fn kleene_op ( token : & token:: Token ) -> Option < KleeneOp > {
338+ match * token {
339+ token:: BinOp ( token:: Star ) => Some ( KleeneOp :: ZeroOrMore ) ,
340+ token:: BinOp ( token:: Plus ) => Some ( KleeneOp :: OneOrMore ) ,
341+ token:: Question => Some ( KleeneOp :: ZeroOrOne ) ,
342+ _ => None ,
343+ }
344+ }
345+
346+ /// Parse the next token tree of the input looking for a KleeneOp. Returns
347+ ///
348+ /// - Ok(Ok(op)) if the next token tree is a KleeneOp
349+ /// - Ok(Err(tok, span)) if the next token tree is a token but not a KleeneOp
350+ /// - Err(span) if the next token tree is not a token
351+ fn parse_kleene_op < I > (
352+ input : & mut I ,
353+ span : Span ,
354+ ) -> Result < Result < KleeneOp , ( token:: Token , Span ) > , Span >
355+ where
356+ I : Iterator < Item = tokenstream:: TokenTree > ,
357+ {
358+ match input. next ( ) {
359+ Some ( tokenstream:: TokenTree :: Token ( span, tok) ) => match kleene_op ( & tok) {
360+ Some ( op) => Ok ( Ok ( op) ) ,
361+ None => Ok ( Err ( ( tok, span) ) ) ,
362+ } ,
363+ tree => Err ( tree. as_ref ( )
364+ . map ( tokenstream:: TokenTree :: span)
365+ . unwrap_or ( span) ) ,
366+ }
367+ }
368+
324369/// Attempt to parse a single Kleene star, possibly with a separator.
325370///
326371/// For example, in a pattern such as `$(a),*`, `a` is the pattern to be repeated, `,` is the
@@ -334,55 +379,121 @@ where
334379/// operator and separator, then a tuple with `(separator, KleeneOp)` is returned. Otherwise, an
335380/// error with the appropriate span is emitted to `sess` and a dummy value is returned.
336381fn parse_sep_and_kleene_op < I > (
337- input : & mut I ,
382+ input : & mut Peekable < I > ,
338383 span : Span ,
339384 sess : & ParseSess ,
385+ features : & RefCell < Features > ,
386+ attrs : & [ ast:: Attribute ] ,
340387) -> ( Option < token:: Token > , KleeneOp )
341388where
342389 I : Iterator < Item = tokenstream:: TokenTree > ,
343390{
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 ,
391+ // We basically look at two token trees here, denoted as #1 and #2 below
392+ let span = match parse_kleene_op ( input, span) {
393+ // #1 is a `+` or `*` KleeneOp
394+ //
395+ // `?` is ambiguous: it could be a separator or a Kleene::ZeroOrOne, so we need to look
396+ // ahead one more token to be sure.
397+ Ok ( Ok ( op) ) if op != KleeneOp :: ZeroOrOne => return ( None , op) ,
398+
399+ // #1 is `?` token, but it could be a Kleene::ZeroOrOne without a separator or it could
400+ // be a `?` separator followed by any Kleene operator. We need to look ahead 1 token to
401+ // find out which.
402+ Ok ( Ok ( op) ) => {
403+ assert_eq ! ( op, KleeneOp :: ZeroOrOne ) ;
404+
405+ // Lookahead at #2. If it is a KleenOp, then #1 is a separator.
406+ let is_1_sep = if let Some ( & tokenstream:: TokenTree :: Token ( _, ref tok2) ) = input. peek ( ) {
407+ kleene_op ( tok2) . is_some ( )
408+ } else {
409+ false
410+ } ;
411+
412+ if is_1_sep {
413+ // #1 is a separator and #2 should be a KleepeOp::*
414+ // (N.B. We need to advance the input iterator.)
415+ match parse_kleene_op ( input, span) {
416+ // #2 is a KleeneOp (this is the only valid option) :)
417+ Ok ( Ok ( op) ) if op == KleeneOp :: ZeroOrOne => {
418+ if !features. borrow ( ) . macro_at_most_once_rep
419+ && !attr:: contains_name ( attrs, "allow_internal_unstable" )
420+ {
421+ let explain = feature_gate:: EXPLAIN_MACRO_AT_MOST_ONCE_REP ;
422+ emit_feature_err (
423+ sess,
424+ "macro_at_most_once_rep" ,
425+ span,
426+ GateIssue :: Language ,
427+ explain,
428+ ) ;
429+ }
430+ return ( Some ( token:: Question ) , op) ;
431+ }
432+ Ok ( Ok ( op) ) => return ( Some ( token:: Question ) , op) ,
433+
434+ // #2 is a random token (this is an error) :(
435+ Ok ( Err ( ( _, span) ) ) => span,
436+
437+ // #2 is not even a token at all :(
438+ Err ( span) => span,
439+ }
440+ } else {
441+ if !features. borrow ( ) . macro_at_most_once_rep
442+ && !attr:: contains_name ( attrs, "allow_internal_unstable" )
443+ {
444+ let explain = feature_gate:: EXPLAIN_MACRO_AT_MOST_ONCE_REP ;
445+ emit_feature_err (
446+ sess,
447+ "macro_at_most_once_rep" ,
448+ span,
449+ GateIssue :: Language ,
450+ explain,
451+ ) ;
452+ }
453+
454+ // #2 is a random tree and #1 is KleeneOp::ZeroOrOne
455+ return ( None , op) ;
456+ }
349457 }
350- }
351458
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- } ,
459+ // #1 is a separator followed by #2, a KleeneOp
460+ Ok ( Err ( ( tok , span ) ) ) => match parse_kleene_op ( input , span ) {
461+ // #2 is a KleeneOp :D
462+ Ok ( Ok ( op ) ) if op == KleeneOp :: ZeroOrOne => {
463+ if !features . borrow ( ) . macro_at_most_once_rep
464+ && !attr :: contains_name ( attrs , "allow_internal_unstable" )
465+ {
466+ let explain = feature_gate :: EXPLAIN_MACRO_AT_MOST_ONCE_REP ;
467+ emit_feature_err (
468+ sess ,
469+ "macro_at_most_once_rep" ,
470+ span ,
471+ GateIssue :: Language ,
472+ explain ,
473+ ) ;
474+ }
475+ return ( Some ( tok ) , op ) ;
476+ }
477+ Ok ( Ok ( op ) ) => return ( Some ( tok ) , op ) ,
478+
479+ // #2 is a random token :(
480+ Ok ( Err ( ( _ , span ) ) ) => span ,
481+
482+ // #2 is not a token at all :(
483+ Err ( span ) => span ,
377484 } ,
378485
379- // #1 is not a token at all... error
380- tree => tree. as_ref ( )
381- . map ( tokenstream:: TokenTree :: span)
382- . unwrap_or ( span) ,
486+ // #1 is not a token
487+ Err ( span) => span,
383488 } ;
384489
385- // Error...
386- sess. span_diagnostic . span_err ( span, "expected `*` or `+`" ) ;
490+ if !features. borrow ( ) . macro_at_most_once_rep
491+ && !attr:: contains_name ( attrs, "allow_internal_unstable" )
492+ {
493+ sess. span_diagnostic
494+ . span_err ( span, "expected one of: `*`, `+`, or `?`" ) ;
495+ } else {
496+ sess. span_diagnostic . span_err ( span, "expected `*` or `+`" ) ;
497+ }
387498 ( None , KleeneOp :: ZeroOrMore )
388499}
0 commit comments