+fn delim_token_to_str(
+ context: &RewriteContext,
+ delim_token: DelimToken,
+ shape: Shape,
+ use_multiple_lines: bool,
+ inner_is_empty: bool,
+) -> (String, String) {
+ let (lhs, rhs) = match delim_token {
+ DelimToken::Paren => ("(", ")"),
+ DelimToken::Bracket => ("[", "]"),
+ DelimToken::Brace => {
+ if inner_is_empty || use_multiple_lines {
+ ("{", "}")
+ } else {
+ ("{ ", " }")
+ }
+ }
+ 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 inner = wrap_macro_args(context, args, shape)?;
+ let (lhs, rhs) = delim_token_to_str(context, delim_tok, shape, false, inner.is_empty());
+ 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, false);
+ 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(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_else(|| "".to_owned());
+ let repeat_tok = pprust::token_to_string(tok);
+
+ Some(format!("${}{}{}{}{}", lhs, inner, rhs, another, repeat_tok))
+ }
+ MacroArgKind::Delimited(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) -> Option<()> {
+ match iter.next() {
+ Some(TokenTree::Token(sp, Token::Ident(ref ident, _))) => {
+ self.result.push(ParsedMacroArg {
+ kind: MacroArgKind::MetaVariable(*ident, self.buf.clone()),
+ span: mk_sp(self.lo, sp.hi()),
+ });
+
+ self.buf.clear();
+ self.is_meta_var = false;
+ Some(())
+ }
+ _ => None,
+ }
+ }
+
+ 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,
+ ) -> Option<()> {
+ let mut buffer = String::new();
+ let mut first = false;
+ let mut lo = span.lo();
+ let mut hi = span.hi();
+
+ // Parse '*', '+' or '?.
+ for tok in iter {
+ 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;