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