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