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                _ => 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(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
212pub(crate) fn requires_semi(delimiter: &MacroDelimiter) -> bool {
213    match delimiter {
214        MacroDelimiter::Paren(_) | MacroDelimiter::Bracket(_) => true,
215        MacroDelimiter::Brace(_) => false,
216    }
217}
218
219fn 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")]
230mod standard_library {
231    use crate::algorithm::Printer;
232    use crate::fixup::FixupContext;
233    use crate::iter::IterDelimited;
234    use crate::path::PathKind;
235    use crate::INDENT;
236    use syn::ext::IdentExt;
237    use syn::parse::{Parse, ParseStream, Parser, Result};
238    use syn::{
239        parenthesized, token, Attribute, Expr, ExprAssign, ExprPath, Ident, Lit, Macro, Pat, Path,
240        Token, Type, Visibility,
241    };
242
243    enum KnownMacro {
244        Expr(Expr),
245        Exprs(Vec<Expr>),
246        Cfg(Cfg),
247        Matches(Matches),
248        ThreadLocal(Vec<ThreadLocal>),
249        VecArray(Vec<Expr>),
250        VecRepeat { elem: Expr, n: Expr },
251    }
252
253    enum Cfg {
254        Eq(Ident, Option<Lit>),
255        Call(Ident, Vec<Cfg>),
256    }
257
258    struct Matches {
259        expression: Expr,
260        pattern: Pat,
261        guard: Option<Expr>,
262    }
263
264    struct ThreadLocal {
265        attrs: Vec<Attribute>,
266        vis: Visibility,
267        name: Ident,
268        ty: Type,
269        init: Expr,
270    }
271
272    struct FormatArgs {
273        format_string: Expr,
274        args: Vec<Expr>,
275    }
276
277    impl Parse for FormatArgs {
278        fn parse(input: ParseStream) -> Result<Self> {
279            let format_string: Expr = input.parse()?;
280
281            let mut args = Vec::new();
282            while !input.is_empty() {
283                input.parse::<Token![,]>()?;
284                if input.is_empty() {
285                    break;
286                }
287                let arg = if input.peek(Ident::peek_any)
288                    && input.peek2(Token![=])
289                    && !input.peek2(Token![==])
290                {
291                    let key = input.call(Ident::parse_any)?;
292                    let eq_token: Token![=] = input.parse()?;
293                    let value: Expr = input.parse()?;
294                    Expr::Assign(ExprAssign {
295                        attrs: Vec::new(),
296                        left: Box::new(Expr::Path(ExprPath {
297                            attrs: Vec::new(),
298                            qself: None,
299                            path: Path::from(key),
300                        })),
301                        eq_token,
302                        right: Box::new(value),
303                    })
304                } else {
305                    input.parse()?
306                };
307                args.push(arg);
308            }
309
310            Ok(FormatArgs {
311                format_string,
312                args,
313            })
314        }
315    }
316
317    impl KnownMacro {
318        fn parse_expr(input: ParseStream) -> Result<Self> {
319            let expr: Expr = input.parse()?;
320            Ok(KnownMacro::Expr(expr))
321        }
322
323        fn parse_expr_comma(input: ParseStream) -> Result<Self> {
324            let expr: Expr = input.parse()?;
325            input.parse::<Option<Token![,]>>()?;
326            Ok(KnownMacro::Exprs(vec![expr]))
327        }
328
329        fn parse_exprs(input: ParseStream) -> Result<Self> {
330            let exprs = input.parse_terminated(Expr::parse, Token![,])?;
331            Ok(KnownMacro::Exprs(Vec::from_iter(exprs)))
332        }
333
334        fn parse_assert(input: ParseStream) -> Result<Self> {
335            let mut exprs = Vec::new();
336            let cond: Expr = input.parse()?;
337            exprs.push(cond);
338            if input.parse::<Option<Token![,]>>()?.is_some() && !input.is_empty() {
339                let format_args: FormatArgs = input.parse()?;
340                exprs.push(format_args.format_string);
341                exprs.extend(format_args.args);
342            }
343            Ok(KnownMacro::Exprs(exprs))
344        }
345
346        fn parse_assert_cmp(input: ParseStream) -> Result<Self> {
347            let mut exprs = Vec::new();
348            let left: Expr = input.parse()?;
349            exprs.push(left);
350            input.parse::<Token![,]>()?;
351            let right: Expr = input.parse()?;
352            exprs.push(right);
353            if input.parse::<Option<Token![,]>>()?.is_some() && !input.is_empty() {
354                let format_args: FormatArgs = input.parse()?;
355                exprs.push(format_args.format_string);
356                exprs.extend(format_args.args);
357            }
358            Ok(KnownMacro::Exprs(exprs))
359        }
360
361        fn parse_cfg(input: ParseStream) -> Result<Self> {
362            fn parse_single(input: ParseStream) -> Result<Cfg> {
363                let ident: Ident = input.parse()?;
364                if input.peek(token::Paren) && (ident == "all" || ident == "any") {
365                    let content;
366                    parenthesized!(content in input);
367                    let list = content.call(parse_multiple)?;
368                    Ok(Cfg::Call(ident, list))
369                } else if input.peek(token::Paren) && ident == "not" {
370                    let content;
371                    parenthesized!(content in input);
372                    let cfg = content.call(parse_single)?;
373                    content.parse::<Option<Token![,]>>()?;
374                    Ok(Cfg::Call(ident, vec![cfg]))
375                } else if input.peek(Token![=]) {
376                    input.parse::<Token![=]>()?;
377                    let string: Lit = input.parse()?;
378                    Ok(Cfg::Eq(ident, Some(string)))
379                } else {
380                    Ok(Cfg::Eq(ident, None))
381                }
382            }
383
384            fn parse_multiple(input: ParseStream) -> Result<Vec<Cfg>> {
385                let mut vec = Vec::new();
386                while !input.is_empty() {
387                    let cfg = input.call(parse_single)?;
388                    vec.push(cfg);
389                    if input.is_empty() {
390                        break;
391                    }
392                    input.parse::<Token![,]>()?;
393                }
394                Ok(vec)
395            }
396
397            let cfg = input.call(parse_single)?;
398            input.parse::<Option<Token![,]>>()?;
399            Ok(KnownMacro::Cfg(cfg))
400        }
401
402        fn parse_env(input: ParseStream) -> Result<Self> {
403            let mut exprs = Vec::new();
404            let name: Expr = input.parse()?;
405            exprs.push(name);
406            if input.parse::<Option<Token![,]>>()?.is_some() && !input.is_empty() {
407                let error_msg: Expr = input.parse()?;
408                exprs.push(error_msg);
409                input.parse::<Option<Token![,]>>()?;
410            }
411            Ok(KnownMacro::Exprs(exprs))
412        }
413
414        fn parse_format_args(input: ParseStream) -> Result<Self> {
415            let format_args: FormatArgs = input.parse()?;
416            let mut exprs = format_args.args;
417            exprs.insert(0, format_args.format_string);
418            Ok(KnownMacro::Exprs(exprs))
419        }
420
421        fn parse_matches(input: ParseStream) -> Result<Self> {
422            let expression: Expr = input.parse()?;
423            input.parse::<Token![,]>()?;
424            let pattern = input.call(Pat::parse_multi_with_leading_vert)?;
425            let guard = if input.parse::<Option<Token![if]>>()?.is_some() {
426                Some(input.parse()?)
427            } else {
428                None
429            };
430            input.parse::<Option<Token![,]>>()?;
431            Ok(KnownMacro::Matches(Matches {
432                expression,
433                pattern,
434                guard,
435            }))
436        }
437
438        fn parse_thread_local(input: ParseStream) -> Result<Self> {
439            let mut items = Vec::new();
440            while !input.is_empty() {
441                let attrs = input.call(Attribute::parse_outer)?;
442                let vis: Visibility = input.parse()?;
443                input.parse::<Token![static]>()?;
444                let name: Ident = input.parse()?;
445                input.parse::<Token![:]>()?;
446                let ty: Type = input.parse()?;
447                input.parse::<Token![=]>()?;
448                let init: Expr = input.parse()?;
449                if input.is_empty() {
450                    break;
451                }
452                input.parse::<Token![;]>()?;
453                items.push(ThreadLocal {
454                    attrs,
455                    vis,
456                    name,
457                    ty,
458                    init,
459                });
460            }
461            Ok(KnownMacro::ThreadLocal(items))
462        }
463
464        fn parse_vec(input: ParseStream) -> Result<Self> {
465            if input.is_empty() {
466                return Ok(KnownMacro::VecArray(Vec::new()));
467            }
468            let first: Expr = input.parse()?;
469            if input.parse::<Option<Token![;]>>()?.is_some() {
470                let len: Expr = input.parse()?;
471                Ok(KnownMacro::VecRepeat {
472                    elem: first,
473                    n: len,
474                })
475            } else {
476                let mut vec = vec![first];
477                while !input.is_empty() {
478                    input.parse::<Token![,]>()?;
479                    if input.is_empty() {
480                        break;
481                    }
482                    let next: Expr = input.parse()?;
483                    vec.push(next);
484                }
485                Ok(KnownMacro::VecArray(vec))
486            }
487        }
488
489        fn parse_write(input: ParseStream) -> Result<Self> {
490            let mut exprs = Vec::new();
491            let dst: Expr = input.parse()?;
492            exprs.push(dst);
493            input.parse::<Token![,]>()?;
494            let format_args: FormatArgs = input.parse()?;
495            exprs.push(format_args.format_string);
496            exprs.extend(format_args.args);
497            Ok(KnownMacro::Exprs(exprs))
498        }
499
500        fn parse_writeln(input: ParseStream) -> Result<Self> {
501            let mut exprs = Vec::new();
502            let dst: Expr = input.parse()?;
503            exprs.push(dst);
504            if input.parse::<Option<Token![,]>>()?.is_some() && !input.is_empty() {
505                let format_args: FormatArgs = input.parse()?;
506                exprs.push(format_args.format_string);
507                exprs.extend(format_args.args);
508            }
509            Ok(KnownMacro::Exprs(exprs))
510        }
511    }
512
513    impl Printer {
514        pub fn standard_library_macro(&mut self, mac: &Macro, mut semicolon: bool) -> bool {
515            let name = mac.path.segments.last().unwrap().ident.to_string();
516            let parser = match name.as_str() {
517                "addr_of" | "addr_of_mut" => KnownMacro::parse_expr,
518                "assert" | "debug_assert" => KnownMacro::parse_assert,
519                "assert_eq" | "assert_ne" | "debug_assert_eq" | "debug_assert_ne" => {
520                    KnownMacro::parse_assert_cmp
521                }
522                "cfg" => KnownMacro::parse_cfg,
523                "compile_error" | "include" | "include_bytes" | "include_str" | "option_env" => {
524                    KnownMacro::parse_expr_comma
525                }
526                "concat" | "concat_bytes" | "dbg" => KnownMacro::parse_exprs,
527                "const_format_args" | "eprint" | "eprintln" | "format" | "format_args"
528                | "format_args_nl" | "panic" | "print" | "println" | "todo" | "unimplemented"
529                | "unreachable" => KnownMacro::parse_format_args,
530                "env" => KnownMacro::parse_env,
531                "matches" => KnownMacro::parse_matches,
532                "thread_local" => KnownMacro::parse_thread_local,
533                "vec" => KnownMacro::parse_vec,
534                "write" => KnownMacro::parse_write,
535                "writeln" => KnownMacro::parse_writeln,
536                _ => return false,
537            };
538
539            let known_macro = match parser.parse2(mac.tokens.clone()) {
540                Ok(known_macro) => known_macro,
541                Err(_) => return false,
542            };
543
544            self.path(&mac.path, PathKind::Simple);
545            self.word("!");
546
547            match &known_macro {
548                KnownMacro::Expr(expr) => {
549                    self.word("(");
550                    self.cbox(INDENT);
551                    self.zerobreak();
552                    self.expr(expr, FixupContext::NONE);
553                    self.zerobreak();
554                    self.offset(-INDENT);
555                    self.end();
556                    self.word(")");
557                }
558                KnownMacro::Exprs(exprs) => {
559                    self.word("(");
560                    self.cbox(INDENT);
561                    self.zerobreak();
562                    for elem in exprs.iter().delimited() {
563                        self.expr(&elem, FixupContext::NONE);
564                        self.trailing_comma(elem.is_last);
565                    }
566                    self.offset(-INDENT);
567                    self.end();
568                    self.word(")");
569                }
570                KnownMacro::Cfg(cfg) => {
571                    self.word("(");
572                    self.cfg(cfg);
573                    self.word(")");
574                }
575                KnownMacro::Matches(matches) => {
576                    self.word("(");
577                    self.cbox(INDENT);
578                    self.zerobreak();
579                    self.expr(&matches.expression, FixupContext::NONE);
580                    self.word(",");
581                    self.space();
582                    self.pat(&matches.pattern);
583                    if let Some(guard) = &matches.guard {
584                        self.space();
585                        self.word("if ");
586                        self.expr(guard, FixupContext::NONE);
587                    }
588                    self.zerobreak();
589                    self.offset(-INDENT);
590                    self.end();
591                    self.word(")");
592                }
593                KnownMacro::ThreadLocal(items) => {
594                    self.word(" {");
595                    self.cbox(INDENT);
596                    self.hardbreak_if_nonempty();
597                    for item in items {
598                        self.outer_attrs(&item.attrs);
599                        self.cbox(0);
600                        self.visibility(&item.vis);
601                        self.word("static ");
602                        self.ident(&item.name);
603                        self.word(": ");
604                        self.ty(&item.ty);
605                        self.word(" = ");
606                        self.neverbreak();
607                        self.expr(&item.init, FixupContext::NONE);
608                        self.word(";");
609                        self.end();
610                        self.hardbreak();
611                    }
612                    self.offset(-INDENT);
613                    self.end();
614                    self.word("}");
615                    semicolon = false;
616                }
617                KnownMacro::VecArray(vec) => {
618                    self.word("[");
619                    self.cbox(INDENT);
620                    self.zerobreak();
621                    for elem in vec.iter().delimited() {
622                        self.expr(&elem, FixupContext::NONE);
623                        self.trailing_comma(elem.is_last);
624                    }
625                    self.offset(-INDENT);
626                    self.end();
627                    self.word("]");
628                }
629                KnownMacro::VecRepeat { elem, n } => {
630                    self.word("[");
631                    self.cbox(INDENT);
632                    self.zerobreak();
633                    self.expr(elem, FixupContext::NONE);
634                    self.word(";");
635                    self.space();
636                    self.expr(n, FixupContext::NONE);
637                    self.zerobreak();
638                    self.offset(-INDENT);
639                    self.end();
640                    self.word("]");
641                }
642            }
643
644            if semicolon {
645                self.word(";");
646            }
647
648            true
649        }
650
651        fn cfg(&mut self, cfg: &Cfg) {
652            match cfg {
653                Cfg::Eq(ident, value) => {
654                    self.ident(ident);
655                    if let Some(value) = value {
656                        self.word(" = ");
657                        self.lit(value);
658                    }
659                }
660                Cfg::Call(ident, args) => {
661                    self.ident(ident);
662                    self.word("(");
663                    self.cbox(INDENT);
664                    self.zerobreak();
665                    for arg in args.iter().delimited() {
666                        self.cfg(&arg);
667                        self.trailing_comma(arg.is_last);
668                    }
669                    self.offset(-INDENT);
670                    self.end();
671                    self.word(")");
672                }
673            }
674        }
675    }
676}