Skip to main content

a9_prettyplease/
mac.rs

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