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}