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