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