diff options
| author | Julien Cretin <cretin@google.com> | 2019-05-29 20:29:51 +0200 |
|---|---|---|
| committer | Julien Cretin <cretin@google.com> | 2019-07-19 19:59:11 +0200 |
| commit | 82abc0db816e7441a0d89a3eaa51f439a03f4506 (patch) | |
| tree | 9674a3548e72a1b15ef4a05022ebd2dd6cfa36ad | |
| parent | 527dce7137f7a3c7bf47d9a503abf25f88ea22de (diff) | |
| download | rust-82abc0db816e7441a0d89a3eaa51f439a03f4506.tar.gz rust-82abc0db816e7441a0d89a3eaa51f439a03f4506.zip | |
Remember the span of the Kleene operator in macros
This is needed for having complete error messages where reporting macro variable
errors. Here is what they would look like:
error: meta-variable repeats with different kleene operator
--> $DIR/issue-61053-different-kleene.rs:3:57
|
LL | ( $( $i:ident = $($j:ident),+ );* ) => { $( $( $i = $j; )* )* };
| - expected repetition ^^ - conflicting repetition
| -rw-r--r-- | src/libsyntax/ext/tt/macro_parser.rs | 6 | ||||
| -rw-r--r-- | src/libsyntax/ext/tt/macro_rules.rs | 16 | ||||
| -rw-r--r-- | src/libsyntax/ext/tt/quoted.rs | 30 | ||||
| -rw-r--r-- | src/libsyntax/ext/tt/transcribe.rs | 2 |
4 files changed, 33 insertions, 21 deletions
diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index fc8aa4793bc..ae1979540ff 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -557,8 +557,8 @@ fn inner_parse_loop<'root, 'tt>( // implicitly disallowing OneOrMore from having 0 matches here. Thus, that will // result in a "no rules expected token" error by virtue of this matcher not // working. - if seq.op == quoted::KleeneOp::ZeroOrMore - || seq.op == quoted::KleeneOp::ZeroOrOne + if seq.kleene.op == quoted::KleeneOp::ZeroOrMore + || seq.kleene.op == quoted::KleeneOp::ZeroOrOne { let mut new_item = item.clone(); new_item.match_cur += seq.num_captures; @@ -573,7 +573,7 @@ fn inner_parse_loop<'root, 'tt>( cur_items.push(MatcherPosHandle::Box(Box::new(MatcherPos { stack: smallvec![], sep: seq.separator.clone(), - seq_op: Some(seq.op), + seq_op: Some(seq.kleene.op), idx: 0, matches, match_lo: item.match_cur, diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 5c6438a7ef5..54f901d095b 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -273,7 +273,7 @@ pub fn compile( if body.legacy { token::Semi } else { token::Comma }, def.span, )), - op: quoted::KleeneOp::OneOrMore, + kleene: quoted::KleeneToken::new(quoted::KleeneOp::OneOrMore, def.span), num_captures: 2, }), ), @@ -283,7 +283,7 @@ pub fn compile( Lrc::new(quoted::SequenceRepetition { tts: vec![quoted::TokenTree::token(token::Semi, def.span)], separator: None, - op: quoted::KleeneOp::ZeroOrMore, + kleene: quoted::KleeneToken::new(quoted::KleeneOp::ZeroOrMore, def.span), num_captures: 0, }), ), @@ -477,8 +477,8 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[quoted::TokenTree]) -> bool { && seq.tts.iter().all(|seq_tt| match *seq_tt { TokenTree::MetaVarDecl(_, _, id) => id.name == sym::vis, TokenTree::Sequence(_, ref sub_seq) => { - sub_seq.op == quoted::KleeneOp::ZeroOrMore - || sub_seq.op == quoted::KleeneOp::ZeroOrOne + sub_seq.kleene.op == quoted::KleeneOp::ZeroOrMore + || sub_seq.kleene.op == quoted::KleeneOp::ZeroOrOne } _ => false, }) @@ -628,8 +628,8 @@ impl FirstSets { // Reverse scan: Sequence comes before `first`. if subfirst.maybe_empty - || seq_rep.op == quoted::KleeneOp::ZeroOrMore - || seq_rep.op == quoted::KleeneOp::ZeroOrOne + || seq_rep.kleene.op == quoted::KleeneOp::ZeroOrMore + || seq_rep.kleene.op == quoted::KleeneOp::ZeroOrOne { // If sequence is potentially empty, then // union them (preserving first emptiness). @@ -677,8 +677,8 @@ impl FirstSets { assert!(first.maybe_empty); first.add_all(subfirst); if subfirst.maybe_empty - || seq_rep.op == quoted::KleeneOp::ZeroOrMore - || seq_rep.op == quoted::KleeneOp::ZeroOrOne + || seq_rep.kleene.op == quoted::KleeneOp::ZeroOrMore + || seq_rep.kleene.op == quoted::KleeneOp::ZeroOrOne { // continue scanning for more first // tokens, but also make sure we diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs index ccf9db842ab..eff6b9dd429 100644 --- a/src/libsyntax/ext/tt/quoted.rs +++ b/src/libsyntax/ext/tt/quoted.rs @@ -50,11 +50,23 @@ pub struct SequenceRepetition { /// The optional separator pub separator: Option<Token>, /// Whether the sequence can be repeated zero (*), or one or more times (+) - pub op: KleeneOp, + pub kleene: KleeneToken, /// The number of `Match`s that appear in the sequence (and subsequences) pub num_captures: usize, } +#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)] +pub struct KleeneToken { + pub span: Span, + pub op: KleeneOp, +} + +impl KleeneToken { + pub fn new(op: KleeneOp, span: Span) -> KleeneToken { + KleeneToken { span, op } + } +} + /// A Kleene-style [repetition operator](http://en.wikipedia.org/wiki/Kleene_star) /// for token sequences. #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] @@ -273,7 +285,7 @@ fn parse_tree( macro_node_id, ); // Get the Kleene operator and optional separator - let (separator, op) = parse_sep_and_kleene_op(trees, span.entire(), sess); + let (separator, kleene) = parse_sep_and_kleene_op(trees, span.entire(), sess); // Count the number of captured "names" (i.e., named metavars) let name_captures = macro_parser::count_names(&sequence); TokenTree::Sequence( @@ -281,7 +293,7 @@ fn parse_tree( Lrc::new(SequenceRepetition { tts: sequence, separator, - op, + kleene, num_captures: name_captures, }), ) @@ -379,16 +391,16 @@ fn parse_sep_and_kleene_op( input: &mut Peekable<impl Iterator<Item = tokenstream::TokenTree>>, span: Span, sess: &ParseSess, -) -> (Option<Token>, KleeneOp) { +) -> (Option<Token>, KleeneToken) { // We basically look at two token trees here, denoted as #1 and #2 below let span = match parse_kleene_op(input, span) { // #1 is a `?`, `+`, or `*` KleeneOp - Ok(Ok((op, _))) => return (None, op), + Ok(Ok((op, span))) => return (None, KleeneToken::new(op, span)), // #1 is a separator followed by #2, a KleeneOp Ok(Err(token)) => match parse_kleene_op(input, token.span) { // #2 is the `?` Kleene op, which does not take a separator (error) - Ok(Ok((KleeneOp::ZeroOrOne, _))) => { + Ok(Ok((KleeneOp::ZeroOrOne, span))) => { // Error! sess.span_diagnostic.span_err( token.span, @@ -396,11 +408,11 @@ fn parse_sep_and_kleene_op( ); // Return a dummy - return (None, KleeneOp::ZeroOrMore); + return (None, KleeneToken::new(KleeneOp::ZeroOrMore, span)); } // #2 is a KleeneOp :D - Ok(Ok((op, _))) => return (Some(token), op), + Ok(Ok((op, span))) => return (Some(token), KleeneToken::new(op, span)), // #2 is a random token or not a token at all :( Ok(Err(Token { span, .. })) | Err(span) => span, @@ -414,5 +426,5 @@ fn parse_sep_and_kleene_op( sess.span_diagnostic.span_err(span, "expected one of: `*`, `+`, or `?`"); // Return a dummy - (None, KleeneOp::ZeroOrMore) + (None, KleeneToken::new(KleeneOp::ZeroOrMore, span)) } diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index e04fd2ddc05..93a2f506901 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -183,7 +183,7 @@ pub fn transcribe( // Is the repetition empty? if len == 0 { - if seq.op == quoted::KleeneOp::OneOrMore { + if seq.kleene.op == quoted::KleeneOp::OneOrMore { // FIXME: this really ought to be caught at macro definition // time... It happens when the Kleene operator in the matcher and // the body for the same meta-variable do not match. |
