1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 // Format list-like macro invocations. These are invocations whose token trees
12 // can be interpreted as expressions and separated by commas.
13 // Note that these token trees do not actually have to be interpreted as
14 // expressions by the compiler. An example of an invocation we would reformat is
15 // foo!( x, y, z ). The token x may represent an identifier in the code, but we
16 // interpreted as an expression.
17 // Macro uses which are not-list like, such as bar!(key => val), will not be
19 // List-like invocations with parentheses will be formatted as function calls,
20 // and those with brackets will be formatted as array literals.
22 use std::collections::HashMap;
25 use syntax::parse::new_parser_from_tts;
26 use syntax::parse::parser::Parser;
27 use syntax::parse::token::{BinOpToken, DelimToken, Token};
28 use syntax::print::pprust;
29 use syntax::source_map::{BytePos, Span};
31 use syntax::tokenstream::{Cursor, ThinTokenStream, TokenStream, TokenTree};
33 use syntax::{ast, ptr};
36 contains_comment, remove_trailing_white_spaces, CharClasses, FindUncommented, FullCodeCharKind,
39 use expr::rewrite_array;
40 use lists::{itemize_list, write_list, ListFormatting};
42 use rewrite::{Rewrite, RewriteContext};
43 use shape::{Indent, Shape};
44 use source_map::SpanUtils;
46 use utils::{format_visibility, mk_sp, rewrite_ident, wrap_str};
47 use visitor::FmtVisitor;
49 const FORCED_BRACKET_MACROS: &[&str] = &["vec!"];
51 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
52 pub enum MacroPosition {
61 Expr(ptr::P<ast::Expr>),
63 Pat(ptr::P<ast::Pat>),
64 Item(ptr::P<ast::Item>),
67 impl Rewrite for ast::Item {
68 fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
69 let mut visitor = ::visitor::FmtVisitor::from_context(context);
70 visitor.block_indent = shape.indent;
71 visitor.last_pos = self.span().lo();
72 visitor.visit_item(self);
73 Some(visitor.buffer.to_owned())
77 impl Rewrite for MacroArg {
78 fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
80 MacroArg::Expr(ref expr) => expr.rewrite(context, shape),
81 MacroArg::Ty(ref ty) => ty.rewrite(context, shape),
82 MacroArg::Pat(ref pat) => pat.rewrite(context, shape),
83 MacroArg::Item(ref item) => item.rewrite(context, shape),
88 fn parse_macro_arg(parser: &mut Parser) -> Option<MacroArg> {
89 macro_rules! parse_macro_arg {
90 ($macro_arg:ident, $parser:ident, $f:expr) => {
91 let mut cloned_parser = (*parser).clone();
92 match cloned_parser.$parser() {
94 if parser.sess.span_diagnostic.has_errors() {
95 parser.sess.span_diagnostic.reset_err_count();
98 *parser = cloned_parser;
99 return Some(MacroArg::$macro_arg($f(x)?));
104 parser.sess.span_diagnostic.reset_err_count();
110 parse_macro_arg!(Expr, parse_expr, |x: ptr::P<ast::Expr>| Some(x));
111 parse_macro_arg!(Ty, parse_ty, |x: ptr::P<ast::Ty>| Some(x));
112 parse_macro_arg!(Pat, parse_pat, |x: ptr::P<ast::Pat>| Some(x));
113 // `parse_item` returns `Option<ptr::P<ast::Item>>`.
114 parse_macro_arg!(Item, parse_item, |x: Option<ptr::P<ast::Item>>| x);
119 /// Rewrite macro name without using pretty-printer if possible.
120 fn rewrite_macro_name(
121 context: &RewriteContext,
123 extra_ident: Option<ast::Ident>,
125 let name = if path.segments.len() == 1 {
126 // Avoid using pretty-printer in the common case.
127 format!("{}!", rewrite_ident(context, path.segments[0].ident))
132 Some(ident) if ident != symbol::keywords::Invalid.ident() => format!("{} {}", name, ident),
137 // Use this on failing to format the macro call.
138 fn return_original_snippet_with_failure_marked(
139 context: &RewriteContext,
141 ) -> Option<String> {
142 context.macro_rewrite_failure.replace(true);
143 Some(context.snippet(span).to_owned())
146 struct InsideMacroGuard<'a> {
147 context: &'a RewriteContext<'a>,
151 impl<'a> InsideMacroGuard<'a> {
152 fn inside_macro_context(context: &'a RewriteContext) -> InsideMacroGuard<'a> {
153 let is_nested = context.inside_macro.replace(true);
154 InsideMacroGuard { context, is_nested }
158 impl<'a> Drop for InsideMacroGuard<'a> {
160 self.context.inside_macro.replace(self.is_nested);
164 pub fn rewrite_macro(
166 extra_ident: Option<ast::Ident>,
167 context: &RewriteContext,
169 position: MacroPosition,
170 ) -> Option<String> {
171 let guard = InsideMacroGuard::inside_macro_context(context);
172 let result = rewrite_macro_inner(mac, extra_ident, context, shape, position, guard.is_nested);
173 if result.is_none() {
174 context.macro_rewrite_failure.replace(true);
179 pub fn rewrite_macro_inner(
181 extra_ident: Option<ast::Ident>,
182 context: &RewriteContext,
184 position: MacroPosition,
185 is_nested_macro: bool,
186 ) -> Option<String> {
187 if context.config.use_try_shorthand() {
188 if let Some(expr) = convert_try_mac(mac, context) {
189 context.inside_macro.replace(false);
190 return expr.rewrite(context, shape);
194 let original_style = macro_style(mac, context);
196 let macro_name = rewrite_macro_name(context, &mac.node.path, extra_ident);
198 let style = if FORCED_BRACKET_MACROS.contains(&¯o_name[..]) && !is_nested_macro {
204 let ts: TokenStream = mac.node.stream();
205 let has_comment = contains_comment(context.snippet(mac.span));
206 if ts.is_empty() && !has_comment {
208 DelimToken::Paren if position == MacroPosition::Item => {
209 Some(format!("{}();", macro_name))
211 DelimToken::Paren => Some(format!("{}()", macro_name)),
212 DelimToken::Bracket => Some(format!("{}[]", macro_name)),
213 DelimToken::Brace => Some(format!("{}{{}}", macro_name)),
217 // Format well-known macros which cannot be parsed as a valid AST.
218 if macro_name == "lazy_static!" && !has_comment {
219 if let success @ Some(..) = format_lazy_static(context, shape, &ts) {
224 let mut parser = new_parser_from_tts(context.parse_session, ts.trees().collect());
225 let mut arg_vec = Vec::new();
226 let mut vec_with_semi = false;
227 let mut trailing_comma = false;
229 if DelimToken::Brace != style {
231 match parse_macro_arg(&mut parser) {
232 Some(arg) => arg_vec.push(arg),
233 None => return return_original_snippet_with_failure_marked(context, mac.span),
240 // Try to parse `vec![expr; expr]`
241 if FORCED_BRACKET_MACROS.contains(&¯o_name[..]) {
243 if parser.token != Token::Eof {
244 match parse_macro_arg(&mut parser) {
248 if parser.token == Token::Eof && arg_vec.len() == 2 {
249 vec_with_semi = true;
254 return return_original_snippet_with_failure_marked(
261 return return_original_snippet_with_failure_marked(context, mac.span);
263 _ => return return_original_snippet_with_failure_marked(context, mac.span),
268 if parser.token == Token::Eof {
269 trailing_comma = true;
275 if !arg_vec.is_empty() && arg_vec.iter().all(|arg| {
276 if let MacroArg::Item(..) = arg {
282 return rewrite_macro_with_items(
294 DelimToken::Paren => {
295 // Format macro invocation as function call, preserve the trailing
296 // comma because not all macros support them.
297 overflow::rewrite_with_parens(
303 context.config.width_heuristics().fn_call_width,
305 Some(SeparatorTactic::Always)
307 Some(SeparatorTactic::Never)
310 .map(|rw| match position {
311 MacroPosition::Item => format!("{};", rw),
315 DelimToken::Bracket => {
316 // Handle special case: `vec![expr; expr]`
318 let mac_shape = shape.offset_left(macro_name.len())?;
319 // 8 = `vec![]` + `; `
320 let total_overhead = 8;
321 let nested_shape = mac_shape.block_indent(context.config.tab_spaces());
322 let lhs = arg_vec[0].rewrite(context, nested_shape)?;
323 let rhs = arg_vec[1].rewrite(context, nested_shape)?;
324 if !lhs.contains('\n')
325 && !rhs.contains('\n')
326 && lhs.len() + rhs.len() + total_overhead <= shape.width
328 Some(format!("{}[{}; {}]", macro_name, lhs, rhs))
333 nested_shape.indent.to_string_with_newline(context.config),
335 nested_shape.indent.to_string_with_newline(context.config),
337 shape.indent.to_string_with_newline(context.config),
341 // If we are rewriting `vec!` macro or other special macros,
342 // then we can rewrite this as an usual array literal.
343 // Otherwise, we must preserve the original existence of trailing comma.
344 let macro_name = ¯o_name.as_str();
345 let mut force_trailing_comma = if trailing_comma {
346 Some(SeparatorTactic::Always)
348 Some(SeparatorTactic::Never)
350 if FORCED_BRACKET_MACROS.contains(macro_name) && !is_nested_macro {
351 context.inside_macro.replace(false);
352 if context.use_block_indent() {
353 force_trailing_comma = Some(SeparatorTactic::Vertical);
356 let rewrite = rewrite_array(
362 force_trailing_comma,
363 Some(original_style),
365 let comma = match position {
366 MacroPosition::Item => ";",
370 Some(format!("{}{}", rewrite, comma))
373 DelimToken::Brace => {
374 // Skip macro invocations with braces, for now.
375 indent_macro_snippet(context, context.snippet(mac.span), shape.indent)
381 pub fn rewrite_macro_def(
382 context: &RewriteContext,
387 vis: &ast::Visibility,
389 ) -> Option<String> {
390 let snippet = Some(remove_trailing_white_spaces(context.snippet(span)));
391 if snippet.as_ref().map_or(true, |s| s.ends_with(';')) {
395 let mut parser = MacroParser::new(def.stream().into_trees());
396 let parsed_def = match parser.parse() {
398 None => return snippet,
401 let mut result = if def.legacy {
402 String::from("macro_rules!")
404 format!("{}macro", format_visibility(context, vis))
408 result += rewrite_ident(context, ident);
410 let multi_branch_style = def.legacy || parsed_def.branches.len() != 1;
412 let arm_shape = if multi_branch_style {
414 .block_indent(context.config.tab_spaces())
415 .with_max_width(context.config)
420 let branch_items = itemize_list(
421 context.snippet_provider,
422 parsed_def.branches.iter(),
425 |branch| branch.span.lo(),
426 |branch| branch.span.hi(),
427 |branch| match branch.rewrite(context, arm_shape, multi_branch_style) {
429 // if the rewrite returned None because a macro could not be rewritten, then return the
431 None if *context.macro_rewrite_failure.borrow() == true => {
432 Some(context.snippet(branch.body).trim().to_string())
436 context.snippet_provider.span_after(span, "{"),
440 .collect::<Vec<_>>();
442 let fmt = ListFormatting::new(arm_shape, context.config)
443 .separator(if def.legacy { ";" } else { "" })
444 .trailing_separator(SeparatorTactic::Always)
445 .preserve_newline(true);
447 if multi_branch_style {
449 result += &arm_shape.indent.to_string_with_newline(context.config);
452 match write_list(&branch_items, &fmt) {
453 Some(ref s) => result += s,
454 None => return snippet,
457 if multi_branch_style {
458 result += &indent.to_string_with_newline(context.config);
465 fn register_metavariable(
466 map: &mut HashMap<String, String>,
471 let mut new_name = String::new();
472 let mut old_name = String::new();
475 for _ in 0..(dollar_count - 1) {
480 new_name.push_str(&name);
481 old_name.push_str(&name);
483 result.push_str(&new_name);
484 map.insert(old_name, new_name);
487 // Replaces `$foo` with `zfoo`. We must check for name overlap to ensure we
488 // aren't causing problems.
489 // This should also work for escaped `$` variables, where we leave earlier `$`s.
490 fn replace_names(input: &str) -> Option<(String, HashMap<String, String>)> {
491 // Each substitution will require five or six extra bytes.
492 let mut result = String::with_capacity(input.len() + 64);
493 let mut substs = HashMap::new();
494 let mut dollar_count = 0;
495 let mut cur_name = String::new();
497 for (kind, c) in CharClasses::new(input.chars()) {
498 if kind != FullCodeCharKind::Normal {
502 } else if dollar_count == 0 {
504 } else if !c.is_alphanumeric() && !cur_name.is_empty() {
505 // Terminates a name following one or more dollars.
506 register_metavariable(&mut substs, &mut result, &cur_name, dollar_count);
511 } else if c == '(' && cur_name.is_empty() {
512 // FIXME: Support macro def with repeat.
514 } else if c.is_alphanumeric() || c == '_' {
519 if !cur_name.is_empty() {
520 register_metavariable(&mut substs, &mut result, &cur_name, dollar_count);
523 debug!("replace_names `{}` {:?}", result, substs);
525 Some((result, substs))
528 #[derive(Debug, Clone)]
531 MetaVariable(ast::Ident, String),
532 /// e.g. `$($foo: expr),*`
534 /// `()`, `[]` or `{}`.
536 /// Inner arguments inside delimiters.
538 /// Something after the closing delimiter and the repeat token, if available.
539 Option<Box<ParsedMacroArg>>,
540 /// The repeat token. This could be one of `*`, `+` or `?`.
543 /// e.g. `[derive(Debug)]`
544 Delimited(DelimToken, Vec<ParsedMacroArg>),
545 /// A possible separator. e.g. `,` or `;`.
546 Separator(String, String),
547 /// Other random stuff that does not fit to other kinds.
548 /// e.g. `== foo` in `($x: expr == foo)`.
549 Other(String, String),
552 fn delim_token_to_str(
553 context: &RewriteContext,
554 delim_token: DelimToken,
556 use_multiple_lines: bool,
557 inner_is_empty: bool,
558 ) -> (String, String) {
559 let (lhs, rhs) = match delim_token {
560 DelimToken::Paren => ("(", ")"),
561 DelimToken::Bracket => ("[", "]"),
562 DelimToken::Brace => {
563 if inner_is_empty || use_multiple_lines {
569 DelimToken::NoDelim => ("", ""),
571 if use_multiple_lines {
572 let indent_str = shape.indent.to_string_with_newline(context.config);
573 let nested_indent_str = shape
575 .block_indent(context.config)
576 .to_string_with_newline(context.config);
578 format!("{}{}", lhs, nested_indent_str),
579 format!("{}{}", indent_str, rhs),
582 (lhs.to_owned(), rhs.to_owned())
587 fn starts_with_brace(&self) -> bool {
589 MacroArgKind::Repeat(DelimToken::Brace, _, _, _)
590 | MacroArgKind::Delimited(DelimToken::Brace, _) => true,
595 fn starts_with_dollar(&self) -> bool {
597 MacroArgKind::Repeat(..) | MacroArgKind::MetaVariable(..) => true,
602 fn ends_with_space(&self) -> bool {
604 MacroArgKind::Separator(..) => true,
609 fn has_meta_var(&self) -> bool {
611 MacroArgKind::MetaVariable(..) => true,
612 MacroArgKind::Repeat(_, ref args, _, _) => args.iter().any(|a| a.kind.has_meta_var()),
619 context: &RewriteContext,
621 use_multiple_lines: bool,
622 ) -> Option<String> {
623 let rewrite_delimited_inner = |delim_tok, args| -> Option<(String, String, String)> {
624 let inner = wrap_macro_args(context, args, shape)?;
625 let (lhs, rhs) = delim_token_to_str(context, delim_tok, shape, false, inner.is_empty());
626 if lhs.len() + inner.len() + rhs.len() <= shape.width {
627 return Some((lhs, inner, rhs));
630 let (lhs, rhs) = delim_token_to_str(context, delim_tok, shape, true, false);
631 let nested_shape = shape
632 .block_indent(context.config.tab_spaces())
633 .with_max_width(context.config);
634 let inner = wrap_macro_args(context, args, nested_shape)?;
635 Some((lhs, inner, rhs))
639 MacroArgKind::MetaVariable(ty, ref name) => {
640 Some(format!("${}:{}", name, ty.name.as_str()))
642 MacroArgKind::Repeat(delim_tok, ref args, ref another, ref tok) => {
643 let (lhs, inner, rhs) = rewrite_delimited_inner(delim_tok, args)?;
644 let another = another
646 .and_then(|a| a.rewrite(context, shape, use_multiple_lines))
647 .unwrap_or_else(|| "".to_owned());
648 let repeat_tok = pprust::token_to_string(tok);
650 Some(format!("${}{}{}{}{}", lhs, inner, rhs, another, repeat_tok))
652 MacroArgKind::Delimited(delim_tok, ref args) => {
653 rewrite_delimited_inner(delim_tok, args)
654 .map(|(lhs, inner, rhs)| format!("{}{}{}", lhs, inner, rhs))
656 MacroArgKind::Separator(ref sep, ref prefix) => Some(format!("{}{} ", prefix, sep)),
657 MacroArgKind::Other(ref inner, ref prefix) => Some(format!("{}{}", prefix, inner)),
662 #[derive(Debug, Clone)]
663 struct ParsedMacroArg {
668 impl ParsedMacroArg {
671 context: &RewriteContext,
673 use_multiple_lines: bool,
674 ) -> Option<String> {
675 self.kind.rewrite(context, shape, use_multiple_lines)
679 /// Parses macro arguments on macro def.
680 struct MacroArgParser {
681 /// Holds either a name of the next metavariable, a separator or a junk.
683 /// The start position on the current buffer.
685 /// The first token of the current buffer.
687 /// Set to true if we are parsing a metavariable or a repeat.
689 /// The position of the last token.
691 /// The last token parsed.
693 /// Holds the parsed arguments.
694 result: Vec<ParsedMacroArg>,
697 fn last_tok(tt: &TokenTree) -> Token {
699 TokenTree::Token(_, ref t) => t.clone(),
700 TokenTree::Delimited(_, ref d) => d.close_token(),
704 impl MacroArgParser {
705 pub fn new() -> MacroArgParser {
711 last_tok: Token::Eof,
712 start_tok: Token::Eof,
717 fn set_last_tok(&mut self, tok: &TokenTree) {
718 self.hi = tok.span().hi();
719 self.last_tok = last_tok(tok);
722 fn add_separator(&mut self) {
723 let prefix = if self.need_space_prefix() {
728 self.result.push(ParsedMacroArg {
729 kind: MacroArgKind::Separator(self.buf.clone(), prefix),
730 span: mk_sp(self.lo, self.hi),
735 fn add_other(&mut self) {
736 let prefix = if self.need_space_prefix() {
741 self.result.push(ParsedMacroArg {
742 kind: MacroArgKind::Other(self.buf.clone(), prefix),
743 span: mk_sp(self.lo, self.hi),
748 fn add_meta_variable(&mut self, iter: &mut Cursor) -> Option<()> {
750 Some(TokenTree::Token(sp, Token::Ident(ref ident, _))) => {
751 self.result.push(ParsedMacroArg {
752 kind: MacroArgKind::MetaVariable(*ident, self.buf.clone()),
753 span: mk_sp(self.lo, sp.hi()),
757 self.is_meta_var = false;
764 fn add_delimited(&mut self, inner: Vec<ParsedMacroArg>, delim: DelimToken, span: Span) {
765 self.result.push(ParsedMacroArg {
766 kind: MacroArgKind::Delimited(delim, inner),
774 inner: Vec<ParsedMacroArg>,
779 let mut buffer = String::new();
780 let mut first = false;
781 let mut lo = span.lo();
782 let mut hi = span.hi();
784 // Parse '*', '+' or '?.
786 self.set_last_tok(&tok);
789 lo = tok.span().lo();
793 TokenTree::Token(_, Token::BinOp(BinOpToken::Plus))
794 | TokenTree::Token(_, Token::Question)
795 | TokenTree::Token(_, Token::BinOp(BinOpToken::Star)) => {
798 TokenTree::Token(sp, ref t) => {
799 buffer.push_str(&pprust::token_to_string(t));
806 // There could be some random stuff between ')' and '*', '+' or '?'.
807 let another = if buffer.trim().is_empty() {
810 Some(Box::new(ParsedMacroArg {
811 kind: MacroArgKind::Other(buffer, "".to_owned()),
816 self.result.push(ParsedMacroArg {
817 kind: MacroArgKind::Repeat(delim, inner, another, self.last_tok.clone()),
818 span: mk_sp(self.lo, self.hi),
823 fn update_buffer(&mut self, lo: BytePos, t: &Token) {
824 if self.buf.is_empty() {
826 self.start_tok = t.clone();
828 let needs_space = match next_space(&self.last_tok) {
829 SpaceState::Ident => ident_like(t),
830 SpaceState::Punctuation => !ident_like(t),
831 SpaceState::Always => true,
832 SpaceState::Never => false,
834 if force_space_before(t) || needs_space {
839 self.buf.push_str(&pprust::token_to_string(t));
842 fn need_space_prefix(&self) -> bool {
843 if self.result.is_empty() {
847 let last_arg = self.result.last().unwrap();
848 if let MacroArgKind::MetaVariable(..) = last_arg.kind {
849 if ident_like(&self.start_tok) {
852 if self.start_tok == Token::Colon {
857 if force_space_before(&self.start_tok) {
864 /// Returns a collection of parsed macro def's arguments.
865 pub fn parse(mut self, tokens: ThinTokenStream) -> Option<Vec<ParsedMacroArg>> {
866 let mut iter = (tokens.into(): TokenStream).trees();
868 while let Some(ref tok) = iter.next() {
870 TokenTree::Token(sp, Token::Dollar) => {
871 // We always want to add a separator before meta variables.
872 if !self.buf.is_empty() {
873 self.add_separator();
876 // Start keeping the name of this metavariable in the buffer.
877 self.is_meta_var = true;
879 self.start_tok = Token::Dollar;
881 TokenTree::Token(_, Token::Colon) if self.is_meta_var => {
882 self.add_meta_variable(&mut iter)?;
884 TokenTree::Token(sp, ref t) => self.update_buffer(sp.lo(), t),
885 TokenTree::Delimited(delimited_span, delimited) => {
886 if !self.buf.is_empty() {
887 if next_space(&self.last_tok) == SpaceState::Always {
888 self.add_separator();
894 // Parse the stuff inside delimiters.
895 let mut parser = MacroArgParser::new();
896 parser.lo = delimited_span.open.lo();
897 let delimited_arg = parser.parse(delimited.tts.clone())?;
899 let span = delimited_span.entire();
900 if self.is_meta_var {
901 self.add_repeat(delimited_arg, delimited.delim, &mut iter, span)?;
902 self.is_meta_var = false;
904 self.add_delimited(delimited_arg, delimited.delim, span);
909 self.set_last_tok(tok);
912 // We are left with some stuff in the buffer. Since there is nothing
913 // left to separate, add this as `Other`.
914 if !self.buf.is_empty() {
923 context: &RewriteContext,
924 args: &[ParsedMacroArg],
926 ) -> Option<String> {
927 wrap_macro_args_inner(context, args, shape, false)
928 .or_else(|| wrap_macro_args_inner(context, args, shape, true))
931 fn wrap_macro_args_inner(
932 context: &RewriteContext,
933 args: &[ParsedMacroArg],
935 use_multiple_lines: bool,
936 ) -> Option<String> {
937 let mut result = String::with_capacity(128);
938 let mut iter = args.iter().peekable();
939 let indent_str = shape.indent.to_string_with_newline(context.config);
941 while let Some(ref arg) = iter.next() {
942 result.push_str(&arg.rewrite(context, shape, use_multiple_lines)?);
944 if use_multiple_lines
945 && (arg.kind.ends_with_space() || iter.peek().map_or(false, |a| a.kind.has_meta_var()))
947 if arg.kind.ends_with_space() {
950 result.push_str(&indent_str);
951 } else if let Some(ref next_arg) = iter.peek() {
952 let space_before_dollar =
953 !arg.kind.ends_with_space() && next_arg.kind.starts_with_dollar();
954 let space_before_brace = next_arg.kind.starts_with_brace();
955 if space_before_dollar || space_before_brace {
961 if !use_multiple_lines && result.len() >= shape.width {
968 // This is a bit sketchy. The token rules probably need tweaking, but it works
969 // for some common cases. I hope the basic logic is sufficient. Note that the
970 // meaning of some tokens is a bit different here from usual Rust, e.g., `*`
971 // and `(`/`)` have special meaning.
973 // We always try and format on one line.
974 // FIXME: Use multi-line when every thing does not fit on one line.
975 fn format_macro_args(
976 context: &RewriteContext,
977 toks: ThinTokenStream,
979 ) -> Option<String> {
980 if !context.config.format_macro_matchers() {
981 let token_stream: TokenStream = toks.into();
982 let span = span_for_token_stream(token_stream);
983 return Some(match span {
984 Some(span) => context.snippet(span).to_owned(),
985 None => String::new(),
988 let parsed_args = MacroArgParser::new().parse(toks)?;
989 wrap_macro_args(context, &parsed_args, shape)
992 fn span_for_token_stream(token_stream: TokenStream) -> Option<Span> {
993 token_stream.trees().next().map(|tt| tt.span())
996 // We should insert a space if the next token is a:
997 #[derive(Copy, Clone, PartialEq)]
1001 Ident, // Or ident/literal-like thing.
1005 fn force_space_before(tok: &Token) -> bool {
1006 debug!("tok: force_space_before {:?}", tok);
1027 | Token::Dollar => true,
1032 fn ident_like(tok: &Token) -> bool {
1034 Token::Ident(..) | Token::Literal(..) | Token::Lifetime(_) => true,
1039 fn next_space(tok: &Token) -> SpaceState {
1040 debug!("next_space: {:?}", tok);
1044 | Token::BinOp(BinOpToken::And)
1053 | Token::Question => SpaceState::Punctuation,
1058 | Token::OpenDelim(_)
1059 | Token::CloseDelim(_)
1060 | Token::Whitespace => SpaceState::Never,
1062 Token::Literal(..) | Token::Ident(..) | Token::Lifetime(_) => SpaceState::Ident,
1064 _ => SpaceState::Always,
1068 /// Tries to convert a macro use into a short hand try expression. Returns None
1069 /// when the macro is not an instance of try! (or parsing the inner expression
1071 pub fn convert_try_mac(mac: &ast::Mac, context: &RewriteContext) -> Option<ast::Expr> {
1072 if &format!("{}", mac.node.path) == "try" {
1073 let ts: TokenStream = mac.node.tts.clone().into();
1074 let mut parser = new_parser_from_tts(context.parse_session, ts.trees().collect());
1077 id: ast::NodeId::new(0), // dummy value
1078 node: ast::ExprKind::Try(parser.parse_expr().ok()?),
1079 span: mac.span, // incorrect span, but shouldn't matter too much
1080 attrs: ThinVec::new(),
1087 fn macro_style(mac: &ast::Mac, context: &RewriteContext) -> DelimToken {
1088 let snippet = context.snippet(mac.span);
1089 let paren_pos = snippet.find_uncommented("(").unwrap_or(usize::max_value());
1090 let bracket_pos = snippet.find_uncommented("[").unwrap_or(usize::max_value());
1091 let brace_pos = snippet.find_uncommented("{").unwrap_or(usize::max_value());
1093 if paren_pos < bracket_pos && paren_pos < brace_pos {
1095 } else if bracket_pos < brace_pos {
1102 /// Indent each line according to the specified `indent`.
1130 fn indent_macro_snippet(
1131 context: &RewriteContext,
1134 ) -> Option<String> {
1135 let mut lines = LineClasses::new(macro_str);
1136 let first_line = lines.next().map(|(_, s)| s.trim_right().to_owned())?;
1137 let mut trimmed_lines = Vec::with_capacity(16);
1139 let mut veto_trim = false;
1140 let min_prefix_space_width = lines
1141 .filter_map(|(kind, line)| {
1142 let mut trimmed = true;
1143 let prefix_space_width = if is_empty_line(&line) {
1146 Some(get_prefix_space_width(context, &line))
1149 let line = if veto_trim || (kind.is_string() && !line.ends_with('\\')) {
1150 veto_trim = kind.is_string() && !line.ends_with('\\');
1154 line.trim().to_owned()
1156 trimmed_lines.push((trimmed, line, prefix_space_width));
1158 // when computing the minimum, do not consider lines within a string
1160 FullCodeCharKind::InString | FullCodeCharKind::EndString => None,
1161 _ => prefix_space_width,
1167 first_line + "\n" + &trimmed_lines
1170 |&(trimmed, ref line, prefix_space_width)| match prefix_space_width {
1171 _ if !trimmed => line.to_owned(),
1172 Some(original_indent_width) => {
1173 let new_indent_width = indent.width() + original_indent_width
1174 .saturating_sub(min_prefix_space_width);
1175 let new_indent = Indent::from_width(context.config, new_indent_width);
1176 format!("{}{}", new_indent.to_string(context.config), line)
1178 None => String::new(),
1181 .collect::<Vec<_>>()
1186 fn get_prefix_space_width(context: &RewriteContext, s: &str) -> usize {
1188 for c in s.chars() {
1191 '\t' => width += context.config.tab_spaces(),
1198 fn is_empty_line(s: &str) -> bool {
1199 s.is_empty() || s.chars().all(char::is_whitespace)
1202 // A very simple parser that just parses a macros 2.0 definition into its branches.
1203 // Currently we do not attempt to parse any further than that.
1205 struct MacroParser {
1210 // (`(` ... `)` `=>` `{` ... `}`)*
1211 fn parse(&mut self) -> Option<Macro> {
1212 let mut branches = vec![];
1213 while self.toks.look_ahead(1).is_some() {
1214 branches.push(self.parse_branch()?);
1217 Some(Macro { branches })
1220 // `(` ... `)` `=>` `{` ... `}`
1221 fn parse_branch(&mut self) -> Option<MacroBranch> {
1222 let tok = self.toks.next()?;
1223 let (lo, args_paren_kind) = match tok {
1224 TokenTree::Token(..) => return None,
1225 TokenTree::Delimited(delimited_span, ref d) => (delimited_span.open.lo(), d.delim),
1227 let args = tok.joint().into();
1228 match self.toks.next()? {
1229 TokenTree::Token(_, Token::FatArrow) => {}
1232 let (mut hi, body, whole_body) = match self.toks.next()? {
1233 TokenTree::Token(..) => return None,
1234 TokenTree::Delimited(delimited_span, _) => {
1235 let data = delimited_span.entire().data();
1238 Span::new(data.lo + BytePos(1), data.hi - BytePos(1), data.ctxt),
1239 delimited_span.entire(),
1243 if let Some(TokenTree::Token(sp, Token::Semi)) = self.toks.look_ahead(0) {
1248 span: mk_sp(lo, hi),
1257 // A parsed macros 2.0 macro definition.
1259 branches: Vec<MacroBranch>,
1262 // FIXME: it would be more efficient to use references to the token streams
1263 // rather than clone them, if we can make the borrowing work out.
1264 struct MacroBranch {
1266 args_paren_kind: DelimToken,
1267 args: ThinTokenStream,
1275 context: &RewriteContext,
1277 multi_branch_style: bool,
1278 ) -> Option<String> {
1279 // Only attempt to format function-like macros.
1280 if self.args_paren_kind != DelimToken::Paren {
1281 // FIXME(#1539): implement for non-sugared macros.
1286 let mut result = format_macro_args(context, self.args.clone(), shape.sub_width(5)?)?;
1288 if multi_branch_style {
1292 if !context.config.format_macro_bodies() {
1294 result += context.snippet(self.whole_body);
1295 return Some(result);
1298 // The macro body is the most interesting part. It might end up as various
1299 // AST nodes, but also has special variables (e.g, `$foo`) which can't be
1300 // parsed as regular Rust code (and note that these can be escaped using
1301 // `$$`). We'll try and format like an AST node, but we'll substitute
1302 // variables for new names with the same length first.
1304 let old_body = context.snippet(self.body).trim();
1305 let (body_str, substs) = replace_names(old_body)?;
1306 let has_block_body = old_body.starts_with('{');
1308 let mut config = context.config.clone();
1309 config.set().hide_parse_errors(true);
1313 let body_indent = if has_block_body {
1316 shape.indent.block_indent(&config)
1318 let new_width = config.max_width() - body_indent.width();
1319 config.set().max_width(new_width);
1321 // First try to format as items, then as statements.
1322 let new_body = match ::format_snippet(&body_str, &config) {
1323 Some(new_body) => new_body,
1325 let new_width = new_width + config.tab_spaces();
1326 config.set().max_width(new_width);
1327 match ::format_code_block(&body_str, &config) {
1328 Some(new_body) => new_body,
1329 None => return None,
1333 let new_body = wrap_str(new_body, config.max_width(), shape)?;
1335 // Indent the body since it is in a block.
1336 let indent_str = body_indent.to_string(&config);
1337 let mut new_body = LineClasses::new(new_body.trim_right())
1339 (String::new(), true),
1340 |(mut s, need_indent), (kind, ref l)| {
1341 if !l.is_empty() && need_indent {
1344 (s + l + "\n", !kind.is_string() || l.ends_with('\\'))
1349 // Undo our replacement of macro variables.
1350 // FIXME: this could be *much* more efficient.
1351 for (old, new) in &substs {
1352 if old_body.find(new).is_some() {
1353 debug!("rewrite_macro_def: bailing matching variable: `{}`", new);
1356 new_body = new_body.replace(new, old);
1360 result += new_body.trim();
1361 } else if !new_body.is_empty() {
1363 result += &new_body;
1364 result += &shape.indent.to_string(&config);
1373 /// Format `lazy_static!` from https://crates.io/crates/lazy_static.
1375 /// # Expected syntax
1379 /// [pub] static ref NAME_1: TYPE_1 = EXPR_1;
1380 /// [pub] static ref NAME_2: TYPE_2 = EXPR_2;
1382 /// [pub] static ref NAME_N: TYPE_N = EXPR_N;
1385 fn format_lazy_static(context: &RewriteContext, shape: Shape, ts: &TokenStream) -> Option<String> {
1386 let mut result = String::with_capacity(1024);
1387 let mut parser = new_parser_from_tts(context.parse_session, ts.trees().collect());
1388 let nested_shape = shape
1389 .block_indent(context.config.tab_spaces())
1390 .with_max_width(context.config);
1392 result.push_str("lazy_static! {");
1393 result.push_str(&nested_shape.indent.to_string_with_newline(context.config));
1395 macro parse_or($method:ident $(,)* $($arg:expr),* $(,)*) {
1396 match parser.$method($($arg,)*) {
1398 if parser.sess.span_diagnostic.has_errors() {
1399 parser.sess.span_diagnostic.reset_err_count();
1407 parser.sess.span_diagnostic.reset_err_count();
1413 while parser.token != Token::Eof {
1414 // Parse a `lazy_static!` item.
1415 let vis = ::utils::format_visibility(context, &parse_or!(parse_visibility, false));
1416 parser.eat_keyword(symbol::keywords::Static);
1417 parser.eat_keyword(symbol::keywords::Ref);
1418 let id = parse_or!(parse_ident);
1419 parser.eat(&Token::Colon);
1420 let ty = parse_or!(parse_ty);
1421 parser.eat(&Token::Eq);
1422 let expr = parse_or!(parse_expr);
1423 parser.eat(&Token::Semi);
1425 // Rewrite as a static item.
1426 let mut stmt = String::with_capacity(128);
1427 stmt.push_str(&format!(
1428 "{}static ref {}: {} =",
1431 ty.rewrite(context, nested_shape)?
1433 result.push_str(&::expr::rewrite_assign_rhs(
1437 nested_shape.sub_width(1)?,
1440 if parser.token != Token::Eof {
1441 result.push_str(&nested_shape.indent.to_string_with_newline(context.config));
1445 result.push_str(&shape.indent.to_string_with_newline(context.config));
1451 fn rewrite_macro_with_items(
1452 context: &RewriteContext,
1457 position: MacroPosition,
1459 ) -> Option<String> {
1460 let (opener, closer) = match style {
1461 DelimToken::Paren => ("(", ")"),
1462 DelimToken::Bracket => ("[", "]"),
1463 DelimToken::Brace => (" {", "}"),
1466 let trailing_semicolon = match style {
1467 DelimToken::Paren | DelimToken::Bracket if position == MacroPosition::Item => ";",
1471 let mut visitor = FmtVisitor::from_context(context);
1472 visitor.block_indent = shape.indent.block_indent(context.config);
1473 visitor.last_pos = context.snippet_provider.span_after(span, opener.trim());
1475 let item = match item {
1476 MacroArg::Item(item) => item,
1479 visitor.visit_item(&item);
1482 let mut result = String::with_capacity(256);
1483 result.push_str(¯o_name);
1484 result.push_str(opener);
1485 result.push_str(&visitor.block_indent.to_string_with_newline(context.config));
1486 result.push_str(visitor.buffer.trim());
1487 result.push_str(&shape.indent.to_string_with_newline(context.config));
1488 result.push_str(closer);
1489 result.push_str(trailing_semicolon);
1490 return Some(result);