From 5d973d2e8c1021ca8a7844f5d994c2e2be8b7a07 Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Wed, 24 Jan 2018 18:21:01 +0000 Subject: Initial support for macros 1.1 --- src/macros.rs | 150 ++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 84 insertions(+), 66 deletions(-) (limited to 'src') diff --git a/src/macros.rs b/src/macros.rs index 7df793ca79d..86ac93d19be 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -291,88 +291,103 @@ pub fn rewrite_macro_def( ) -> Option { let snippet = Some(remove_trailing_white_spaces(context.snippet(span))); - if def.legacy { - return snippet; - } - let mut parser = MacroParser::new(def.stream().into_trees()); - let mut parsed_def = match parser.parse() { + let parsed_def = match parser.parse() { Some(def) => def, None => return snippet, }; - // Only attempt to format function-like macros. - if parsed_def.branches.len() != 1 || parsed_def.branches[0].args_paren_kind != DelimToken::Paren - { - // FIXME(#1539): implement for non-sugared macros. - return snippet; - } + let mut result = if def.legacy { + String::from("macro_rules!") + } else { + format!("{}macro", format_visibility(vis)) + }; - let branch = parsed_def.branches.remove(0); - let args_str = format_macro_args(branch.args)?; + result += " "; + result += &ident.name.as_str(); + result += " {"; - // The macro body is the most interesting part. It might end up as various - // AST nodes, but also has special variables (e.g, `$foo`) which can't be - // parsed as regular Rust code (and note that these can be escaped using - // `$$`). We'll try and format like an AST node, but we'll substitute - // variables for new names with the same length first. + let mac_indent = indent.block_indent(context.config); + let mac_indent_str = mac_indent.to_string(context.config); - let old_body = context.snippet(branch.body).trim(); - let (body_str, substs) = match replace_names(old_body) { - Some(result) => result, - None => return snippet, - }; + for branch in parsed_def.branches { + // Only attempt to format function-like macros. + if branch.args_paren_kind != DelimToken::Paren { + // FIXME(#1539): implement for non-sugared macros. + return snippet; + } + + result += "\n"; + result += &mac_indent_str; + result += "("; + result += &format_macro_args(branch.args)?; + result += ") => {\n"; + + // The macro body is the most interesting part. It might end up as various + // AST nodes, but also has special variables (e.g, `$foo`) which can't be + // parsed as regular Rust code (and note that these can be escaped using + // `$$`). We'll try and format like an AST node, but we'll substitute + // variables for new names with the same length first. + + let old_body = context.snippet(branch.body).trim(); + let (body_str, substs) = match replace_names(old_body) { + Some(result) => result, + None => return snippet, + }; - // We'll hack the indent below, take this into account when formatting, - let mut config = context.config.clone(); - let new_width = config.max_width() - indent.block_indent(&config).width(); - config.set().max_width(new_width); - config.set().hide_parse_errors(true); + // We'll hack the indent below, take this into account when formatting, + let mut config = context.config.clone(); + let body_indent = mac_indent.block_indent(&config); + let new_width = config.max_width() - body_indent.width(); + config.set().max_width(new_width); + config.set().hide_parse_errors(true); - // First try to format as items, then as statements. - let new_body = match ::format_snippet(&body_str, &config) { - Some(new_body) => new_body, - None => match ::format_code_block(&body_str, &config) { + // First try to format as items, then as statements. + let new_body = match ::format_snippet(&body_str, &config) { Some(new_body) => new_body, - None => return snippet, - }, - }; + None => match ::format_code_block(&body_str, &config) { + Some(new_body) => new_body, + None => return snippet, + }, + }; - // Indent the body since it is in a block. - let indent_str = indent.block_indent(&config).to_string(&config); - let mut new_body = new_body - .lines() - .map(|l| { - if l.is_empty() { - l.to_owned() - } else { - format!("{}{}", indent_str, l) + // Indent the body since it is in a block. + let indent_str = body_indent.to_string(&config); + let mut new_body = new_body + .trim_right() + .lines() + .fold(String::new(), |mut s, l| { + if !l.is_empty() { + s += &indent_str; + } + s + l + "\n" + }); + + // Undo our replacement of macro variables. + // FIXME: this could be *much* more efficient. + for (old, new) in &substs { + if old_body.find(new).is_some() { + debug!( + "rewrite_macro_def: bailing matching variable: `{}` in `{}`", + new, ident + ); + return snippet; } - }) - .collect::>() - .join("\n"); - - // Undo our replacement of macro variables. - // FIXME: this could be *much* more efficient. - for (old, new) in &substs { - if old_body.find(new).is_some() { - debug!( - "rewrite_macro_def: bailing matching variable: `{}` in `{}`", - new, ident - ); - return snippet; + new_body = new_body.replace(new, old); + } + + result += &new_body; + + result += &mac_indent_str; + result += "}"; + if def.legacy{ + result += ";"; } - new_body = new_body.replace(new, old); + result += "\n"; } - let result = format!( - "{}macro {}({}) {{\n{}\n{}}}", - format_visibility(vis), - ident, - args_str, - new_body, - indent.to_string(context.config), - ); + result += &indent.to_string(context.config); + result += "}"; Some(result) } @@ -729,6 +744,9 @@ impl MacroParser { Span::new(data.lo + BytePos(1), data.hi - BytePos(1), data.ctxt) } }; + if let Some(TokenTree::Token(_, Token::Semi)) = self.toks.look_ahead(0) { + self.toks.next(); + } Some(MacroBranch { args, args_paren_kind, -- cgit 1.4.1-3-g733a5 From 9318b4d2cfc3690812a4cad93934d505d1a6f72d Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Wed, 24 Jan 2018 19:25:57 +0000 Subject: Update some macro tests --- src/bin/cargo-fmt.rs | 2 +- tests/target/macro_not_expr.rs | 3 ++- tests/target/macros.rs | 46 +++++++++++++++++++++++++----------------- 3 files changed, 31 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/bin/cargo-fmt.rs b/src/bin/cargo-fmt.rs index 180c6f0abf3..2c5f16b46fb 100644 --- a/src/bin/cargo-fmt.rs +++ b/src/bin/cargo-fmt.rs @@ -97,7 +97,7 @@ fn execute() -> i32 { } macro_rules! print_usage { - ($print:ident, $opts:ident, $reason:expr) => ({ + ($print: ident, $opts: ident, $reason: expr) => ({ let msg = format!("{}\nusage: cargo fmt [options]", $reason); $print!( "{}\nThis utility formats all bin and lib files of the current crate using rustfmt. \ diff --git a/tests/target/macro_not_expr.rs b/tests/target/macro_not_expr.rs index d8de4dce38f..20dcfe2d622 100644 --- a/tests/target/macro_not_expr.rs +++ b/tests/target/macro_not_expr.rs @@ -1,5 +1,6 @@ macro_rules! test { - ($($t:tt)*) => {} + ($($t: tt)*) => { + }; } fn main() { diff --git a/tests/target/macros.rs b/tests/target/macros.rs index a79eb8fb294..471c90bf470 100644 --- a/tests/target/macros.rs +++ b/tests/target/macros.rs @@ -141,7 +141,8 @@ fn issue_1555() { fn issue1178() { macro_rules! foo { - (#[$attr:meta] $name:ident) => {} + (#[$attr: meta] $name: ident) => { + }; } foo!( @@ -246,11 +247,15 @@ fn __bindgen_test_layout_HandleWithDtor_open0_int_close0_instantiation() { // #878 macro_rules! try_opt { - ($expr:expr) => (match $expr { - Some(val) => val, + ($expr: expr) => { + match $expr { + Some(val) => val, - None => { return None; } - }) + None => { + return None; + } + } + }; } // #2214 @@ -885,24 +890,29 @@ fn macro_in_pattern_position() { }; } -macro foo() { - +macro foo { + () => { + } } -pub macro bar($x: ident + $y: expr;) { - fn foo($x: Foo) { - long_function( - a_long_argument_to_a_long_function_is_what_this_is(AAAAAAAAAAAAAAAAAAAAAAAAAAAA), - $x.bar($y), - ); +pub macro bar { + ($x: ident + $y: expr;) => { + fn foo($x: Foo) { + long_function( + a_long_argument_to_a_long_function_is_what_this_is(AAAAAAAAAAAAAAAAAAAAAAAAAAAA), + $x.bar($y), + ); + } } } -macro foo() { - // a comment - fn foo() { - // another comment - bar(); +macro foo { + () => { + // a comment + fn foo() { + // another comment + bar(); + } } } -- cgit 1.4.1-3-g733a5 From 1b9fd0134367be836ff53422175cfcff3eeb06d6 Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Thu, 25 Jan 2018 13:28:55 +0000 Subject: Support compact macros 2.0 representation --- src/macros.rs | 36 ++++++++++++++++++++++++++---------- tests/target/macros.rs | 35 ++++++++++++++--------------------- 2 files changed, 40 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/macros.rs b/src/macros.rs index 86ac93d19be..a15227fb020 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -305,9 +305,16 @@ pub fn rewrite_macro_def( result += " "; result += &ident.name.as_str(); - result += " {"; - let mac_indent = indent.block_indent(context.config); + let multi_branch_style = def.legacy || parsed_def.branches.len() != 1; + + let mac_indent = if multi_branch_style { + result += " {"; + indent.block_indent(context.config) + } else { + indent + }; + let mac_indent_str = mac_indent.to_string(context.config); for branch in parsed_def.branches { @@ -317,11 +324,18 @@ pub fn rewrite_macro_def( return snippet; } - result += "\n"; - result += &mac_indent_str; - result += "("; - result += &format_macro_args(branch.args)?; - result += ") => {\n"; + let args = format!("({})", format_macro_args(branch.args)?); + + if multi_branch_style { + result += "\n"; + result += &mac_indent_str; + result += &args; + result += " =>"; + } else { + result += &args; + } + + result += " {\n"; // The macro body is the most interesting part. It might end up as various // AST nodes, but also has special variables (e.g, `$foo`) which can't be @@ -380,14 +394,16 @@ pub fn rewrite_macro_def( result += &mac_indent_str; result += "}"; - if def.legacy{ + if def.legacy { result += ";"; } result += "\n"; } - result += &indent.to_string(context.config); - result += "}"; + if multi_branch_style { + result += &indent.to_string(context.config); + result += "}"; + } Some(result) } diff --git a/tests/target/macros.rs b/tests/target/macros.rs index 471c90bf470..82cc76554f5 100644 --- a/tests/target/macros.rs +++ b/tests/target/macros.rs @@ -27,9 +27,8 @@ fn main() { ); kaas!( - // comments - a, // post macro - b // another + /* comments */ a, /* post macro */ + b /* another */ ); trailingcomma!(a, b, c,); @@ -890,29 +889,23 @@ fn macro_in_pattern_position() { }; } -macro foo { - () => { - } +macro foo() { } -pub macro bar { - ($x: ident + $y: expr;) => { - fn foo($x: Foo) { - long_function( - a_long_argument_to_a_long_function_is_what_this_is(AAAAAAAAAAAAAAAAAAAAAAAAAAAA), - $x.bar($y), - ); - } +pub macro bar($x: ident + $y: expr;) { + fn foo($x: Foo) { + long_function( + a_long_argument_to_a_long_function_is_what_this_is(AAAAAAAAAAAAAAAAAAAAAAAAAAAA), + $x.bar($y), + ); } } -macro foo { - () => { - // a comment - fn foo() { - // another comment - bar(); - } +macro foo() { + // a comment + fn foo() { + // another comment + bar(); } } -- cgit 1.4.1-3-g733a5 From 5bd036fcac1b109baf6b0d9a05af5232ec82c495 Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Thu, 25 Jan 2018 14:06:37 +0000 Subject: Optimise common `=> {{` macro pattern --- src/bin/cargo-fmt.rs | 4 ++-- src/macros.rs | 29 +++++++++++++++++++++-------- tests/target/macro_rules.rs | 10 ++++------ 3 files changed, 27 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/bin/cargo-fmt.rs b/src/bin/cargo-fmt.rs index 2c5f16b46fb..1acad99688a 100644 --- a/src/bin/cargo-fmt.rs +++ b/src/bin/cargo-fmt.rs @@ -97,14 +97,14 @@ fn execute() -> i32 { } macro_rules! print_usage { - ($print: ident, $opts: ident, $reason: expr) => ({ + ($print: ident, $opts: ident, $reason: expr) => {{ let msg = format!("{}\nusage: cargo fmt [options]", $reason); $print!( "{}\nThis utility formats all bin and lib files of the current crate using rustfmt. \ Arguments after `--` are passed to rustfmt.", $opts.usage(&msg) ); - }) + }}; } fn print_usage_to_stdout(opts: &Options, reason: &str) { diff --git a/src/macros.rs b/src/macros.rs index a15227fb020..f362736ea92 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -335,8 +335,6 @@ pub fn rewrite_macro_def( result += &args; } - result += " {\n"; - // The macro body is the most interesting part. It might end up as various // AST nodes, but also has special variables (e.g, `$foo`) which can't be // parsed as regular Rust code (and note that these can be escaped using @@ -349,13 +347,23 @@ pub fn rewrite_macro_def( None => return snippet, }; - // We'll hack the indent below, take this into account when formatting, let mut config = context.config.clone(); - let body_indent = mac_indent.block_indent(&config); - let new_width = config.max_width() - body_indent.width(); - config.set().max_width(new_width); config.set().hide_parse_errors(true); + result += " {"; + + let has_block_body = old_body.starts_with("{"); + + let body_indent = if has_block_body { + mac_indent + } else { + // We'll hack the indent below, take this into account when formatting, + let body_indent = mac_indent.block_indent(&config); + let new_width = config.max_width() - body_indent.width(); + config.set().max_width(new_width); + body_indent + }; + // First try to format as items, then as statements. let new_body = match ::format_snippet(&body_str, &config) { Some(new_body) => new_body, @@ -390,9 +398,14 @@ pub fn rewrite_macro_def( new_body = new_body.replace(new, old); } - result += &new_body; + if has_block_body { + result += new_body.trim(); + } else { + result += "\n"; + result += &new_body; + result += &mac_indent_str; + } - result += &mac_indent_str; result += "}"; if def.legacy { result += ";"; diff --git a/tests/target/macro_rules.rs b/tests/target/macro_rules.rs index c1b1d017adb..4c494c932d6 100644 --- a/tests/target/macro_rules.rs +++ b/tests/target/macro_rules.rs @@ -1,10 +1,8 @@ macro_rules! m { - ($expr: expr, $func: ident) => { - { - let x = $expr; - $func(x) - } - }; + ($expr: expr, $func: ident) => {{ + let x = $expr; + $func(x) + }}; () => { }; -- cgit 1.4.1-3-g733a5 From 9423cdba82026ce78bb5e24e7af619dde0b56a0e Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Thu, 25 Jan 2018 14:12:18 +0000 Subject: Omit newline for empty macro branches --- src/macros.rs | 2 +- tests/target/macro_not_expr.rs | 3 +-- tests/target/macro_rules.rs | 3 +-- tests/target/macros.rs | 6 ++---- 4 files changed, 5 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/macros.rs b/src/macros.rs index f362736ea92..2f7c4262b6b 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -400,7 +400,7 @@ pub fn rewrite_macro_def( if has_block_body { result += new_body.trim(); - } else { + } else if !new_body.is_empty() { result += "\n"; result += &new_body; result += &mac_indent_str; diff --git a/tests/target/macro_not_expr.rs b/tests/target/macro_not_expr.rs index 20dcfe2d622..c76a6492a9d 100644 --- a/tests/target/macro_not_expr.rs +++ b/tests/target/macro_not_expr.rs @@ -1,6 +1,5 @@ macro_rules! test { - ($($t: tt)*) => { - }; + ($($t: tt)*) => {}; } fn main() { diff --git a/tests/target/macro_rules.rs b/tests/target/macro_rules.rs index 4c494c932d6..d5ce0f7309e 100644 --- a/tests/target/macro_rules.rs +++ b/tests/target/macro_rules.rs @@ -4,8 +4,7 @@ macro_rules! m { $func(x) }}; - () => { - }; + () => {}; ($item: ident) => { mod macro_item { diff --git a/tests/target/macros.rs b/tests/target/macros.rs index 83116de7e3d..9b32c6623bb 100644 --- a/tests/target/macros.rs +++ b/tests/target/macros.rs @@ -141,8 +141,7 @@ fn issue_1555() { fn issue1178() { macro_rules! foo { - (#[$attr: meta] $name: ident) => { - }; + (#[$attr: meta] $name: ident) => {}; } foo!( @@ -890,8 +889,7 @@ fn macro_in_pattern_position() { }; } -macro foo() { -} +macro foo() {} pub macro bar($x: ident + $y: expr;) { fn foo($x: Foo) { -- cgit 1.4.1-3-g733a5 From 41c393c7516d4c1d5d8ad29fa177b43fb620b211 Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Sun, 28 Jan 2018 19:08:09 +0000 Subject: Keep delimiter as part of macro args list --- src/macros.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/macros.rs b/src/macros.rs index 2f7c4262b6b..10f03e95c2f 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -324,7 +324,7 @@ pub fn rewrite_macro_def( return snippet; } - let args = format!("({})", format_macro_args(branch.args)?); + let args = format_macro_args(branch.args)?; if multi_branch_style { result += "\n"; @@ -758,10 +758,12 @@ impl MacroParser { // `(` ... `)` `=>` `{` ... `}` fn parse_branch(&mut self) -> Option { - let (args_paren_kind, args) = match self.toks.next()? { + let tok = self.toks.next()?; + let args_paren_kind = match tok { TokenTree::Token(..) => return None, - TokenTree::Delimited(_, ref d) => (d.delim, d.tts.clone()), + TokenTree::Delimited(_, ref d) => d.delim, }; + let args = tok.joint().into(); match self.toks.next()? { TokenTree::Token(_, Token::FatArrow) => {} _ => return None, -- cgit 1.4.1-3-g733a5 From 70e77162621c7cde2435224cf1decdee088be27e Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Mon, 29 Jan 2018 10:15:18 +0000 Subject: Comments WIP --- src/macros.rs | 201 ++++++++++++++++++++++++++------------------ src/visitor.rs | 1 + tests/source/macro_rules.rs | 6 +- 3 files changed, 124 insertions(+), 84 deletions(-) (limited to 'src') diff --git a/src/macros.rs b/src/macros.rs index 10f03e95c2f..1c9ca3057f0 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -33,6 +33,7 @@ use syntax::util::ThinVec; use codemap::SpanUtils; use comment::{contains_comment, remove_trailing_white_spaces, FindUncommented}; use expr::{rewrite_array, rewrite_call_inner}; +use lists::{itemize_list, write_list, DefinitiveListTactic, ListFormatting, SeparatorPlace, SeparatorTactic}; use rewrite::{Rewrite, RewriteContext}; use shape::{Indent, Shape}; use utils::{format_visibility, mk_sp}; @@ -283,6 +284,7 @@ pub fn rewrite_macro( pub fn rewrite_macro_def( context: &RewriteContext, + shape: Shape, indent: Indent, def: &ast::MacroDef, ident: ast::Ident, @@ -317,101 +319,132 @@ pub fn rewrite_macro_def( let mac_indent_str = mac_indent.to_string(context.config); - for branch in parsed_def.branches { - // Only attempt to format function-like macros. - if branch.args_paren_kind != DelimToken::Paren { - // FIXME(#1539): implement for non-sugared macros. - return snippet; - } + let branch_items = itemize_list( + context.codemap, + parsed_def.branches.iter(), + "", + "", + |branch| branch.args_span.lo(), + |branch| branch.body.hi(), + |branch| { + let mut result = String::new(); + + // Only attempt to format function-like macros. + if branch.args_paren_kind != DelimToken::Paren { + // FIXME(#1539): implement for non-sugared macros. + return None; + } - let args = format_macro_args(branch.args)?; + let args = format_macro_args(branch.args.clone())?; - if multi_branch_style { - result += "\n"; - result += &mac_indent_str; - result += &args; - result += " =>"; - } else { - result += &args; - } + if multi_branch_style { + result += "\n"; + result += &mac_indent_str; + result += &args; + result += " =>"; + } else { + result += &args; + } - // The macro body is the most interesting part. It might end up as various - // AST nodes, but also has special variables (e.g, `$foo`) which can't be - // parsed as regular Rust code (and note that these can be escaped using - // `$$`). We'll try and format like an AST node, but we'll substitute - // variables for new names with the same length first. + // The macro body is the most interesting part. It might end up as various + // AST nodes, but also has special variables (e.g, `$foo`) which can't be + // parsed as regular Rust code (and note that these can be escaped using + // `$$`). We'll try and format like an AST node, but we'll substitute + // variables for new names with the same length first. - let old_body = context.snippet(branch.body).trim(); - let (body_str, substs) = match replace_names(old_body) { - Some(result) => result, - None => return snippet, - }; + let old_body = context.snippet(branch.body).trim(); + let (body_str, substs) = match replace_names(old_body) { + Some(result) => result, + None => return snippet, + }; - let mut config = context.config.clone(); - config.set().hide_parse_errors(true); + let mut config = context.config.clone(); + config.set().hide_parse_errors(true); - result += " {"; + result += " {"; - let has_block_body = old_body.starts_with("{"); + let has_block_body = old_body.starts_with('{'); - let body_indent = if has_block_body { - mac_indent - } else { - // We'll hack the indent below, take this into account when formatting, - let body_indent = mac_indent.block_indent(&config); - let new_width = config.max_width() - body_indent.width(); - config.set().max_width(new_width); - body_indent - }; + let body_indent = if has_block_body { + mac_indent + } else { + // We'll hack the indent below, take this into account when formatting, + let body_indent = mac_indent.block_indent(&config); + let new_width = config.max_width() - body_indent.width(); + config.set().max_width(new_width); + body_indent + }; - // First try to format as items, then as statements. - let new_body = match ::format_snippet(&body_str, &config) { - Some(new_body) => new_body, - None => match ::format_code_block(&body_str, &config) { + // First try to format as items, then as statements. + let new_body = match ::format_snippet(&body_str, &config) { Some(new_body) => new_body, - None => return snippet, - }, - }; + None => match ::format_code_block(&body_str, &config) { + Some(new_body) => new_body, + None => return None, + }, + }; - // Indent the body since it is in a block. - let indent_str = body_indent.to_string(&config); - let mut new_body = new_body - .trim_right() - .lines() - .fold(String::new(), |mut s, l| { - if !l.is_empty() { - s += &indent_str; + // Indent the body since it is in a block. + let indent_str = body_indent.to_string(&config); + let mut new_body = new_body + .trim_right() + .lines() + .fold(String::new(), |mut s, l| { + if !l.is_empty() { + s += &indent_str; + } + s + l + "\n" + }); + + // Undo our replacement of macro variables. + // FIXME: this could be *much* more efficient. + for (old, new) in &substs { + if old_body.find(new).is_some() { + debug!( + "rewrite_macro_def: bailing matching variable: `{}` in `{}`", + new, ident + ); + return None; } - s + l + "\n" - }); - - // Undo our replacement of macro variables. - // FIXME: this could be *much* more efficient. - for (old, new) in &substs { - if old_body.find(new).is_some() { - debug!( - "rewrite_macro_def: bailing matching variable: `{}` in `{}`", - new, ident - ); - return snippet; + new_body = new_body.replace(new, old); } - new_body = new_body.replace(new, old); - } - if has_block_body { - result += new_body.trim(); - } else if !new_body.is_empty() { + if has_block_body { + result += new_body.trim(); + } else if !new_body.is_empty() { + result += "\n"; + result += &new_body; + result += &mac_indent_str; + } + + result += "}"; + if def.legacy { + result += ";"; + } result += "\n"; - result += &new_body; - result += &mac_indent_str; - } + Some(result) + }, + span.lo(), + span.hi(), + false + ).collect::>(); + + let arm_shape = shape + .block_indent(context.config.tab_spaces()) + .with_max_width(context.config); + + let fmt = ListFormatting { + tactic: DefinitiveListTactic::Vertical, + separator: "", + trailing_separator: SeparatorTactic::Never, + separator_place: SeparatorPlace::Back, + shape: arm_shape, + ends_with_newline: false, + preserve_newline: true, + config: context.config, + }; - result += "}"; - if def.legacy { - result += ";"; - } - result += "\n"; - } + result += write_list(&branch_items, &fmt)?.as_str(); if multi_branch_style { result += &indent.to_string(context.config); @@ -759,9 +792,9 @@ impl MacroParser { // `(` ... `)` `=>` `{` ... `}` fn parse_branch(&mut self) -> Option { let tok = self.toks.next()?; - let args_paren_kind = match tok { + let (args_span, args_paren_kind) = match tok { TokenTree::Token(..) => return None, - TokenTree::Delimited(_, ref d) => d.delim, + TokenTree::Delimited(sp, ref d) => (sp, d.delim), }; let args = tok.joint().into(); match self.toks.next()? { @@ -779,8 +812,9 @@ impl MacroParser { self.toks.next(); } Some(MacroBranch { - args, args_paren_kind, + args_span, + args, body, }) } @@ -794,8 +828,9 @@ struct Macro { // FIXME: it would be more efficient to use references to the token streams // rather than clone them, if we can make the borrowing work out. struct MacroBranch { - args: ThinTokenStream, args_paren_kind: DelimToken, + args_span: Span, + args: ThinTokenStream, body: Span, } diff --git a/src/visitor.rs b/src/visitor.rs index 3157597697d..398fc57ce47 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -451,6 +451,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { ast::ItemKind::MacroDef(ref def) => { let rewrite = rewrite_macro_def( &self.get_context(), + self.shape(), self.block_indent, def, item.ident, diff --git a/tests/source/macro_rules.rs b/tests/source/macro_rules.rs index 24d4b669011..39de86b9bf6 100644 --- a/tests/source/macro_rules.rs +++ b/tests/source/macro_rules.rs @@ -1,4 +1,5 @@ macro_rules! m { + // a ($expr :expr, $( $func : ident ) * ) => { { let x = $expr; @@ -8,8 +9,11 @@ macro_rules! m { } }; - () => { }; + /* b */ + () => {/* c */}; + +// d ( $item:ident ) => { mod macro_item { struct $item ; } }; -- cgit 1.4.1-3-g733a5 From 6377c5223307e6bff3d1555c0cddd34bef1b68a0 Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Tue, 30 Jan 2018 17:05:31 +0000 Subject: Fix comment handling in macros --- src/macros.rs | 50 ++++++++++++++++++++++++--------------------- tests/source/macro_rules.rs | 31 ++++++++++++++++++++++++++++ tests/target/macro_rules.rs | 31 +++++++++++++++++++++++++++- 3 files changed, 88 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/macros.rs b/src/macros.rs index 1c9ca3057f0..bd1523f2dea 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -311,7 +311,6 @@ pub fn rewrite_macro_def( let multi_branch_style = def.legacy || parsed_def.branches.len() != 1; let mac_indent = if multi_branch_style { - result += " {"; indent.block_indent(context.config) } else { indent @@ -322,28 +321,25 @@ pub fn rewrite_macro_def( let branch_items = itemize_list( context.codemap, parsed_def.branches.iter(), - "", - "", - |branch| branch.args_span.lo(), - |branch| branch.body.hi(), + "}", + ";", + |branch| { + branch.span.lo() + }, + |branch| { + branch.span.hi() + }, |branch| { - let mut result = String::new(); - // Only attempt to format function-like macros. if branch.args_paren_kind != DelimToken::Paren { // FIXME(#1539): implement for non-sugared macros. return None; } - let args = format_macro_args(branch.args.clone())?; + let mut result = format_macro_args(branch.args.clone())?; if multi_branch_style { - result += "\n"; - result += &mac_indent_str; - result += &args; result += " =>"; - } else { - result += &args; } // The macro body is the most interesting part. It might end up as various @@ -418,13 +414,14 @@ pub fn rewrite_macro_def( } result += "}"; + if def.legacy { result += ";"; } - result += "\n"; + Some(result) }, - span.lo(), + context.codemap.span_after(span, "{"), span.hi(), false ).collect::>(); @@ -439,14 +436,20 @@ pub fn rewrite_macro_def( trailing_separator: SeparatorTactic::Never, separator_place: SeparatorPlace::Back, shape: arm_shape, - ends_with_newline: false, + ends_with_newline: true, preserve_newline: true, config: context.config, }; + if multi_branch_style { + result += " {\n"; + result += &mac_indent_str; + } + result += write_list(&branch_items, &fmt)?.as_str(); if multi_branch_style { + result += "\n"; result += &indent.to_string(context.config); result += "}"; } @@ -792,28 +795,29 @@ impl MacroParser { // `(` ... `)` `=>` `{` ... `}` fn parse_branch(&mut self) -> Option { let tok = self.toks.next()?; - let (args_span, args_paren_kind) = match tok { + let (lo, args_paren_kind) = match tok { TokenTree::Token(..) => return None, - TokenTree::Delimited(sp, ref d) => (sp, d.delim), + TokenTree::Delimited(sp, ref d) => (sp.lo(), d.delim), }; let args = tok.joint().into(); match self.toks.next()? { TokenTree::Token(_, Token::FatArrow) => {} _ => return None, } - let body = match self.toks.next()? { + let (mut hi, body) = match self.toks.next()? { TokenTree::Token(..) => return None, TokenTree::Delimited(sp, _) => { let data = sp.data(); - Span::new(data.lo + BytePos(1), data.hi - BytePos(1), data.ctxt) + (data.hi, Span::new(data.lo + BytePos(1), data.hi - BytePos(1), data.ctxt)) } }; - if let Some(TokenTree::Token(_, Token::Semi)) = self.toks.look_ahead(0) { + if let Some(TokenTree::Token(sp, Token::Semi)) = self.toks.look_ahead(0) { self.toks.next(); + hi = sp.hi(); } Some(MacroBranch { + span: mk_sp(lo, hi), args_paren_kind, - args_span, args, body, }) @@ -828,8 +832,8 @@ struct Macro { // FIXME: it would be more efficient to use references to the token streams // rather than clone them, if we can make the borrowing work out. struct MacroBranch { + span: Span, args_paren_kind: DelimToken, - args_span: Span, args: ThinTokenStream, body: Span, } diff --git a/tests/source/macro_rules.rs b/tests/source/macro_rules.rs index 39de86b9bf6..7d14f44971d 100644 --- a/tests/source/macro_rules.rs +++ b/tests/source/macro_rules.rs @@ -13,8 +13,39 @@ macro_rules! m { () => {/* c */}; + (@tag) => + { + + }; + // d ( $item:ident ) => { mod macro_item { struct $item ; } }; } + +macro m2 { + // a + ($expr :expr, $( $func : ident ) * ) => { + { + let x = $expr; + $func ( + x + ) + } + } + + /* b */ + + () => {/* c */} + + (@tag) => + { + + } + +// d +( $item:ident ) => { + mod macro_item { struct $item ; } +} +} diff --git a/tests/target/macro_rules.rs b/tests/target/macro_rules.rs index 5835c27faee..647d442034f 100644 --- a/tests/target/macro_rules.rs +++ b/tests/target/macro_rules.rs @@ -1,14 +1,43 @@ macro_rules! m { + // a ($expr: expr, $($func: ident)*) => {{ let x = $expr; $func(x) }}; - () => {}; + /* b */ + () => { + /* c */ + }; + + (@tag) => {}; + // d ($item: ident) => { mod macro_item { struct $item; } }; } + +macro m2 { + // a + ($expr: expr, $($func: ident)*) => {{ + let x = $expr; + $func(x) + }} + + /* b */ + () => { + /* c */ + } + + (@tag) => {} + + // d + ($item: ident) => { + mod macro_item { + struct $item; + } + } +} -- cgit 1.4.1-3-g733a5 From bc9185451d547a071b74e9432d1c447dbbdeac6e Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Tue, 30 Jan 2018 17:14:13 +0000 Subject: Move ; between macro branches to a separator --- src/macros.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/macros.rs b/src/macros.rs index bd1523f2dea..d7e49ec0e0a 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -415,10 +415,6 @@ pub fn rewrite_macro_def( result += "}"; - if def.legacy { - result += ";"; - } - Some(result) }, context.codemap.span_after(span, "{"), @@ -432,8 +428,8 @@ pub fn rewrite_macro_def( let fmt = ListFormatting { tactic: DefinitiveListTactic::Vertical, - separator: "", - trailing_separator: SeparatorTactic::Never, + separator: if def.legacy { ";" } else { "" }, + trailing_separator: SeparatorTactic::Always, separator_place: SeparatorPlace::Back, shape: arm_shape, ends_with_newline: true, -- cgit 1.4.1-3-g733a5 From 571af9d4b11d8ccc64ab637d9881485e0f6a059a Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Tue, 30 Jan 2018 17:24:28 +0000 Subject: Format --- src/macros.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/macros.rs b/src/macros.rs index d7e49ec0e0a..42a091fc57b 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -323,12 +323,8 @@ pub fn rewrite_macro_def( parsed_def.branches.iter(), "}", ";", - |branch| { - branch.span.lo() - }, - |branch| { - branch.span.hi() - }, + |branch| branch.span.lo(), + |branch| branch.span.hi(), |branch| { // Only attempt to format function-like macros. if branch.args_paren_kind != DelimToken::Paren { @@ -419,7 +415,7 @@ pub fn rewrite_macro_def( }, context.codemap.span_after(span, "{"), span.hi(), - false + false, ).collect::>(); let arm_shape = shape @@ -804,7 +800,10 @@ impl MacroParser { TokenTree::Token(..) => return None, TokenTree::Delimited(sp, _) => { let data = sp.data(); - (data.hi, Span::new(data.lo + BytePos(1), data.hi - BytePos(1), data.ctxt)) + ( + data.hi, + Span::new(data.lo + BytePos(1), data.hi - BytePos(1), data.ctxt), + ) } }; if let Some(TokenTree::Token(sp, Token::Semi)) = self.toks.look_ahead(0) { -- cgit 1.4.1-3-g733a5 From d8c154f05254cf09bf15a14fdfdadb4f50fb9e55 Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Tue, 30 Jan 2018 18:19:47 +0000 Subject: Extract branch rewrite function --- src/macros.rs | 193 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 95 insertions(+), 98 deletions(-) (limited to 'src') diff --git a/src/macros.rs b/src/macros.rs index 42a091fc57b..bb623368b97 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -310,14 +310,14 @@ pub fn rewrite_macro_def( let multi_branch_style = def.legacy || parsed_def.branches.len() != 1; - let mac_indent = if multi_branch_style { - indent.block_indent(context.config) + let arm_shape = if multi_branch_style { + shape + .block_indent(context.config.tab_spaces()) + .with_max_width(context.config) } else { - indent + shape }; - let mac_indent_str = mac_indent.to_string(context.config); - let branch_items = itemize_list( context.codemap, parsed_def.branches.iter(), @@ -325,103 +325,12 @@ pub fn rewrite_macro_def( ";", |branch| branch.span.lo(), |branch| branch.span.hi(), - |branch| { - // Only attempt to format function-like macros. - if branch.args_paren_kind != DelimToken::Paren { - // FIXME(#1539): implement for non-sugared macros. - return None; - } - - let mut result = format_macro_args(branch.args.clone())?; - - if multi_branch_style { - result += " =>"; - } - - // The macro body is the most interesting part. It might end up as various - // AST nodes, but also has special variables (e.g, `$foo`) which can't be - // parsed as regular Rust code (and note that these can be escaped using - // `$$`). We'll try and format like an AST node, but we'll substitute - // variables for new names with the same length first. - - let old_body = context.snippet(branch.body).trim(); - let (body_str, substs) = match replace_names(old_body) { - Some(result) => result, - None => return snippet, - }; - - let mut config = context.config.clone(); - config.set().hide_parse_errors(true); - - result += " {"; - - let has_block_body = old_body.starts_with('{'); - - let body_indent = if has_block_body { - mac_indent - } else { - // We'll hack the indent below, take this into account when formatting, - let body_indent = mac_indent.block_indent(&config); - let new_width = config.max_width() - body_indent.width(); - config.set().max_width(new_width); - body_indent - }; - - // First try to format as items, then as statements. - let new_body = match ::format_snippet(&body_str, &config) { - Some(new_body) => new_body, - None => match ::format_code_block(&body_str, &config) { - Some(new_body) => new_body, - None => return None, - }, - }; - - // Indent the body since it is in a block. - let indent_str = body_indent.to_string(&config); - let mut new_body = new_body - .trim_right() - .lines() - .fold(String::new(), |mut s, l| { - if !l.is_empty() { - s += &indent_str; - } - s + l + "\n" - }); - - // Undo our replacement of macro variables. - // FIXME: this could be *much* more efficient. - for (old, new) in &substs { - if old_body.find(new).is_some() { - debug!( - "rewrite_macro_def: bailing matching variable: `{}` in `{}`", - new, ident - ); - return None; - } - new_body = new_body.replace(new, old); - } - - if has_block_body { - result += new_body.trim(); - } else if !new_body.is_empty() { - result += "\n"; - result += &new_body; - result += &mac_indent_str; - } - - result += "}"; - - Some(result) - }, + |branch| branch.rewrite(context, arm_shape, multi_branch_style), context.codemap.span_after(span, "{"), span.hi(), false, ).collect::>(); - let arm_shape = shape - .block_indent(context.config.tab_spaces()) - .with_max_width(context.config); - let fmt = ListFormatting { tactic: DefinitiveListTactic::Vertical, separator: if def.legacy { ";" } else { "" }, @@ -435,7 +344,7 @@ pub fn rewrite_macro_def( if multi_branch_style { result += " {\n"; - result += &mac_indent_str; + result += &arm_shape.indent.to_string(context.config); } result += write_list(&branch_items, &fmt)?.as_str(); @@ -833,6 +742,94 @@ struct MacroBranch { body: Span, } +impl MacroBranch { + fn rewrite(&self, context: &RewriteContext, shape: Shape, multi_branch_style: bool) -> Option { + // Only attempt to format function-like macros. + if self.args_paren_kind != DelimToken::Paren { + // FIXME(#1539): implement for non-sugared macros. + return None; + } + + let mut result = format_macro_args(self.args.clone())?; + + if multi_branch_style { + result += " =>"; + } + + // The macro body is the most interesting part. It might end up as various + // AST nodes, but also has special variables (e.g, `$foo`) which can't be + // parsed as regular Rust code (and note that these can be escaped using + // `$$`). We'll try and format like an AST node, but we'll substitute + // variables for new names with the same length first. + + let old_body = context.snippet(self.body).trim(); + let (body_str, substs) = replace_names(old_body)?; + + let mut config = context.config.clone(); + config.set().hide_parse_errors(true); + + result += " {"; + + let has_block_body = old_body.starts_with('{'); + + let body_indent = if has_block_body { + shape.indent + } else { + // We'll hack the indent below, take this into account when formatting, + let body_indent = shape.indent.block_indent(&config); + let new_width = config.max_width() - body_indent.width(); + config.set().max_width(new_width); + body_indent + }; + + // First try to format as items, then as statements. + let new_body = match ::format_snippet(&body_str, &config) { + Some(new_body) => new_body, + None => match ::format_code_block(&body_str, &config) { + Some(new_body) => new_body, + None => return None, + }, + }; + + // Indent the body since it is in a block. + let indent_str = body_indent.to_string(&config); + let mut new_body = new_body + .trim_right() + .lines() + .fold(String::new(), |mut s, l| { + if !l.is_empty() { + s += &indent_str; + } + s + l + "\n" + }); + + // Undo our replacement of macro variables. + // FIXME: this could be *much* more efficient. + for (old, new) in &substs { + if old_body.find(new).is_some() { + debug!( + "rewrite_macro_def: bailing matching variable: `{}`", + new + ); + return None; + } + new_body = new_body.replace(new, old); + } + + if has_block_body { + result += new_body.trim(); + } else if !new_body.is_empty() { + result += "\n"; + result += &new_body; + result += &shape.indent.to_string(&config); + } + + result += "}"; + + Some(result) + } +} + #[cfg(test)] mod test { use super::*; -- cgit 1.4.1-3-g733a5 From 8691c64e9970043f13ed3d5a6f1ac62ced7159f3 Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Sun, 4 Feb 2018 12:09:03 +0000 Subject: cargo run cargo-fmt Reformat codebase with current version to pass self_tests (formats macros without repetitions). --- src/config.rs | 2 +- src/macros.rs | 21 ++++++++++++--------- src/spanned.rs | 24 +++++++++++------------- src/utils.rs | 19 ++++++++++--------- 4 files changed, 34 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/config.rs b/src/config.rs index c313f8e2aef..cca1779a4a8 100644 --- a/src/config.rs +++ b/src/config.rs @@ -36,7 +36,7 @@ macro_rules! is_nightly_channel { option_env!("CFG_RELEASE_CHANNEL") .map(|c| c == "nightly") .unwrap_or(true) - } + }; } macro_rules! configuration_option_enum{ diff --git a/src/macros.rs b/src/macros.rs index bb623368b97..3abfe6239fd 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -33,7 +33,8 @@ use syntax::util::ThinVec; use codemap::SpanUtils; use comment::{contains_comment, remove_trailing_white_spaces, FindUncommented}; use expr::{rewrite_array, rewrite_call_inner}; -use lists::{itemize_list, write_list, DefinitiveListTactic, ListFormatting, SeparatorPlace, SeparatorTactic}; +use lists::{itemize_list, write_list, DefinitiveListTactic, ListFormatting, SeparatorPlace, + SeparatorTactic}; use rewrite::{Rewrite, RewriteContext}; use shape::{Indent, Shape}; use utils::{format_visibility, mk_sp}; @@ -102,7 +103,7 @@ fn parse_macro_arg(parser: &mut Parser) -> Option { parser.sess.span_diagnostic.reset_err_count(); } } - } + }; } parse_macro_arg!(Expr, parse_expr); @@ -312,8 +313,8 @@ pub fn rewrite_macro_def( let arm_shape = if multi_branch_style { shape - .block_indent(context.config.tab_spaces()) - .with_max_width(context.config) + .block_indent(context.config.tab_spaces()) + .with_max_width(context.config) } else { shape }; @@ -743,7 +744,12 @@ struct MacroBranch { } impl MacroBranch { - fn rewrite(&self, context: &RewriteContext, shape: Shape, multi_branch_style: bool) -> Option { + fn rewrite( + &self, + context: &RewriteContext, + shape: Shape, + multi_branch_style: bool, + ) -> Option { // Only attempt to format function-like macros. if self.args_paren_kind != DelimToken::Paren { // FIXME(#1539): implement for non-sugared macros. @@ -807,10 +813,7 @@ impl MacroBranch { // FIXME: this could be *much* more efficient. for (old, new) in &substs { if old_body.find(new).is_some() { - debug!( - "rewrite_macro_def: bailing matching variable: `{}`", - new - ); + debug!("rewrite_macro_def: bailing matching variable: `{}`", new); return None; } new_body = new_body.replace(new, old); diff --git a/src/spanned.rs b/src/spanned.rs index eb36a117428..a431f3a544a 100644 --- a/src/spanned.rs +++ b/src/spanned.rs @@ -20,32 +20,30 @@ pub trait Spanned { } macro_rules! span_with_attrs_lo_hi { - ($this:ident, $lo:expr, $hi:expr) => { - { - let attrs = outer_attributes(&$this.attrs); - if attrs.is_empty() { - mk_sp($lo, $hi) - } else { - mk_sp(attrs[0].span.lo(), $hi) - } + ($this: ident, $lo: expr, $hi: expr) => {{ + let attrs = outer_attributes(&$this.attrs); + if attrs.is_empty() { + mk_sp($lo, $hi) + } else { + mk_sp(attrs[0].span.lo(), $hi) } - } + }}; } macro_rules! span_with_attrs { - ($this:ident) => { + ($this: ident) => { span_with_attrs_lo_hi!($this, $this.span.lo(), $this.span.hi()) - } + }; } macro_rules! implement_spanned { - ($this:ty) => { + ($this: ty) => { impl Spanned for $this { fn span(&self) -> Span { span_with_attrs!(self) } } - } + }; } // Implement `Spanned` for structs with `attrs` field. diff --git a/src/utils.rs b/src/utils.rs index 2f65d273246..443dc6c7a05 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -342,9 +342,9 @@ macro_rules! msg { // For format_missing and last_pos, need to use the source callsite (if applicable). // Required as generated code spans aren't guaranteed to follow on from the last span. macro_rules! source { - ($this:ident, $sp: expr) => { + ($this: ident, $sp: expr) => { $sp.source_callsite() - } + }; } pub fn mk_sp(lo: BytePos, hi: BytePos) -> Span { @@ -353,28 +353,29 @@ pub fn mk_sp(lo: BytePos, hi: BytePos) -> Span { // Return true if the given span does not intersect with file lines. macro_rules! out_of_file_lines_range { - ($self:ident, $span:expr) => { - !$self.config + ($self: ident, $span: expr) => { + !$self + .config .file_lines() .intersects(&$self.codemap.lookup_line_range($span)) - } + }; } macro_rules! skip_out_of_file_lines_range { - ($self:ident, $span:expr) => { + ($self: ident, $span: expr) => { if out_of_file_lines_range!($self, $span) { return None; } - } + }; } macro_rules! skip_out_of_file_lines_range_visitor { - ($self:ident, $span:expr) => { + ($self: ident, $span: expr) => { if out_of_file_lines_range!($self, $span) { $self.push_rewrite($span, None); return; } - } + }; } // Wraps String in an Option. Returns Some when the string adheres to the -- cgit 1.4.1-3-g733a5