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