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