8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
- use ast;
11
+ use { ast, attr } ;
12
12
use ext:: tt:: macro_parser;
13
+ use feature_gate:: { self , emit_feature_err, Features , GateIssue } ;
13
14
use parse:: { token, ParseSess } ;
14
15
use print:: pprust;
15
16
use symbol:: keywords;
16
17
use syntax_pos:: { BytePos , Span , DUMMY_SP } ;
17
18
use tokenstream;
18
19
20
+ use std:: cell:: RefCell ;
21
+ use std:: iter:: Peekable ;
19
22
use std:: rc:: Rc ;
20
23
21
24
/// Contains the sub-token-trees of a "delimited" token tree, such as the contents of `(`. Note
@@ -78,6 +81,7 @@ pub enum KleeneOp {
78
81
ZeroOrMore ,
79
82
/// Kleene plus (`+`) for one or more repetitions
80
83
OneOrMore ,
84
+ ZeroOrOne ,
81
85
}
82
86
83
87
/// Similar to `tokenstream::TokenTree`, except that `$i`, `$i:ident`, and `$(...)`
@@ -169,6 +173,8 @@ impl TokenTree {
169
173
/// `ident` are "matchers". They are not present in the body of a macro rule -- just in the
170
174
/// pattern, so we pass a parameter to indicate whether to expect them or not.
171
175
/// - `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.
172
178
///
173
179
/// # Returns
174
180
///
@@ -177,18 +183,19 @@ pub fn parse(
177
183
input : tokenstream:: TokenStream ,
178
184
expect_matchers : bool ,
179
185
sess : & ParseSess ,
186
+ features : & RefCell < Features > ,
187
+ attrs : & [ ast:: Attribute ] ,
180
188
) -> Vec < TokenTree > {
181
189
// Will contain the final collection of `self::TokenTree`
182
190
let mut result = Vec :: new ( ) ;
183
191
184
192
// For each token tree in `input`, parse the token into a `self::TokenTree`, consuming
185
193
// additional trees if need be.
186
- let mut trees = input. trees ( ) ;
194
+ let mut trees = input. trees ( ) . peekable ( ) ;
187
195
while let Some ( tree) = trees. next ( ) {
188
- let tree = parse_tree ( tree, & mut trees, expect_matchers, sess) ;
189
-
190
196
// Given the parsed tree, if there is a metavar and we are expecting matchers, actually
191
197
// 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) ;
192
199
match tree {
193
200
TokenTree :: MetaVar ( start_sp, ident) if expect_matchers => {
194
201
let span = match trees. next ( ) {
@@ -237,11 +244,15 @@ pub fn parse(
237
244
/// converting `tree`
238
245
/// - `expect_matchers`: same as for `parse` (see above).
239
246
/// - `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.
240
249
fn parse_tree < I > (
241
250
tree : tokenstream:: TokenTree ,
242
- trees : & mut I ,
251
+ trees : & mut Peekable < I > ,
243
252
expect_matchers : bool ,
244
253
sess : & ParseSess ,
254
+ features : & RefCell < Features > ,
255
+ attrs : & [ ast:: Attribute ] ,
245
256
) -> TokenTree
246
257
where
247
258
I : Iterator < Item = tokenstream:: TokenTree > ,
@@ -260,9 +271,9 @@ where
260
271
sess. span_diagnostic . span_err ( span, & msg) ;
261
272
}
262
273
// 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 ) ;
264
275
// 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 ) ;
266
277
// Count the number of captured "names" (i.e. named metavars)
267
278
let name_captures = macro_parser:: count_names ( & sequence) ;
268
279
TokenTree :: Sequence (
@@ -315,12 +326,46 @@ where
315
326
span,
316
327
Rc :: new ( Delimited {
317
328
delim : delimited. delim ,
318
- tts : parse ( delimited. tts . into ( ) , expect_matchers, sess) ,
329
+ tts : parse ( delimited. tts . into ( ) , expect_matchers, sess, features , attrs ) ,
319
330
} ) ,
320
331
) ,
321
332
}
322
333
}
323
334
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
+
324
369
/// Attempt to parse a single Kleene star, possibly with a separator.
325
370
///
326
371
/// For example, in a pattern such as `$(a),*`, `a` is the pattern to be repeated, `,` is the
@@ -334,55 +379,121 @@ where
334
379
/// operator and separator, then a tuple with `(separator, KleeneOp)` is returned. Otherwise, an
335
380
/// error with the appropriate span is emitted to `sess` and a dummy value is returned.
336
381
fn parse_sep_and_kleene_op < I > (
337
- input : & mut I ,
382
+ input : & mut Peekable < I > ,
338
383
span : Span ,
339
384
sess : & ParseSess ,
385
+ features : & RefCell < Features > ,
386
+ attrs : & [ ast:: Attribute ] ,
340
387
) -> ( Option < token:: Token > , KleeneOp )
341
388
where
342
389
I : Iterator < Item = tokenstream:: TokenTree > ,
343
390
{
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
+ }
349
457
}
350
- }
351
458
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 ,
377
484
} ,
378
485
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,
383
488
} ;
384
489
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
+ }
387
498
( None , KleeneOp :: ZeroOrMore )
388
499
}
0 commit comments