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