@@ -33,6 +33,8 @@ use syntax::util::ThinVec;
33
33
use codemap:: SpanUtils ;
34
34
use comment:: { contains_comment, remove_trailing_white_spaces, FindUncommented } ;
35
35
use expr:: { rewrite_array, rewrite_call_inner} ;
36
+ use lists:: { itemize_list, write_list, DefinitiveListTactic , ListFormatting , SeparatorPlace ,
37
+ SeparatorTactic } ;
36
38
use rewrite:: { Rewrite , RewriteContext } ;
37
39
use shape:: { Indent , Shape } ;
38
40
use utils:: { format_visibility, mk_sp} ;
@@ -101,7 +103,7 @@ fn parse_macro_arg(parser: &mut Parser) -> Option<MacroArg> {
101
103
parser. sess. span_diagnostic. reset_err_count( ) ;
102
104
}
103
105
}
104
- }
106
+ } ;
105
107
}
106
108
107
109
parse_macro_arg ! ( Expr , parse_expr) ;
@@ -283,6 +285,7 @@ pub fn rewrite_macro(
283
285
284
286
pub fn rewrite_macro_def (
285
287
context : & RewriteContext ,
288
+ shape : Shape ,
286
289
indent : Indent ,
287
290
def : & ast:: MacroDef ,
288
291
ident : ast:: Ident ,
@@ -291,88 +294,67 @@ pub fn rewrite_macro_def(
291
294
) -> Option < String > {
292
295
let snippet = Some ( remove_trailing_white_spaces ( context. snippet ( span) ) ) ;
293
296
294
- if def. legacy {
295
- return snippet;
296
- }
297
-
298
297
let mut parser = MacroParser :: new ( def. stream ( ) . into_trees ( ) ) ;
299
- let mut parsed_def = match parser. parse ( ) {
298
+ let parsed_def = match parser. parse ( ) {
300
299
Some ( def) => def,
301
300
None => return snippet,
302
301
} ;
303
302
304
- // Only attempt to format function-like macros.
305
- if parsed_def. branches . len ( ) != 1 || parsed_def. branches [ 0 ] . args_paren_kind != DelimToken :: Paren
306
- {
307
- // FIXME(#1539): implement for non-sugared macros.
308
- return snippet;
309
- }
303
+ let mut result = if def. legacy {
304
+ String :: from ( "macro_rules!" )
305
+ } else {
306
+ format ! ( "{}macro" , format_visibility( vis) )
307
+ } ;
310
308
311
- let branch = parsed_def . branches . remove ( 0 ) ;
312
- let args_str = format_macro_args ( branch . args ) ? ;
309
+ result += " " ;
310
+ result += & ident . name . as_str ( ) ;
313
311
314
- // The macro body is the most interesting part. It might end up as various
315
- // AST nodes, but also has special variables (e.g, `$foo`) which can't be
316
- // parsed as regular Rust code (and note that these can be escaped using
317
- // `$$`). We'll try and format like an AST node, but we'll substitute
318
- // variables for new names with the same length first.
312
+ let multi_branch_style = def. legacy || parsed_def. branches . len ( ) != 1 ;
319
313
320
- let old_body = context. snippet ( branch. body ) . trim ( ) ;
321
- let ( body_str, substs) = match replace_names ( old_body) {
322
- Some ( result) => result,
323
- None => return snippet,
314
+ let arm_shape = if multi_branch_style {
315
+ shape
316
+ . block_indent ( context. config . tab_spaces ( ) )
317
+ . with_max_width ( context. config )
318
+ } else {
319
+ shape
324
320
} ;
325
321
326
- // We'll hack the indent below, take this into account when formatting,
327
- let mut config = context. config . clone ( ) ;
328
- let new_width = config. max_width ( ) - indent. block_indent ( & config) . width ( ) ;
329
- config. set ( ) . max_width ( new_width) ;
330
- config. set ( ) . hide_parse_errors ( true ) ;
331
-
332
- // First try to format as items, then as statements.
333
- let new_body = match :: format_snippet ( & body_str, & config) {
334
- Some ( new_body) => new_body,
335
- None => match :: format_code_block ( & body_str, & config) {
336
- Some ( new_body) => new_body,
337
- None => return snippet,
338
- } ,
322
+ let branch_items = itemize_list (
323
+ context. codemap ,
324
+ parsed_def. branches . iter ( ) ,
325
+ "}" ,
326
+ ";" ,
327
+ |branch| branch. span . lo ( ) ,
328
+ |branch| branch. span . hi ( ) ,
329
+ |branch| branch. rewrite ( context, arm_shape, multi_branch_style) ,
330
+ context. codemap . span_after ( span, "{" ) ,
331
+ span. hi ( ) ,
332
+ false ,
333
+ ) . collect :: < Vec < _ > > ( ) ;
334
+
335
+ let fmt = ListFormatting {
336
+ tactic : DefinitiveListTactic :: Vertical ,
337
+ separator : if def. legacy { ";" } else { "" } ,
338
+ trailing_separator : SeparatorTactic :: Always ,
339
+ separator_place : SeparatorPlace :: Back ,
340
+ shape : arm_shape,
341
+ ends_with_newline : true ,
342
+ preserve_newline : true ,
343
+ config : context. config ,
339
344
} ;
340
345
341
- // Indent the body since it is in a block.
342
- let indent_str = indent. block_indent ( & config) . to_string ( & config) ;
343
- let mut new_body = new_body
344
- . lines ( )
345
- . map ( |l| {
346
- if l. is_empty ( ) {
347
- l. to_owned ( )
348
- } else {
349
- format ! ( "{}{}" , indent_str, l)
350
- }
351
- } )
352
- . collect :: < Vec < _ > > ( )
353
- . join ( "\n " ) ;
354
-
355
- // Undo our replacement of macro variables.
356
- // FIXME: this could be *much* more efficient.
357
- for ( old, new) in & substs {
358
- if old_body. find ( new) . is_some ( ) {
359
- debug ! (
360
- "rewrite_macro_def: bailing matching variable: `{}` in `{}`" ,
361
- new, ident
362
- ) ;
363
- return snippet;
364
- }
365
- new_body = new_body. replace ( new, old) ;
346
+ if multi_branch_style {
347
+ result += " {\n " ;
348
+ result += & arm_shape. indent . to_string ( context. config ) ;
366
349
}
367
350
368
- let result = format ! (
369
- "{}macro {}({}) {{\n {}\n {}}}" ,
370
- format_visibility( vis) ,
371
- ident,
372
- args_str,
373
- new_body,
374
- indent. to_string( context. config) ,
375
- ) ;
351
+ result += write_list ( & branch_items, & fmt) ?. as_str ( ) ;
352
+
353
+ if multi_branch_style {
354
+ result += "\n " ;
355
+ result += & indent. to_string ( context. config ) ;
356
+ result += "}" ;
357
+ }
376
358
377
359
Some ( result)
378
360
}
@@ -714,24 +696,34 @@ impl MacroParser {
714
696
715
697
// `(` ... `)` `=>` `{` ... `}`
716
698
fn parse_branch ( & mut self ) -> Option < MacroBranch > {
717
- let ( args_paren_kind, args) = match self . toks . next ( ) ? {
699
+ let tok = self . toks . next ( ) ?;
700
+ let ( lo, args_paren_kind) = match tok {
718
701
TokenTree :: Token ( ..) => return None ,
719
- TokenTree :: Delimited ( _ , ref d) => ( d . delim , d. tts . clone ( ) ) ,
702
+ TokenTree :: Delimited ( sp , ref d) => ( sp . lo ( ) , d. delim ) ,
720
703
} ;
704
+ let args = tok. joint ( ) . into ( ) ;
721
705
match self . toks . next ( ) ? {
722
706
TokenTree :: Token ( _, Token :: FatArrow ) => { }
723
707
_ => return None ,
724
708
}
725
- let body = match self . toks . next ( ) ? {
709
+ let ( mut hi , body) = match self . toks . next ( ) ? {
726
710
TokenTree :: Token ( ..) => return None ,
727
711
TokenTree :: Delimited ( sp, _) => {
728
712
let data = sp. data ( ) ;
729
- Span :: new ( data. lo + BytePos ( 1 ) , data. hi - BytePos ( 1 ) , data. ctxt )
713
+ (
714
+ data. hi ,
715
+ Span :: new ( data. lo + BytePos ( 1 ) , data. hi - BytePos ( 1 ) , data. ctxt ) ,
716
+ )
730
717
}
731
718
} ;
719
+ if let Some ( TokenTree :: Token ( sp, Token :: Semi ) ) = self . toks . look_ahead ( 0 ) {
720
+ self . toks . next ( ) ;
721
+ hi = sp. hi ( ) ;
722
+ }
732
723
Some ( MacroBranch {
733
- args ,
724
+ span : mk_sp ( lo , hi ) ,
734
725
args_paren_kind,
726
+ args,
735
727
body,
736
728
} )
737
729
}
@@ -745,11 +737,102 @@ struct Macro {
745
737
// FIXME: it would be more efficient to use references to the token streams
746
738
// rather than clone them, if we can make the borrowing work out.
747
739
struct MacroBranch {
748
- args : ThinTokenStream ,
740
+ span : Span ,
749
741
args_paren_kind : DelimToken ,
742
+ args : ThinTokenStream ,
750
743
body : Span ,
751
744
}
752
745
746
+ impl MacroBranch {
747
+ fn rewrite (
748
+ & self ,
749
+ context : & RewriteContext ,
750
+ shape : Shape ,
751
+ multi_branch_style : bool ,
752
+ ) -> Option < String > {
753
+ // Only attempt to format function-like macros.
754
+ if self . args_paren_kind != DelimToken :: Paren {
755
+ // FIXME(#1539): implement for non-sugared macros.
756
+ return None ;
757
+ }
758
+
759
+ let mut result = format_macro_args ( self . args . clone ( ) ) ?;
760
+
761
+ if multi_branch_style {
762
+ result += " =>" ;
763
+ }
764
+
765
+ // The macro body is the most interesting part. It might end up as various
766
+ // AST nodes, but also has special variables (e.g, `$foo`) which can't be
767
+ // parsed as regular Rust code (and note that these can be escaped using
768
+ // `$$`). We'll try and format like an AST node, but we'll substitute
769
+ // variables for new names with the same length first.
770
+
771
+ let old_body = context. snippet ( self . body ) . trim ( ) ;
772
+ let ( body_str, substs) = replace_names ( old_body) ?;
773
+
774
+ let mut config = context. config . clone ( ) ;
775
+ config. set ( ) . hide_parse_errors ( true ) ;
776
+
777
+ result += " {" ;
778
+
779
+ let has_block_body = old_body. starts_with ( '{' ) ;
780
+
781
+ let body_indent = if has_block_body {
782
+ shape. indent
783
+ } else {
784
+ // We'll hack the indent below, take this into account when formatting,
785
+ let body_indent = shape. indent . block_indent ( & config) ;
786
+ let new_width = config. max_width ( ) - body_indent. width ( ) ;
787
+ config. set ( ) . max_width ( new_width) ;
788
+ body_indent
789
+ } ;
790
+
791
+ // First try to format as items, then as statements.
792
+ let new_body = match :: format_snippet ( & body_str, & config) {
793
+ Some ( new_body) => new_body,
794
+ None => match :: format_code_block ( & body_str, & config) {
795
+ Some ( new_body) => new_body,
796
+ None => return None ,
797
+ } ,
798
+ } ;
799
+
800
+ // Indent the body since it is in a block.
801
+ let indent_str = body_indent. to_string ( & config) ;
802
+ let mut new_body = new_body
803
+ . trim_right ( )
804
+ . lines ( )
805
+ . fold ( String :: new ( ) , |mut s, l| {
806
+ if !l. is_empty ( ) {
807
+ s += & indent_str;
808
+ }
809
+ s + l + "\n "
810
+ } ) ;
811
+
812
+ // Undo our replacement of macro variables.
813
+ // FIXME: this could be *much* more efficient.
814
+ for ( old, new) in & substs {
815
+ if old_body. find ( new) . is_some ( ) {
816
+ debug ! ( "rewrite_macro_def: bailing matching variable: `{}`" , new) ;
817
+ return None ;
818
+ }
819
+ new_body = new_body. replace ( new, old) ;
820
+ }
821
+
822
+ if has_block_body {
823
+ result += new_body. trim ( ) ;
824
+ } else if !new_body. is_empty ( ) {
825
+ result += "\n " ;
826
+ result += & new_body;
827
+ result += & shape. indent . to_string ( & config) ;
828
+ }
829
+
830
+ result += "}" ;
831
+
832
+ Some ( result)
833
+ }
834
+ }
835
+
753
836
#[ cfg( test) ]
754
837
mod test {
755
838
use super :: * ;
0 commit comments