mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-12 08:36:03 +00:00
Merge pull request #2542 from topecongiro/macro-2.0
Handle macro arguments which exceeds max width
This commit is contained in:
commit
5516223900
560
src/macros.rs
560
src/macros.rs
@ -463,6 +463,435 @@ fn replace_names(input: &str) -> Option<(String, HashMap<String, String>)> {
|
||||
Some((result, substs))
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum MacroArgKind {
|
||||
/// e.g. `$x: expr`.
|
||||
MetaVariable(ast::Ident, String),
|
||||
/// e.g. `$($foo: expr),*`
|
||||
Repeat(
|
||||
/// `()`, `[]` or `{}`.
|
||||
DelimToken,
|
||||
/// Inner arguments inside delimiters.
|
||||
Vec<ParsedMacroArg>,
|
||||
/// Something after the closing delimiter and the repeat token, if available.
|
||||
Option<Box<ParsedMacroArg>>,
|
||||
/// The repeat token. This could be one of `*`, `+` or `?`.
|
||||
Token,
|
||||
),
|
||||
/// e.g. `[derive(Debug)]`
|
||||
Delimited(DelimToken, Vec<ParsedMacroArg>),
|
||||
/// A possible separator. e.g. `,` or `;`.
|
||||
Separator(String, String),
|
||||
/// Other random stuff that does not fit to other kinds.
|
||||
/// e.g. `== foo` in `($x: expr == foo)`.
|
||||
Other(String, String),
|
||||
}
|
||||
|
||||
fn delim_token_to_str(
|
||||
context: &RewriteContext,
|
||||
delim_token: &DelimToken,
|
||||
shape: Shape,
|
||||
use_multiple_lines: bool,
|
||||
) -> (String, String) {
|
||||
let (lhs, rhs) = match *delim_token {
|
||||
DelimToken::Paren => ("(", ")"),
|
||||
DelimToken::Bracket => ("[", "]"),
|
||||
DelimToken::Brace => ("{ ", " }"),
|
||||
DelimToken::NoDelim => ("", ""),
|
||||
};
|
||||
if use_multiple_lines {
|
||||
let indent_str = shape.indent.to_string_with_newline(context.config);
|
||||
let nested_indent_str = shape
|
||||
.indent
|
||||
.block_indent(context.config)
|
||||
.to_string_with_newline(context.config);
|
||||
(
|
||||
format!("{}{}", lhs, nested_indent_str),
|
||||
format!("{}{}", indent_str, rhs),
|
||||
)
|
||||
} else {
|
||||
(lhs.to_owned(), rhs.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
impl MacroArgKind {
|
||||
fn starts_with_brace(&self) -> bool {
|
||||
match *self {
|
||||
MacroArgKind::Repeat(DelimToken::Brace, _, _, _)
|
||||
| MacroArgKind::Delimited(DelimToken::Brace, _) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn starts_with_dollar(&self) -> bool {
|
||||
match *self {
|
||||
MacroArgKind::Repeat(..) | MacroArgKind::MetaVariable(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn ends_with_space(&self) -> bool {
|
||||
match *self {
|
||||
MacroArgKind::Separator(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn has_meta_var(&self) -> bool {
|
||||
match *self {
|
||||
MacroArgKind::MetaVariable(..) => true,
|
||||
MacroArgKind::Repeat(_, ref args, _, _) => args.iter().any(|a| a.kind.has_meta_var()),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn rewrite(
|
||||
&self,
|
||||
context: &RewriteContext,
|
||||
shape: Shape,
|
||||
use_multiple_lines: bool,
|
||||
) -> Option<String> {
|
||||
let rewrite_delimited_inner = |delim_tok, args| -> Option<(String, String, String)> {
|
||||
let (lhs, rhs) = delim_token_to_str(context, delim_tok, shape, false);
|
||||
let inner = wrap_macro_args(context, args, shape)?;
|
||||
if lhs.len() + inner.len() + rhs.len() <= shape.width {
|
||||
return Some((lhs, inner, rhs));
|
||||
}
|
||||
|
||||
let (lhs, rhs) = delim_token_to_str(context, delim_tok, shape, true);
|
||||
let nested_shape = shape
|
||||
.block_indent(context.config.tab_spaces())
|
||||
.with_max_width(context.config);
|
||||
let inner = wrap_macro_args(context, args, nested_shape)?;
|
||||
Some((lhs, inner, rhs))
|
||||
};
|
||||
|
||||
match *self {
|
||||
MacroArgKind::MetaVariable(ty, ref name) => {
|
||||
Some(format!("${}: {}", name, ty.name.as_str()))
|
||||
}
|
||||
MacroArgKind::Repeat(ref delim_tok, ref args, ref another, ref tok) => {
|
||||
let (lhs, inner, rhs) = rewrite_delimited_inner(delim_tok, args)?;
|
||||
let another = another
|
||||
.as_ref()
|
||||
.and_then(|a| a.rewrite(context, shape, use_multiple_lines))
|
||||
.unwrap_or("".to_owned());
|
||||
let repeat_tok = pprust::token_to_string(tok);
|
||||
|
||||
Some(format!("${}{}{}{}{}", lhs, inner, rhs, another, repeat_tok))
|
||||
}
|
||||
MacroArgKind::Delimited(ref delim_tok, ref args) => {
|
||||
rewrite_delimited_inner(delim_tok, args)
|
||||
.map(|(lhs, inner, rhs)| format!("{}{}{}", lhs, inner, rhs))
|
||||
}
|
||||
MacroArgKind::Separator(ref sep, ref prefix) => Some(format!("{}{} ", prefix, sep)),
|
||||
MacroArgKind::Other(ref inner, ref prefix) => Some(format!("{}{}", prefix, inner)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct ParsedMacroArg {
|
||||
kind: MacroArgKind,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
impl ParsedMacroArg {
|
||||
pub fn rewrite(
|
||||
&self,
|
||||
context: &RewriteContext,
|
||||
shape: Shape,
|
||||
use_multiple_lines: bool,
|
||||
) -> Option<String> {
|
||||
self.kind.rewrite(context, shape, use_multiple_lines)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses macro arguments on macro def.
|
||||
struct MacroArgParser {
|
||||
/// Holds either a name of the next metavariable, a separator or a junk.
|
||||
buf: String,
|
||||
/// The start position on the current buffer.
|
||||
lo: BytePos,
|
||||
/// The first token of the current buffer.
|
||||
start_tok: Token,
|
||||
/// Set to true if we are parsing a metavariable or a repeat.
|
||||
is_meta_var: bool,
|
||||
/// The position of the last token.
|
||||
hi: BytePos,
|
||||
/// The last token parsed.
|
||||
last_tok: Token,
|
||||
/// Holds the parsed arguments.
|
||||
result: Vec<ParsedMacroArg>,
|
||||
}
|
||||
|
||||
fn last_tok(tt: &TokenTree) -> Token {
|
||||
match *tt {
|
||||
TokenTree::Token(_, ref t) => t.clone(),
|
||||
TokenTree::Delimited(_, ref d) => d.close_token(),
|
||||
}
|
||||
}
|
||||
|
||||
impl MacroArgParser {
|
||||
pub fn new() -> MacroArgParser {
|
||||
MacroArgParser {
|
||||
lo: BytePos(0),
|
||||
hi: BytePos(0),
|
||||
buf: String::new(),
|
||||
is_meta_var: false,
|
||||
last_tok: Token::Eof,
|
||||
start_tok: Token::Eof,
|
||||
result: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
fn set_last_tok(&mut self, tok: &TokenTree) {
|
||||
self.hi = tok.span().hi();
|
||||
self.last_tok = last_tok(tok);
|
||||
}
|
||||
|
||||
fn add_separator(&mut self) {
|
||||
let prefix = if self.need_space_prefix() {
|
||||
" ".to_owned()
|
||||
} else {
|
||||
"".to_owned()
|
||||
};
|
||||
self.result.push(ParsedMacroArg {
|
||||
kind: MacroArgKind::Separator(self.buf.clone(), prefix),
|
||||
span: mk_sp(self.lo, self.hi),
|
||||
});
|
||||
self.buf.clear();
|
||||
}
|
||||
|
||||
fn add_other(&mut self) {
|
||||
let prefix = if self.need_space_prefix() {
|
||||
" ".to_owned()
|
||||
} else {
|
||||
"".to_owned()
|
||||
};
|
||||
self.result.push(ParsedMacroArg {
|
||||
kind: MacroArgKind::Other(self.buf.clone(), prefix),
|
||||
span: mk_sp(self.lo, self.hi),
|
||||
});
|
||||
self.buf.clear();
|
||||
}
|
||||
|
||||
fn add_meta_variable(&mut self, iter: &mut Cursor) {
|
||||
match iter.next() {
|
||||
Some(TokenTree::Token(sp, Token::Ident(ref ident))) => {
|
||||
self.result.push(ParsedMacroArg {
|
||||
kind: MacroArgKind::MetaVariable(ident.clone(), self.buf.clone()),
|
||||
span: mk_sp(self.lo, sp.hi()),
|
||||
});
|
||||
|
||||
self.buf.clear();
|
||||
self.is_meta_var = false;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_delimited(&mut self, inner: Vec<ParsedMacroArg>, delim: DelimToken, span: Span) {
|
||||
self.result.push(ParsedMacroArg {
|
||||
kind: MacroArgKind::Delimited(delim, inner),
|
||||
span,
|
||||
});
|
||||
}
|
||||
|
||||
// $($foo: expr),?
|
||||
fn add_repeat(
|
||||
&mut self,
|
||||
inner: Vec<ParsedMacroArg>,
|
||||
delim: DelimToken,
|
||||
iter: &mut Cursor,
|
||||
span: Span,
|
||||
) {
|
||||
let mut buffer = String::new();
|
||||
let mut first = false;
|
||||
let mut lo = span.lo();
|
||||
let mut hi = span.hi();
|
||||
|
||||
// Parse '*', '+' or '?.
|
||||
while let Some(ref tok) = iter.next() {
|
||||
self.set_last_tok(tok);
|
||||
if first {
|
||||
first = false;
|
||||
lo = tok.span().lo();
|
||||
}
|
||||
|
||||
match tok {
|
||||
TokenTree::Token(_, Token::BinOp(BinOpToken::Plus))
|
||||
| TokenTree::Token(_, Token::Question)
|
||||
| TokenTree::Token(_, Token::BinOp(BinOpToken::Star)) => {
|
||||
break;
|
||||
}
|
||||
TokenTree::Token(sp, ref t) => {
|
||||
buffer.push_str(&pprust::token_to_string(t));
|
||||
hi = sp.hi();
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
// There could be some random stuff between ')' and '*', '+' or '?'.
|
||||
let another = if buffer.trim().is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(Box::new(ParsedMacroArg {
|
||||
kind: MacroArgKind::Other(buffer, "".to_owned()),
|
||||
span: mk_sp(lo, hi),
|
||||
}))
|
||||
};
|
||||
|
||||
self.result.push(ParsedMacroArg {
|
||||
kind: MacroArgKind::Repeat(delim, inner, another, self.last_tok.clone()),
|
||||
span: mk_sp(self.lo, self.hi),
|
||||
});
|
||||
}
|
||||
|
||||
fn update_buffer(&mut self, lo: BytePos, t: &Token) {
|
||||
if self.buf.is_empty() {
|
||||
self.lo = lo;
|
||||
self.start_tok = t.clone();
|
||||
} else {
|
||||
let needs_space = match next_space(&self.last_tok) {
|
||||
SpaceState::Ident => ident_like(t),
|
||||
SpaceState::Punctuation => !ident_like(t),
|
||||
SpaceState::Always => true,
|
||||
SpaceState::Never => false,
|
||||
};
|
||||
if force_space_before(t) || needs_space {
|
||||
self.buf.push(' ');
|
||||
}
|
||||
}
|
||||
|
||||
self.buf.push_str(&pprust::token_to_string(t));
|
||||
}
|
||||
|
||||
fn need_space_prefix(&self) -> bool {
|
||||
if self.result.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let last_arg = self.result.last().unwrap();
|
||||
if let MacroArgKind::MetaVariable(..) = last_arg.kind {
|
||||
if ident_like(&self.start_tok) {
|
||||
return true;
|
||||
}
|
||||
if self.start_tok == Token::Colon {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if force_space_before(&self.start_tok) {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
/// Returns a collection of parsed macro def's arguments.
|
||||
pub fn parse(mut self, tokens: ThinTokenStream) -> Vec<ParsedMacroArg> {
|
||||
let mut iter = (tokens.into(): TokenStream).trees();
|
||||
|
||||
while let Some(ref tok) = iter.next() {
|
||||
match tok {
|
||||
TokenTree::Token(sp, Token::Dollar) => {
|
||||
// We always want to add a separator before meta variables.
|
||||
if !self.buf.is_empty() {
|
||||
self.add_separator();
|
||||
}
|
||||
|
||||
// Start keeping the name of this metavariable in the buffer.
|
||||
self.is_meta_var = true;
|
||||
self.lo = sp.lo();
|
||||
self.start_tok = Token::Dollar;
|
||||
}
|
||||
TokenTree::Token(_, Token::Colon) if self.is_meta_var => {
|
||||
self.add_meta_variable(&mut iter);
|
||||
}
|
||||
TokenTree::Token(sp, ref t) => self.update_buffer(sp.lo(), t),
|
||||
TokenTree::Delimited(sp, delimited) => {
|
||||
if !self.buf.is_empty() {
|
||||
if next_space(&self.last_tok) == SpaceState::Always {
|
||||
self.add_separator();
|
||||
} else {
|
||||
self.add_other();
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the stuff inside delimiters.
|
||||
let mut parser = MacroArgParser::new();
|
||||
parser.lo = sp.lo();
|
||||
let delimited_arg = parser.parse(delimited.tts.clone());
|
||||
|
||||
if self.is_meta_var {
|
||||
self.add_repeat(delimited_arg, delimited.delim, &mut iter, *sp);
|
||||
} else {
|
||||
self.add_delimited(delimited_arg, delimited.delim, *sp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.set_last_tok(tok);
|
||||
}
|
||||
|
||||
// We are left with some stuff in the buffer. Since there is nothing
|
||||
// left to separate, add this as `Other`.
|
||||
if !self.buf.is_empty() {
|
||||
self.add_other();
|
||||
}
|
||||
|
||||
self.result
|
||||
}
|
||||
}
|
||||
|
||||
fn wrap_macro_args(
|
||||
context: &RewriteContext,
|
||||
args: &[ParsedMacroArg],
|
||||
shape: Shape,
|
||||
) -> Option<String> {
|
||||
wrap_macro_args_inner(context, args, shape, false)
|
||||
.or_else(|| wrap_macro_args_inner(context, args, shape, true))
|
||||
}
|
||||
|
||||
fn wrap_macro_args_inner(
|
||||
context: &RewriteContext,
|
||||
args: &[ParsedMacroArg],
|
||||
shape: Shape,
|
||||
use_multiple_lines: bool,
|
||||
) -> Option<String> {
|
||||
let mut result = String::with_capacity(128);
|
||||
let mut iter = args.iter().peekable();
|
||||
let indent_str = shape.indent.to_string_with_newline(context.config);
|
||||
|
||||
while let Some(ref arg) = iter.next() {
|
||||
result.push_str(&arg.rewrite(context, shape, use_multiple_lines)?);
|
||||
|
||||
if use_multiple_lines
|
||||
&& (arg.kind.ends_with_space() || iter.peek().map_or(false, |a| a.kind.has_meta_var()))
|
||||
{
|
||||
if arg.kind.ends_with_space() {
|
||||
result.pop();
|
||||
}
|
||||
result.push_str(&indent_str);
|
||||
} else if let Some(ref next_arg) = iter.peek() {
|
||||
let space_before_dollar =
|
||||
!arg.kind.ends_with_space() && next_arg.kind.starts_with_dollar();
|
||||
let space_before_brace = next_arg.kind.starts_with_brace();
|
||||
if space_before_dollar || space_before_brace {
|
||||
result.push(' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !use_multiple_lines && result.len() >= shape.width {
|
||||
None
|
||||
} else {
|
||||
Some(result)
|
||||
}
|
||||
}
|
||||
|
||||
// This is a bit sketchy. The token rules probably need tweaking, but it works
|
||||
// for some common cases. I hope the basic logic is sufficient. Note that the
|
||||
// meaning of some tokens is a bit different here from usual Rust, e.g., `*`
|
||||
@ -470,66 +899,17 @@ fn replace_names(input: &str) -> Option<(String, HashMap<String, String>)> {
|
||||
//
|
||||
// We always try and format on one line.
|
||||
// FIXME: Use multi-line when every thing does not fit on one line.
|
||||
fn format_macro_args(toks: ThinTokenStream, shape: Shape) -> Option<String> {
|
||||
let mut result = String::with_capacity(128);
|
||||
let mut insert_space = SpaceState::Never;
|
||||
|
||||
for tok in (toks.into(): TokenStream).trees() {
|
||||
match tok {
|
||||
TokenTree::Token(_, t) => {
|
||||
if !result.is_empty() && force_space_before(&t) {
|
||||
insert_space = SpaceState::Always;
|
||||
}
|
||||
if force_no_space_before(&t) {
|
||||
insert_space = SpaceState::Never;
|
||||
}
|
||||
match (insert_space, ident_like(&t)) {
|
||||
(SpaceState::Always, _)
|
||||
| (SpaceState::Punctuation, false)
|
||||
| (SpaceState::Ident, true) => {
|
||||
result.push(' ');
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
result.push_str(&pprust::token_to_string(&t));
|
||||
insert_space = next_space(&t);
|
||||
}
|
||||
TokenTree::Delimited(_, d) => {
|
||||
if let SpaceState::Always = insert_space {
|
||||
result.push(' ');
|
||||
}
|
||||
let formatted = format_macro_args(d.tts, shape)?;
|
||||
match d.delim {
|
||||
DelimToken::Paren => {
|
||||
result.push_str(&format!("({})", formatted));
|
||||
insert_space = SpaceState::Always;
|
||||
}
|
||||
DelimToken::Bracket => {
|
||||
result.push_str(&format!("[{}]", formatted));
|
||||
insert_space = SpaceState::Always;
|
||||
}
|
||||
DelimToken::Brace => {
|
||||
result.push_str(&format!(" {{ {} }}", formatted));
|
||||
insert_space = SpaceState::Always;
|
||||
}
|
||||
DelimToken::NoDelim => {
|
||||
result.push_str(&format!("{}", formatted));
|
||||
insert_space = SpaceState::Always;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if result.len() <= shape.width {
|
||||
Some(result)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
fn format_macro_args(
|
||||
context: &RewriteContext,
|
||||
toks: ThinTokenStream,
|
||||
shape: Shape,
|
||||
) -> Option<String> {
|
||||
let parsed_args = MacroArgParser::new().parse(toks);
|
||||
wrap_macro_args(context, &parsed_args, shape)
|
||||
}
|
||||
|
||||
// We should insert a space if the next token is a:
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
enum SpaceState {
|
||||
Never,
|
||||
Punctuation,
|
||||
@ -538,6 +918,8 @@ enum SpaceState {
|
||||
}
|
||||
|
||||
fn force_space_before(tok: &Token) -> bool {
|
||||
debug!("tok: force_space_before {:?}", tok);
|
||||
|
||||
match *tok {
|
||||
Token::Eq
|
||||
| Token::Lt
|
||||
@ -555,20 +937,13 @@ fn force_space_before(tok: &Token) -> bool {
|
||||
| Token::RArrow
|
||||
| Token::LArrow
|
||||
| Token::FatArrow
|
||||
| Token::BinOp(_)
|
||||
| Token::Pound
|
||||
| Token::Dollar => true,
|
||||
Token::BinOp(bot) => bot != BinOpToken::Star,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn force_no_space_before(tok: &Token) -> bool {
|
||||
match *tok {
|
||||
Token::Semi | Token::Comma | Token::Dot => true,
|
||||
Token::BinOp(bot) => bot == BinOpToken::Star,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
fn ident_like(tok: &Token) -> bool {
|
||||
match *tok {
|
||||
Token::Ident(_) | Token::Literal(..) | Token::Lifetime(_) => true,
|
||||
@ -577,8 +952,11 @@ fn ident_like(tok: &Token) -> bool {
|
||||
}
|
||||
|
||||
fn next_space(tok: &Token) -> SpaceState {
|
||||
debug!("next_space: {:?}", tok);
|
||||
|
||||
match *tok {
|
||||
Token::Not
|
||||
| Token::BinOp(BinOpToken::And)
|
||||
| Token::Tilde
|
||||
| Token::At
|
||||
| Token::Comma
|
||||
@ -588,8 +966,7 @@ fn next_space(tok: &Token) -> SpaceState {
|
||||
| Token::DotDotEq
|
||||
| Token::DotEq
|
||||
| Token::Question
|
||||
| Token::Underscore
|
||||
| Token::BinOp(_) => SpaceState::Punctuation,
|
||||
| Token::Underscore => SpaceState::Punctuation,
|
||||
|
||||
Token::ModSep
|
||||
| Token::Pound
|
||||
@ -804,7 +1181,7 @@ impl MacroBranch {
|
||||
}
|
||||
|
||||
// 5 = " => {"
|
||||
let mut result = format_macro_args(self.args.clone(), shape.sub_width(5)?)?;
|
||||
let mut result = format_macro_args(context, self.args.clone(), shape.sub_width(5)?)?;
|
||||
|
||||
if multi_branch_style {
|
||||
result += " =>";
|
||||
@ -957,50 +1334,3 @@ fn format_lazy_static(context: &RewriteContext, shape: Shape, ts: &TokenStream)
|
||||
|
||||
Some(result)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use syntax;
|
||||
use syntax::parse::{parse_stream_from_source_str, ParseSess};
|
||||
use syntax::codemap::{FileName, FilePathMapping};
|
||||
|
||||
fn format_macro_args_str(s: &str) -> String {
|
||||
let mut result = String::new();
|
||||
syntax::with_globals(|| {
|
||||
let input = parse_stream_from_source_str(
|
||||
FileName::Custom("stdin".to_owned()),
|
||||
s.to_owned(),
|
||||
&ParseSess::new(FilePathMapping::empty()),
|
||||
None,
|
||||
);
|
||||
let shape = Shape {
|
||||
width: 100,
|
||||
indent: Indent::empty(),
|
||||
offset: 0,
|
||||
};
|
||||
result = format_macro_args(input.into(), shape).unwrap();
|
||||
});
|
||||
result
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_format_macro_args() {
|
||||
assert_eq!(format_macro_args_str(""), "".to_owned());
|
||||
assert_eq!(format_macro_args_str("$ x : ident"), "$x: ident".to_owned());
|
||||
assert_eq!(
|
||||
format_macro_args_str("$ m1 : ident , $ m2 : ident , $ x : ident"),
|
||||
"$m1: ident, $m2: ident, $x: ident".to_owned()
|
||||
);
|
||||
assert_eq!(
|
||||
format_macro_args_str("$($beginning:ident),*;$middle:ident;$($end:ident),*"),
|
||||
"$($beginning: ident),*; $middle: ident; $($end: ident),*".to_owned()
|
||||
);
|
||||
assert_eq!(
|
||||
format_macro_args_str(
|
||||
"$ name : ident ( $ ( $ dol : tt $ var : ident ) * ) $ ( $ body : tt ) *"
|
||||
),
|
||||
"$name: ident($($dol: tt $var: ident)*) $($body: tt)*".to_owned()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,44 @@
|
||||
// rustfmt-error_on_line_overflow: false
|
||||
|
||||
macro_rules! m {
|
||||
() => ();
|
||||
( $ x : ident ) => ();
|
||||
( $ m1 : ident , $ m2 : ident , $ x : ident ) => ();
|
||||
( $($beginning:ident),*;$middle:ident;$($end:ident),* ) => ();
|
||||
( $($beginning: ident),*; $middle: ident; $($end: ident),*; $($beginning: ident),*; $middle: ident; $($end: ident),* ) => {};
|
||||
( $ name : ident ( $ ( $ dol : tt $ var : ident ) * ) $ ( $ body : tt ) * ) => ();
|
||||
( $( $ i : ident : $ ty : ty , $def : expr , $stb : expr , $ ( $ dstring : tt ) , + ) ; + $ ( ; ) *
|
||||
$( $ i : ident : $ ty : ty , $def : expr , $stb : expr , $ ( $ dstring : tt ) , + ) ; + $ ( ; ) *
|
||||
) => {};
|
||||
( $foo: tt foo [$ attr : meta] $name: ident ) => {};
|
||||
( $foo: tt [$ attr: meta] $name: ident ) => {};
|
||||
( $foo: tt &'a [$attr : meta] $name: ident ) => {};
|
||||
( $foo: tt foo # [ $attr : meta] $name: ident ) => {};
|
||||
( $foo: tt # [ $attr : meta] $name: ident) => {};
|
||||
( $foo: tt &'a # [ $attr : meta] $name: ident ) => {};
|
||||
( $ x : tt foo bar foo bar foo bar $ y : tt => x*y*z $ z : tt , $ ( $a: tt ) , * ) => {};
|
||||
}
|
||||
|
||||
|
||||
macro_rules! impl_a_method {
|
||||
($n:ident ( $a:ident : $ta:ty ) -> $ret:ty { $body:expr }) => {
|
||||
fn $n($a:$ta) -> $ret { $body }
|
||||
macro_rules! $n { ($va:expr) => { $n($va) } }
|
||||
};
|
||||
($n:ident ( $a:ident : $ta:ty, $b:ident : $tb:ty ) -> $ret:ty { $body:expr }) => {
|
||||
fn $n($a:$ta, $b:$tb) -> $ret { $body }
|
||||
macro_rules! $n { ($va:expr, $vb:expr) => { $n($va, $vb) } }
|
||||
};
|
||||
($n:ident ( $a:ident : $ta:ty, $b:ident : $tb:ty, $c:ident : $tc:ty ) -> $ret:ty { $body:expr }) => {
|
||||
fn $n($a:$ta, $b:$tb, $c:$tc) -> $ret { $body }
|
||||
macro_rules! $n { ($va:expr, $vb:expr, $vc:expr) => { $n($va, $vb, $vc) } }
|
||||
};
|
||||
($n:ident ( $a:ident : $ta:ty, $b:ident : $tb:ty, $c:ident : $tc:ty, $d:ident : $td:ty ) -> $ret:ty { $body:expr }) => {
|
||||
fn $n($a:$ta, $b:$tb, $c:$tc, $d:$td) -> $ret { $body }
|
||||
macro_rules! $n { ($va:expr, $vb:expr, $vc:expr, $vd:expr) => { $n($va, $vb, $vc, $vd) } }
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! m {
|
||||
// a
|
||||
($expr :expr, $( $func : ident ) * ) => {
|
||||
@ -88,12 +127,7 @@ macro_rules! m {
|
||||
|
||||
// #2439
|
||||
macro_rules! m {
|
||||
(
|
||||
$line0_xxxxxxxxxxxxxxxxx: expr,
|
||||
$line1_xxxxxxxxxxxxxxxxx: expr,
|
||||
$line2_xxxxxxxxxxxxxxxxx: expr,
|
||||
$line3_xxxxxxxxxxxxxxxxx: expr,
|
||||
) => {};
|
||||
($line0_xxxxxxxxxxxxxxxxx: expr, $line1_xxxxxxxxxxxxxxxxx: expr, $line2_xxxxxxxxxxxxxxxxx: expr, $line3_xxxxxxxxxxxxxxxxx: expr,) => {};
|
||||
}
|
||||
|
||||
// #2466
|
||||
@ -113,6 +147,12 @@ macro foo($type_name: ident, $docs: expr) {
|
||||
pub struct $type_name;
|
||||
}
|
||||
|
||||
// #2534
|
||||
macro_rules! foo {
|
||||
($a:ident : $b:ty) => {};
|
||||
($a:ident $b:ident $c:ident) => {};
|
||||
}
|
||||
|
||||
// #2538
|
||||
macro_rules! add_message_to_notes {
|
||||
($msg:expr) => {{
|
||||
|
@ -1,5 +1,81 @@
|
||||
// rustfmt-error_on_line_overflow: false
|
||||
|
||||
macro_rules! m {
|
||||
() => {};
|
||||
($x: ident) => {};
|
||||
($m1: ident, $m2: ident, $x: ident) => {};
|
||||
($($beginning: ident),*; $middle: ident; $($end: ident),*) => {};
|
||||
(
|
||||
$($beginning: ident),*;
|
||||
$middle: ident;
|
||||
$($end: ident),*;
|
||||
$($beginning: ident),*;
|
||||
$middle: ident;
|
||||
$($end: ident),*
|
||||
) => {};
|
||||
($name: ident($($dol: tt $var: ident)*) $($body: tt)*) => {};
|
||||
(
|
||||
$($i: ident : $ty: ty, $def: expr, $stb: expr, $($dstring: tt),+);+ $(;)*
|
||||
$($i: ident : $ty: ty, $def: expr, $stb: expr, $($dstring: tt),+);+ $(;)*
|
||||
) => {};
|
||||
($foo: tt foo[$attr: meta] $name: ident) => {};
|
||||
($foo: tt[$attr: meta] $name: ident) => {};
|
||||
($foo: tt &'a[$attr: meta] $name: ident) => {};
|
||||
($foo: tt foo #[$attr: meta] $name: ident) => {};
|
||||
($foo: tt #[$attr: meta] $name: ident) => {};
|
||||
($foo: tt &'a #[$attr: meta] $name: ident) => {};
|
||||
($x: tt foo bar foo bar foo bar $y: tt => x * y * z $z: tt, $($a: tt),*) => {};
|
||||
}
|
||||
|
||||
macro_rules! impl_a_method {
|
||||
($n: ident($a: ident : $ta: ty) -> $ret: ty { $body: expr }) => {
|
||||
fn $n($a: $ta) -> $ret {
|
||||
$body
|
||||
}
|
||||
macro_rules! $n {
|
||||
($va: expr) => {
|
||||
$n($va)
|
||||
};
|
||||
}
|
||||
};
|
||||
($n: ident($a: ident : $ta: ty, $b: ident : $tb: ty) -> $ret: ty { $body: expr }) => {
|
||||
fn $n($a: $ta, $b: $tb) -> $ret {
|
||||
$body
|
||||
}
|
||||
macro_rules! $n {
|
||||
($va: expr,$vb: expr) => {
|
||||
$n($va, $vb)
|
||||
};
|
||||
}
|
||||
};
|
||||
(
|
||||
$n: ident($a: ident : $ta: ty, $b: ident : $tb: ty, $c: ident : $tc: ty) ->
|
||||
$ret: ty { $body: expr }
|
||||
) => {
|
||||
fn $n($a: $ta, $b: $tb, $c: $tc) -> $ret {
|
||||
$body
|
||||
}
|
||||
macro_rules! $n {
|
||||
($va: expr,$vb: expr,$vc: expr) => {
|
||||
$n($va, $vb, $vc)
|
||||
};
|
||||
}
|
||||
};
|
||||
(
|
||||
$n: ident($a: ident : $ta: ty, $b: ident : $tb: ty, $c: ident : $tc: ty, $d: ident : $td: ty) ->
|
||||
$ret: ty { $body: expr }
|
||||
) => {
|
||||
fn $n($a: $ta, $b: $tb, $c: $tc, $d: $td) -> $ret {
|
||||
$body
|
||||
}
|
||||
macro_rules! $n {
|
||||
($va: expr,$vb: expr,$vc: expr,$vd: expr) => {
|
||||
$n($va, $vb, $vc, $vd)
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! m {
|
||||
// a
|
||||
($expr: expr, $($func: ident)*) => {{
|
||||
@ -104,6 +180,12 @@ macro foo($type_name: ident, $docs: expr) {
|
||||
pub struct $type_name;
|
||||
}
|
||||
|
||||
// #2534
|
||||
macro_rules! foo {
|
||||
($a: ident : $b: ty) => {};
|
||||
($a: ident $b: ident $c: ident) => {};
|
||||
}
|
||||
|
||||
// #2538
|
||||
macro_rules! add_message_to_notes {
|
||||
($msg: expr) => {{
|
||||
|
Loading…
Reference in New Issue
Block a user