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}