• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::algorithm::Printer;
2 use crate::path::PathKind;
3 use crate::token::Token;
4 use crate::INDENT;
5 use proc_macro2::{Delimiter, Spacing, TokenStream};
6 use syn::{Ident, Macro, MacroDelimiter};
7 
8 impl Printer {
mac(&mut self, mac: &Macro, ident: Option<&Ident>, semicolon: bool)9     pub fn mac(&mut self, mac: &Macro, ident: Option<&Ident>, semicolon: bool) {
10         if mac.path.is_ident("macro_rules") {
11             if let Some(ident) = ident {
12                 self.macro_rules(ident, &mac.tokens);
13                 return;
14             }
15         }
16         #[cfg(feature = "verbatim")]
17         if ident.is_none() && self.standard_library_macro(mac, semicolon) {
18             return;
19         }
20         self.path(&mac.path, PathKind::Simple);
21         self.word("!");
22         if let Some(ident) = ident {
23             self.nbsp();
24             self.ident(ident);
25         }
26         let (open, close, delimiter_break) = match mac.delimiter {
27             MacroDelimiter::Paren(_) => ("(", ")", Self::zerobreak as fn(&mut Self)),
28             MacroDelimiter::Brace(_) => (" {", "}", Self::hardbreak as fn(&mut Self)),
29             MacroDelimiter::Bracket(_) => ("[", "]", Self::zerobreak as fn(&mut Self)),
30         };
31         self.word(open);
32         if !mac.tokens.is_empty() {
33             self.cbox(INDENT);
34             delimiter_break(self);
35             self.ibox(0);
36             self.macro_rules_tokens(mac.tokens.clone(), false);
37             self.end();
38             delimiter_break(self);
39             self.offset(-INDENT);
40             self.end();
41         }
42         self.word(close);
43         if semicolon {
44             self.word(";");
45         }
46     }
47 
macro_rules(&mut self, name: &Ident, rules: &TokenStream)48     fn macro_rules(&mut self, name: &Ident, rules: &TokenStream) {
49         enum State {
50             Start,
51             Matcher,
52             Equal,
53             Greater,
54             Expander,
55         }
56 
57         use State::*;
58 
59         self.word("macro_rules! ");
60         self.ident(name);
61         self.word(" {");
62         self.cbox(INDENT);
63         self.hardbreak_if_nonempty();
64         let mut state = State::Start;
65         for tt in rules.clone() {
66             let token = Token::from(tt);
67             match (state, token) {
68                 (Start, Token::Group(delimiter, stream)) => {
69                     self.delimiter_open(delimiter);
70                     if !stream.is_empty() {
71                         self.cbox(INDENT);
72                         self.zerobreak();
73                         self.ibox(0);
74                         self.macro_rules_tokens(stream, true);
75                         self.end();
76                         self.zerobreak();
77                         self.offset(-INDENT);
78                         self.end();
79                     }
80                     self.delimiter_close(delimiter);
81                     state = Matcher;
82                 }
83                 (Matcher, Token::Punct('=', Spacing::Joint)) => {
84                     self.word(" =");
85                     state = Equal;
86                 }
87                 (Equal, Token::Punct('>', Spacing::Alone)) => {
88                     self.word(">");
89                     state = Greater;
90                 }
91                 (Greater, Token::Group(_delimiter, stream)) => {
92                     self.word(" {");
93                     self.neverbreak();
94                     if !stream.is_empty() {
95                         self.cbox(INDENT);
96                         self.hardbreak();
97                         self.ibox(0);
98                         self.macro_rules_tokens(stream, false);
99                         self.end();
100                         self.hardbreak();
101                         self.offset(-INDENT);
102                         self.end();
103                     }
104                     self.word("}");
105                     state = Expander;
106                 }
107                 (Expander, Token::Punct(';', Spacing::Alone)) => {
108                     self.word(";");
109                     self.hardbreak();
110                     state = Start;
111                 }
112                 _ => unimplemented!("bad macro_rules syntax"),
113             }
114         }
115         match state {
116             Start => {}
117             Expander => {
118                 self.word(";");
119                 self.hardbreak();
120             }
121             _ => self.hardbreak(),
122         }
123         self.offset(-INDENT);
124         self.end();
125         self.word("}");
126     }
127 
macro_rules_tokens(&mut self, stream: TokenStream, matcher: bool)128     pub fn macro_rules_tokens(&mut self, stream: TokenStream, matcher: bool) {
129         #[derive(PartialEq)]
130         enum State {
131             Start,
132             Dollar,
133             DollarIdent,
134             DollarIdentColon,
135             DollarParen,
136             DollarParenSep,
137             Pound,
138             PoundBang,
139             Dot,
140             Colon,
141             Colon2,
142             Ident,
143             IdentBang,
144             Delim,
145             Other,
146         }
147 
148         use State::*;
149 
150         let mut state = Start;
151         let mut previous_is_joint = true;
152         for tt in stream {
153             let token = Token::from(tt);
154             let (needs_space, next_state) = match (&state, &token) {
155                 (Dollar, Token::Ident(_)) => (false, if matcher { DollarIdent } else { Other }),
156                 (DollarIdent, Token::Punct(':', Spacing::Alone)) => (false, DollarIdentColon),
157                 (DollarIdentColon, Token::Ident(_)) => (false, Other),
158                 (DollarParen, Token::Punct('+' | '*' | '?', Spacing::Alone)) => (false, Other),
159                 (DollarParen, Token::Ident(_) | Token::Literal(_)) => (false, DollarParenSep),
160                 (DollarParen, Token::Punct(_, Spacing::Joint)) => (false, DollarParen),
161                 (DollarParen, Token::Punct(_, Spacing::Alone)) => (false, DollarParenSep),
162                 (DollarParenSep, Token::Punct('+' | '*', _)) => (false, Other),
163                 (Pound, Token::Punct('!', _)) => (false, PoundBang),
164                 (Dollar, Token::Group(Delimiter::Parenthesis, _)) => (false, DollarParen),
165                 (Pound | PoundBang, Token::Group(Delimiter::Bracket, _)) => (false, Other),
166                 (Ident, Token::Group(Delimiter::Parenthesis | Delimiter::Bracket, _)) => {
167                     (false, Delim)
168                 }
169                 (Ident, Token::Punct('!', Spacing::Alone)) => (false, IdentBang),
170                 (IdentBang, Token::Group(Delimiter::Parenthesis | Delimiter::Bracket, _)) => {
171                     (false, Other)
172                 }
173                 (Colon, Token::Punct(':', _)) => (false, Colon2),
174                 (_, Token::Group(Delimiter::Parenthesis | Delimiter::Bracket, _)) => (true, Delim),
175                 (_, Token::Group(Delimiter::Brace | Delimiter::None, _)) => (true, Other),
176                 (_, Token::Ident(ident)) if !is_keyword(ident) => {
177                     (state != Dot && state != Colon2, Ident)
178                 }
179                 (_, Token::Literal(lit)) if lit.to_string().ends_with('.') => (state != Dot, Other),
180                 (_, Token::Literal(_)) => (state != Dot, Ident),
181                 (_, Token::Punct(',' | ';', _)) => (false, Other),
182                 (_, Token::Punct('.', _)) if !matcher => (state != Ident && state != Delim, Dot),
183                 (_, Token::Punct(':', Spacing::Joint)) => (state != Ident, Colon),
184                 (_, Token::Punct('$', _)) => (true, Dollar),
185                 (_, Token::Punct('#', _)) => (true, Pound),
186                 (_, _) => (true, Other),
187             };
188             if !previous_is_joint {
189                 if needs_space {
190                     self.space();
191                 } else if let Token::Punct('.', _) = token {
192                     self.zerobreak();
193                 }
194             }
195             previous_is_joint = match token {
196                 Token::Punct(_, Spacing::Joint) | Token::Punct('$', _) => true,
197                 _ => false,
198             };
199             self.single_token(
200                 token,
201                 if matcher {
202                     |printer, stream| printer.macro_rules_tokens(stream, true)
203                 } else {
204                     |printer, stream| printer.macro_rules_tokens(stream, false)
205                 },
206             );
207             state = next_state;
208         }
209     }
210 }
211 
requires_semi(delimiter: &MacroDelimiter) -> bool212 pub(crate) fn requires_semi(delimiter: &MacroDelimiter) -> bool {
213     match delimiter {
214         MacroDelimiter::Paren(_) | MacroDelimiter::Bracket(_) => true,
215         MacroDelimiter::Brace(_) => false,
216     }
217 }
218 
is_keyword(ident: &Ident) -> bool219 fn is_keyword(ident: &Ident) -> bool {
220     match ident.to_string().as_str() {
221         "as" | "async" | "await" | "box" | "break" | "const" | "continue" | "crate" | "dyn"
222         | "else" | "enum" | "extern" | "fn" | "for" | "if" | "impl" | "in" | "let" | "loop"
223         | "macro" | "match" | "mod" | "move" | "mut" | "pub" | "ref" | "return" | "static"
224         | "struct" | "trait" | "type" | "unsafe" | "use" | "where" | "while" | "yield" => true,
225         _ => false,
226     }
227 }
228 
229 #[cfg(feature = "verbatim")]
230 mod standard_library {
231     use crate::algorithm::Printer;
232     use crate::expr;
233     use crate::fixup::FixupContext;
234     use crate::iter::IterDelimited;
235     use crate::path::PathKind;
236     use crate::INDENT;
237     use syn::ext::IdentExt;
238     use syn::parse::{Parse, ParseStream, Parser, Result};
239     use syn::punctuated::Punctuated;
240     use syn::{
241         parenthesized, token, Attribute, Expr, ExprAssign, ExprPath, Ident, Lit, Macro, Pat, Path,
242         Token, Type, Visibility,
243     };
244 
245     enum KnownMacro {
246         Expr(Expr),
247         Exprs(Vec<Expr>),
248         Cfg(Cfg),
249         Matches(Matches),
250         ThreadLocal(Vec<ThreadLocal>),
251         VecArray(Punctuated<Expr, Token![,]>),
252         VecRepeat { elem: Expr, n: Expr },
253     }
254 
255     enum Cfg {
256         Eq(Ident, Option<Lit>),
257         Call(Ident, Vec<Cfg>),
258     }
259 
260     struct Matches {
261         expression: Expr,
262         pattern: Pat,
263         guard: Option<Expr>,
264     }
265 
266     struct ThreadLocal {
267         attrs: Vec<Attribute>,
268         vis: Visibility,
269         name: Ident,
270         ty: Type,
271         init: Expr,
272     }
273 
274     struct FormatArgs {
275         format_string: Expr,
276         args: Vec<Expr>,
277     }
278 
279     impl Parse for FormatArgs {
parse(input: ParseStream) -> Result<Self>280         fn parse(input: ParseStream) -> Result<Self> {
281             let format_string: Expr = input.parse()?;
282 
283             let mut args = Vec::new();
284             while !input.is_empty() {
285                 input.parse::<Token![,]>()?;
286                 if input.is_empty() {
287                     break;
288                 }
289                 let arg = if input.peek(Ident::peek_any)
290                     && input.peek2(Token![=])
291                     && !input.peek2(Token![==])
292                 {
293                     let key = input.call(Ident::parse_any)?;
294                     let eq_token: Token![=] = input.parse()?;
295                     let value: Expr = input.parse()?;
296                     Expr::Assign(ExprAssign {
297                         attrs: Vec::new(),
298                         left: Box::new(Expr::Path(ExprPath {
299                             attrs: Vec::new(),
300                             qself: None,
301                             path: Path::from(key),
302                         })),
303                         eq_token,
304                         right: Box::new(value),
305                     })
306                 } else {
307                     input.parse()?
308                 };
309                 args.push(arg);
310             }
311 
312             Ok(FormatArgs {
313                 format_string,
314                 args,
315             })
316         }
317     }
318 
319     impl KnownMacro {
parse_expr(input: ParseStream) -> Result<Self>320         fn parse_expr(input: ParseStream) -> Result<Self> {
321             let expr: Expr = input.parse()?;
322             Ok(KnownMacro::Expr(expr))
323         }
324 
parse_expr_comma(input: ParseStream) -> Result<Self>325         fn parse_expr_comma(input: ParseStream) -> Result<Self> {
326             let expr: Expr = input.parse()?;
327             input.parse::<Option<Token![,]>>()?;
328             Ok(KnownMacro::Exprs(vec![expr]))
329         }
330 
parse_exprs(input: ParseStream) -> Result<Self>331         fn parse_exprs(input: ParseStream) -> Result<Self> {
332             let exprs = input.parse_terminated(Expr::parse, Token![,])?;
333             Ok(KnownMacro::Exprs(Vec::from_iter(exprs)))
334         }
335 
parse_assert(input: ParseStream) -> Result<Self>336         fn parse_assert(input: ParseStream) -> Result<Self> {
337             let mut exprs = Vec::new();
338             let cond: Expr = input.parse()?;
339             exprs.push(cond);
340             if input.parse::<Option<Token![,]>>()?.is_some() && !input.is_empty() {
341                 let format_args: FormatArgs = input.parse()?;
342                 exprs.push(format_args.format_string);
343                 exprs.extend(format_args.args);
344             }
345             Ok(KnownMacro::Exprs(exprs))
346         }
347 
parse_assert_cmp(input: ParseStream) -> Result<Self>348         fn parse_assert_cmp(input: ParseStream) -> Result<Self> {
349             let mut exprs = Vec::new();
350             let left: Expr = input.parse()?;
351             exprs.push(left);
352             input.parse::<Token![,]>()?;
353             let right: Expr = input.parse()?;
354             exprs.push(right);
355             if input.parse::<Option<Token![,]>>()?.is_some() && !input.is_empty() {
356                 let format_args: FormatArgs = input.parse()?;
357                 exprs.push(format_args.format_string);
358                 exprs.extend(format_args.args);
359             }
360             Ok(KnownMacro::Exprs(exprs))
361         }
362 
parse_cfg(input: ParseStream) -> Result<Self>363         fn parse_cfg(input: ParseStream) -> Result<Self> {
364             fn parse_single(input: ParseStream) -> Result<Cfg> {
365                 let ident: Ident = input.parse()?;
366                 if input.peek(token::Paren) && (ident == "all" || ident == "any") {
367                     let content;
368                     parenthesized!(content in input);
369                     let list = content.call(parse_multiple)?;
370                     Ok(Cfg::Call(ident, list))
371                 } else if input.peek(token::Paren) && ident == "not" {
372                     let content;
373                     parenthesized!(content in input);
374                     let cfg = content.call(parse_single)?;
375                     content.parse::<Option<Token![,]>>()?;
376                     Ok(Cfg::Call(ident, vec![cfg]))
377                 } else if input.peek(Token![=]) {
378                     input.parse::<Token![=]>()?;
379                     let string: Lit = input.parse()?;
380                     Ok(Cfg::Eq(ident, Some(string)))
381                 } else {
382                     Ok(Cfg::Eq(ident, None))
383                 }
384             }
385 
386             fn parse_multiple(input: ParseStream) -> Result<Vec<Cfg>> {
387                 let mut vec = Vec::new();
388                 while !input.is_empty() {
389                     let cfg = input.call(parse_single)?;
390                     vec.push(cfg);
391                     if input.is_empty() {
392                         break;
393                     }
394                     input.parse::<Token![,]>()?;
395                 }
396                 Ok(vec)
397             }
398 
399             let cfg = input.call(parse_single)?;
400             input.parse::<Option<Token![,]>>()?;
401             Ok(KnownMacro::Cfg(cfg))
402         }
403 
parse_env(input: ParseStream) -> Result<Self>404         fn parse_env(input: ParseStream) -> Result<Self> {
405             let mut exprs = Vec::new();
406             let name: Expr = input.parse()?;
407             exprs.push(name);
408             if input.parse::<Option<Token![,]>>()?.is_some() && !input.is_empty() {
409                 let error_msg: Expr = input.parse()?;
410                 exprs.push(error_msg);
411                 input.parse::<Option<Token![,]>>()?;
412             }
413             Ok(KnownMacro::Exprs(exprs))
414         }
415 
parse_format_args(input: ParseStream) -> Result<Self>416         fn parse_format_args(input: ParseStream) -> Result<Self> {
417             let format_args: FormatArgs = input.parse()?;
418             let mut exprs = format_args.args;
419             exprs.insert(0, format_args.format_string);
420             Ok(KnownMacro::Exprs(exprs))
421         }
422 
parse_matches(input: ParseStream) -> Result<Self>423         fn parse_matches(input: ParseStream) -> Result<Self> {
424             let expression: Expr = input.parse()?;
425             input.parse::<Token![,]>()?;
426             let pattern = input.call(Pat::parse_multi_with_leading_vert)?;
427             let guard = if input.parse::<Option<Token![if]>>()?.is_some() {
428                 Some(input.parse()?)
429             } else {
430                 None
431             };
432             input.parse::<Option<Token![,]>>()?;
433             Ok(KnownMacro::Matches(Matches {
434                 expression,
435                 pattern,
436                 guard,
437             }))
438         }
439 
parse_thread_local(input: ParseStream) -> Result<Self>440         fn parse_thread_local(input: ParseStream) -> Result<Self> {
441             let mut items = Vec::new();
442             while !input.is_empty() {
443                 let attrs = input.call(Attribute::parse_outer)?;
444                 let vis: Visibility = input.parse()?;
445                 input.parse::<Token![static]>()?;
446                 let name: Ident = input.parse()?;
447                 input.parse::<Token![:]>()?;
448                 let ty: Type = input.parse()?;
449                 input.parse::<Token![=]>()?;
450                 let init: Expr = input.parse()?;
451                 if input.is_empty() {
452                     break;
453                 }
454                 input.parse::<Token![;]>()?;
455                 items.push(ThreadLocal {
456                     attrs,
457                     vis,
458                     name,
459                     ty,
460                     init,
461                 });
462             }
463             Ok(KnownMacro::ThreadLocal(items))
464         }
465 
parse_vec(input: ParseStream) -> Result<Self>466         fn parse_vec(input: ParseStream) -> Result<Self> {
467             if input.is_empty() {
468                 return Ok(KnownMacro::VecArray(Punctuated::new()));
469             }
470             let first: Expr = input.parse()?;
471             if input.parse::<Option<Token![;]>>()?.is_some() {
472                 let len: Expr = input.parse()?;
473                 Ok(KnownMacro::VecRepeat {
474                     elem: first,
475                     n: len,
476                 })
477             } else {
478                 let mut vec = Punctuated::new();
479                 vec.push_value(first);
480                 while !input.is_empty() {
481                     let comma: Token![,] = input.parse()?;
482                     vec.push_punct(comma);
483                     if input.is_empty() {
484                         break;
485                     }
486                     let next: Expr = input.parse()?;
487                     vec.push_value(next);
488                 }
489                 Ok(KnownMacro::VecArray(vec))
490             }
491         }
492 
parse_write(input: ParseStream) -> Result<Self>493         fn parse_write(input: ParseStream) -> Result<Self> {
494             let mut exprs = Vec::new();
495             let dst: Expr = input.parse()?;
496             exprs.push(dst);
497             input.parse::<Token![,]>()?;
498             let format_args: FormatArgs = input.parse()?;
499             exprs.push(format_args.format_string);
500             exprs.extend(format_args.args);
501             Ok(KnownMacro::Exprs(exprs))
502         }
503 
parse_writeln(input: ParseStream) -> Result<Self>504         fn parse_writeln(input: ParseStream) -> Result<Self> {
505             let mut exprs = Vec::new();
506             let dst: Expr = input.parse()?;
507             exprs.push(dst);
508             if input.parse::<Option<Token![,]>>()?.is_some() && !input.is_empty() {
509                 let format_args: FormatArgs = input.parse()?;
510                 exprs.push(format_args.format_string);
511                 exprs.extend(format_args.args);
512             }
513             Ok(KnownMacro::Exprs(exprs))
514         }
515     }
516 
517     impl Printer {
standard_library_macro(&mut self, mac: &Macro, mut semicolon: bool) -> bool518         pub fn standard_library_macro(&mut self, mac: &Macro, mut semicolon: bool) -> bool {
519             let name = mac.path.segments.last().unwrap().ident.to_string();
520             let parser = match name.as_str() {
521                 "addr_of" | "addr_of_mut" => KnownMacro::parse_expr,
522                 "assert" | "debug_assert" => KnownMacro::parse_assert,
523                 "assert_eq" | "assert_ne" | "debug_assert_eq" | "debug_assert_ne" => {
524                     KnownMacro::parse_assert_cmp
525                 }
526                 "cfg" => KnownMacro::parse_cfg,
527                 "compile_error" | "include" | "include_bytes" | "include_str" | "option_env" => {
528                     KnownMacro::parse_expr_comma
529                 }
530                 "concat" | "concat_bytes" | "dbg" => KnownMacro::parse_exprs,
531                 "const_format_args" | "eprint" | "eprintln" | "format" | "format_args"
532                 | "format_args_nl" | "panic" | "print" | "println" | "todo" | "unimplemented"
533                 | "unreachable" => KnownMacro::parse_format_args,
534                 "env" => KnownMacro::parse_env,
535                 "matches" => KnownMacro::parse_matches,
536                 "thread_local" => KnownMacro::parse_thread_local,
537                 "vec" => KnownMacro::parse_vec,
538                 "write" => KnownMacro::parse_write,
539                 "writeln" => KnownMacro::parse_writeln,
540                 _ => return false,
541             };
542 
543             let known_macro = match parser.parse2(mac.tokens.clone()) {
544                 Ok(known_macro) => known_macro,
545                 Err(_) => return false,
546             };
547 
548             self.path(&mac.path, PathKind::Simple);
549             self.word("!");
550 
551             match &known_macro {
552                 KnownMacro::Expr(expr) => {
553                     self.word("(");
554                     self.cbox(INDENT);
555                     self.zerobreak();
556                     self.expr(expr, FixupContext::NONE);
557                     self.zerobreak();
558                     self.offset(-INDENT);
559                     self.end();
560                     self.word(")");
561                 }
562                 KnownMacro::Exprs(exprs) => {
563                     self.word("(");
564                     self.cbox(INDENT);
565                     self.zerobreak();
566                     for elem in exprs.iter().delimited() {
567                         self.expr(&elem, FixupContext::NONE);
568                         self.trailing_comma(elem.is_last);
569                     }
570                     self.offset(-INDENT);
571                     self.end();
572                     self.word(")");
573                 }
574                 KnownMacro::Cfg(cfg) => {
575                     self.word("(");
576                     self.cfg(cfg);
577                     self.word(")");
578                 }
579                 KnownMacro::Matches(matches) => {
580                     self.word("(");
581                     self.cbox(INDENT);
582                     self.zerobreak();
583                     self.expr(&matches.expression, FixupContext::NONE);
584                     self.word(",");
585                     self.space();
586                     self.pat(&matches.pattern);
587                     if let Some(guard) = &matches.guard {
588                         self.space();
589                         self.word("if ");
590                         self.expr(guard, FixupContext::NONE);
591                     }
592                     self.zerobreak();
593                     self.offset(-INDENT);
594                     self.end();
595                     self.word(")");
596                 }
597                 KnownMacro::ThreadLocal(items) => {
598                     self.word(" {");
599                     self.cbox(INDENT);
600                     self.hardbreak_if_nonempty();
601                     for item in items {
602                         self.outer_attrs(&item.attrs);
603                         self.cbox(0);
604                         self.visibility(&item.vis);
605                         self.word("static ");
606                         self.ident(&item.name);
607                         self.word(": ");
608                         self.ty(&item.ty);
609                         self.word(" = ");
610                         self.neverbreak();
611                         self.expr(&item.init, FixupContext::NONE);
612                         self.word(";");
613                         self.end();
614                         self.hardbreak();
615                     }
616                     self.offset(-INDENT);
617                     self.end();
618                     self.word("}");
619                     semicolon = false;
620                 }
621                 KnownMacro::VecArray(vec) => {
622                     if vec.is_empty() {
623                         self.word("[]");
624                     } else if expr::simple_array(vec) {
625                         self.cbox(INDENT);
626                         self.word("[");
627                         self.zerobreak();
628                         self.ibox(0);
629                         for elem in vec.iter().delimited() {
630                             self.expr(&elem, FixupContext::NONE);
631                             if !elem.is_last {
632                                 self.word(",");
633                                 self.space();
634                             }
635                         }
636                         self.end();
637                         self.trailing_comma(true);
638                         self.offset(-INDENT);
639                         self.word("]");
640                         self.end();
641                     } else {
642                         self.word("[");
643                         self.cbox(INDENT);
644                         self.zerobreak();
645                         for elem in vec.iter().delimited() {
646                             self.expr(&elem, FixupContext::NONE);
647                             self.trailing_comma(elem.is_last);
648                         }
649                         self.offset(-INDENT);
650                         self.end();
651                         self.word("]");
652                     }
653                 }
654                 KnownMacro::VecRepeat { elem, n } => {
655                     self.word("[");
656                     self.cbox(INDENT);
657                     self.zerobreak();
658                     self.expr(elem, FixupContext::NONE);
659                     self.word(";");
660                     self.space();
661                     self.expr(n, FixupContext::NONE);
662                     self.zerobreak();
663                     self.offset(-INDENT);
664                     self.end();
665                     self.word("]");
666                 }
667             }
668 
669             if semicolon {
670                 self.word(";");
671             }
672 
673             true
674         }
675 
cfg(&mut self, cfg: &Cfg)676         fn cfg(&mut self, cfg: &Cfg) {
677             match cfg {
678                 Cfg::Eq(ident, value) => {
679                     self.ident(ident);
680                     if let Some(value) = value {
681                         self.word(" = ");
682                         self.lit(value);
683                     }
684                 }
685                 Cfg::Call(ident, args) => {
686                     self.ident(ident);
687                     self.word("(");
688                     self.cbox(INDENT);
689                     self.zerobreak();
690                     for arg in args.iter().delimited() {
691                         self.cfg(&arg);
692                         self.trailing_comma(arg.is_last);
693                     }
694                     self.offset(-INDENT);
695                     self.end();
696                     self.word(")");
697                 }
698             }
699         }
700     }
701 }
702