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
This commit is contained in:
parent
527dce7137
commit
82abc0db81
4 changed files with 33 additions and 21 deletions
|
@ -557,8 +557,8 @@ fn inner_parse_loop<'root, 'tt>(
|
||||||
// implicitly disallowing OneOrMore from having 0 matches here. Thus, that will
|
// 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
|
// result in a "no rules expected token" error by virtue of this matcher not
|
||||||
// working.
|
// working.
|
||||||
if seq.op == quoted::KleeneOp::ZeroOrMore
|
if seq.kleene.op == quoted::KleeneOp::ZeroOrMore
|
||||||
|| seq.op == quoted::KleeneOp::ZeroOrOne
|
|| seq.kleene.op == quoted::KleeneOp::ZeroOrOne
|
||||||
{
|
{
|
||||||
let mut new_item = item.clone();
|
let mut new_item = item.clone();
|
||||||
new_item.match_cur += seq.num_captures;
|
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 {
|
cur_items.push(MatcherPosHandle::Box(Box::new(MatcherPos {
|
||||||
stack: smallvec![],
|
stack: smallvec![],
|
||||||
sep: seq.separator.clone(),
|
sep: seq.separator.clone(),
|
||||||
seq_op: Some(seq.op),
|
seq_op: Some(seq.kleene.op),
|
||||||
idx: 0,
|
idx: 0,
|
||||||
matches,
|
matches,
|
||||||
match_lo: item.match_cur,
|
match_lo: item.match_cur,
|
||||||
|
|
|
@ -273,7 +273,7 @@ pub fn compile(
|
||||||
if body.legacy { token::Semi } else { token::Comma },
|
if body.legacy { token::Semi } else { token::Comma },
|
||||||
def.span,
|
def.span,
|
||||||
)),
|
)),
|
||||||
op: quoted::KleeneOp::OneOrMore,
|
kleene: quoted::KleeneToken::new(quoted::KleeneOp::OneOrMore, def.span),
|
||||||
num_captures: 2,
|
num_captures: 2,
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
@ -283,7 +283,7 @@ pub fn compile(
|
||||||
Lrc::new(quoted::SequenceRepetition {
|
Lrc::new(quoted::SequenceRepetition {
|
||||||
tts: vec![quoted::TokenTree::token(token::Semi, def.span)],
|
tts: vec![quoted::TokenTree::token(token::Semi, def.span)],
|
||||||
separator: None,
|
separator: None,
|
||||||
op: quoted::KleeneOp::ZeroOrMore,
|
kleene: quoted::KleeneToken::new(quoted::KleeneOp::ZeroOrMore, def.span),
|
||||||
num_captures: 0,
|
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 {
|
&& seq.tts.iter().all(|seq_tt| match *seq_tt {
|
||||||
TokenTree::MetaVarDecl(_, _, id) => id.name == sym::vis,
|
TokenTree::MetaVarDecl(_, _, id) => id.name == sym::vis,
|
||||||
TokenTree::Sequence(_, ref sub_seq) => {
|
TokenTree::Sequence(_, ref sub_seq) => {
|
||||||
sub_seq.op == quoted::KleeneOp::ZeroOrMore
|
sub_seq.kleene.op == quoted::KleeneOp::ZeroOrMore
|
||||||
|| sub_seq.op == quoted::KleeneOp::ZeroOrOne
|
|| sub_seq.kleene.op == quoted::KleeneOp::ZeroOrOne
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
})
|
})
|
||||||
|
@ -628,8 +628,8 @@ impl FirstSets {
|
||||||
|
|
||||||
// Reverse scan: Sequence comes before `first`.
|
// Reverse scan: Sequence comes before `first`.
|
||||||
if subfirst.maybe_empty
|
if subfirst.maybe_empty
|
||||||
|| seq_rep.op == quoted::KleeneOp::ZeroOrMore
|
|| seq_rep.kleene.op == quoted::KleeneOp::ZeroOrMore
|
||||||
|| seq_rep.op == quoted::KleeneOp::ZeroOrOne
|
|| seq_rep.kleene.op == quoted::KleeneOp::ZeroOrOne
|
||||||
{
|
{
|
||||||
// If sequence is potentially empty, then
|
// If sequence is potentially empty, then
|
||||||
// union them (preserving first emptiness).
|
// union them (preserving first emptiness).
|
||||||
|
@ -677,8 +677,8 @@ impl FirstSets {
|
||||||
assert!(first.maybe_empty);
|
assert!(first.maybe_empty);
|
||||||
first.add_all(subfirst);
|
first.add_all(subfirst);
|
||||||
if subfirst.maybe_empty
|
if subfirst.maybe_empty
|
||||||
|| seq_rep.op == quoted::KleeneOp::ZeroOrMore
|
|| seq_rep.kleene.op == quoted::KleeneOp::ZeroOrMore
|
||||||
|| seq_rep.op == quoted::KleeneOp::ZeroOrOne
|
|| seq_rep.kleene.op == quoted::KleeneOp::ZeroOrOne
|
||||||
{
|
{
|
||||||
// continue scanning for more first
|
// continue scanning for more first
|
||||||
// tokens, but also make sure we
|
// tokens, but also make sure we
|
||||||
|
|
|
@ -50,11 +50,23 @@ pub struct SequenceRepetition {
|
||||||
/// The optional separator
|
/// The optional separator
|
||||||
pub separator: Option<Token>,
|
pub separator: Option<Token>,
|
||||||
/// Whether the sequence can be repeated zero (*), or one or more times (+)
|
/// 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)
|
/// The number of `Match`s that appear in the sequence (and subsequences)
|
||||||
pub num_captures: usize,
|
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)
|
/// A Kleene-style [repetition operator](http://en.wikipedia.org/wiki/Kleene_star)
|
||||||
/// for token sequences.
|
/// for token sequences.
|
||||||
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
|
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
|
||||||
|
@ -273,7 +285,7 @@ fn parse_tree(
|
||||||
macro_node_id,
|
macro_node_id,
|
||||||
);
|
);
|
||||||
// Get the Kleene operator and optional separator
|
// 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)
|
// Count the number of captured "names" (i.e., named metavars)
|
||||||
let name_captures = macro_parser::count_names(&sequence);
|
let name_captures = macro_parser::count_names(&sequence);
|
||||||
TokenTree::Sequence(
|
TokenTree::Sequence(
|
||||||
|
@ -281,7 +293,7 @@ fn parse_tree(
|
||||||
Lrc::new(SequenceRepetition {
|
Lrc::new(SequenceRepetition {
|
||||||
tts: sequence,
|
tts: sequence,
|
||||||
separator,
|
separator,
|
||||||
op,
|
kleene,
|
||||||
num_captures: name_captures,
|
num_captures: name_captures,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
@ -379,16 +391,16 @@ fn parse_sep_and_kleene_op(
|
||||||
input: &mut Peekable<impl Iterator<Item = tokenstream::TokenTree>>,
|
input: &mut Peekable<impl Iterator<Item = tokenstream::TokenTree>>,
|
||||||
span: Span,
|
span: Span,
|
||||||
sess: &ParseSess,
|
sess: &ParseSess,
|
||||||
) -> (Option<Token>, KleeneOp) {
|
) -> (Option<Token>, KleeneToken) {
|
||||||
// We basically look at two token trees here, denoted as #1 and #2 below
|
// We basically look at two token trees here, denoted as #1 and #2 below
|
||||||
let span = match parse_kleene_op(input, span) {
|
let span = match parse_kleene_op(input, span) {
|
||||||
// #1 is a `?`, `+`, or `*` KleeneOp
|
// #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
|
// #1 is a separator followed by #2, a KleeneOp
|
||||||
Ok(Err(token)) => match parse_kleene_op(input, token.span) {
|
Ok(Err(token)) => match parse_kleene_op(input, token.span) {
|
||||||
// #2 is the `?` Kleene op, which does not take a separator (error)
|
// #2 is the `?` Kleene op, which does not take a separator (error)
|
||||||
Ok(Ok((KleeneOp::ZeroOrOne, _))) => {
|
Ok(Ok((KleeneOp::ZeroOrOne, span))) => {
|
||||||
// Error!
|
// Error!
|
||||||
sess.span_diagnostic.span_err(
|
sess.span_diagnostic.span_err(
|
||||||
token.span,
|
token.span,
|
||||||
|
@ -396,11 +408,11 @@ fn parse_sep_and_kleene_op(
|
||||||
);
|
);
|
||||||
|
|
||||||
// Return a dummy
|
// Return a dummy
|
||||||
return (None, KleeneOp::ZeroOrMore);
|
return (None, KleeneToken::new(KleeneOp::ZeroOrMore, span));
|
||||||
}
|
}
|
||||||
|
|
||||||
// #2 is a KleeneOp :D
|
// #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 :(
|
// #2 is a random token or not a token at all :(
|
||||||
Ok(Err(Token { span, .. })) | Err(span) => span,
|
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 `?`");
|
sess.span_diagnostic.span_err(span, "expected one of: `*`, `+`, or `?`");
|
||||||
|
|
||||||
// Return a dummy
|
// Return a dummy
|
||||||
(None, KleeneOp::ZeroOrMore)
|
(None, KleeneToken::new(KleeneOp::ZeroOrMore, span))
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,7 +183,7 @@ pub fn transcribe(
|
||||||
|
|
||||||
// Is the repetition empty?
|
// Is the repetition empty?
|
||||||
if len == 0 {
|
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
|
// FIXME: this really ought to be caught at macro definition
|
||||||
// time... It happens when the Kleene operator in the matcher and
|
// time... It happens when the Kleene operator in the matcher and
|
||||||
// the body for the same meta-variable do not match.
|
// the body for the same meta-variable do not match.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue