/// Given a `TokenStream` with a `Stream` of only two arguments, return a new `TokenStream`
/// separating the two arguments with a comma for diagnostic suggestions.
pub(crate) fn add_comma(&self) -> Option<(TokenStream, Span)> {
- // Used to suggest if a user writes `println!("{}" a);`
+ // Used to suggest if a user writes `foo!(a b);`
if let TokenStreamKind::Stream(ref slice) = self.kind {
- if slice.len() == 2 {
- let comma_span = match slice[0] {
- TokenStream { kind: TokenStreamKind::Tree(TokenTree::Token(sp, _)) } |
- TokenStream { kind: TokenStreamKind::Tree(TokenTree::Delimited(sp, _)) } => {
- sp.shrink_to_hi()
+ let mut suggestion = None;
+ let mut iter = slice.iter().enumerate().peekable();
+ while let Some((pos, ts)) = iter.next() {
+ if let Some((_, next)) = iter.peek() {
+ match (ts, next) {
+ (TokenStream {
+ kind: TokenStreamKind::Tree(TokenTree::Token(_, token::Token::Comma))
+ }, _) |
+ (_, TokenStream {
+ kind: TokenStreamKind::Tree(TokenTree::Token(_, token::Token::Comma))
+ }) => {}
+ (TokenStream {
+ kind: TokenStreamKind::Tree(TokenTree::Token(sp, _))
+ }, _) |
+ (TokenStream {
+ kind: TokenStreamKind::Tree(TokenTree::Delimited(sp, _))
+ }, _) => {
+ let sp = sp.shrink_to_hi();
+ let comma = TokenStream {
+ kind: TokenStreamKind::Tree(TokenTree::Token(sp, token::Comma)),
+ };
+ suggestion = Some((pos, comma, sp));
+ }
+ _ => {}
}
- _ => DUMMY_SP,
- };
- let comma = TokenStream {
- kind: TokenStreamKind::Tree(TokenTree::Token(comma_span, token::Comma)),
- };
- let slice = RcSlice::new(vec![slice[0].clone(), comma, slice[1].clone()]);
- return Some((TokenStream { kind: TokenStreamKind::Stream(slice) }, comma_span));
+ }
+ }
+ if let Some((pos, comma, sp)) = suggestion {
+ let mut new_slice = vec![];
+ let parts = slice.split_at(pos + 1);
+ new_slice.extend_from_slice(parts.0);
+ new_slice.push(comma);
+ new_slice.extend_from_slice(parts.1);
+ let slice = RcSlice::new(new_slice);
+ return Some((TokenStream { kind: TokenStreamKind::Stream(slice) }, sp));
}
}
None
// except according to those terms.
macro_rules! foo {
- ($a:ident, $b:ident) => ()
+ ($a:ident) => ();
+ ($a:ident, $b:ident) => ();
+ ($a:ident, $b:ident, $c:ident) => ();
+ ($a:ident, $b:ident, $c:ident, $d:ident) => ();
+ ($a:ident, $b:ident, $c:ident, $d:ident, $e:ident) => ();
}
fn main() {
//~^ ERROR expected token: `,`
foo!(a b);
//~^ ERROR no rules expected the token `b`
+ foo!(a, b, c, d e);
+ //~^ ERROR no rules expected the token `e`
+ foo!(a, b, c d, e);
+ //~^ ERROR no rules expected the token `d`
+ foo!(a, b, c d e);
+ //~^ ERROR no rules expected the token `d`
}
error: expected token: `,`
- --> $DIR/missing-comma.rs:16:19
+ --> $DIR/missing-comma.rs:20:19
|
LL | println!("{}" a);
| ^
error: no rules expected the token `b`
- --> $DIR/missing-comma.rs:18:12
+ --> $DIR/missing-comma.rs:22:12
|
LL | foo!(a b);
| -^
| |
| help: missing comma here
-error: aborting due to 2 previous errors
+error: no rules expected the token `e`
+ --> $DIR/missing-comma.rs:24:21
+ |
+LL | foo!(a, b, c, d e);
+ | -^
+ | |
+ | help: missing comma here
+
+error: no rules expected the token `d`
+ --> $DIR/missing-comma.rs:26:18
+ |
+LL | foo!(a, b, c d, e);
+ | -^
+ | |
+ | help: missing comma here
+
+error: no rules expected the token `d`
+ --> $DIR/missing-comma.rs:28:18
+ |
+LL | foo!(a, b, c d e);
+ | ^
+
+error: aborting due to 5 previous errors