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
|
||||
// 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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue