rustfmt_nightly/parse/macros/
mod.rs
1use rustc_ast::token::{Delimiter, NonterminalKind, NtExprKind::*, NtPatKind::*, TokenKind};
2use rustc_ast::tokenstream::TokenStream;
3use rustc_ast::{ast, ptr};
4use rustc_parse::MACRO_ARGUMENTS;
5use rustc_parse::parser::{ForceCollect, Parser, Recovery};
6use rustc_session::parse::ParseSess;
7use rustc_span::symbol;
8
9use crate::macros::MacroArg;
10use crate::rewrite::RewriteContext;
11
12pub(crate) mod asm;
13pub(crate) mod cfg_if;
14pub(crate) mod lazy_static;
15
16fn build_stream_parser<'a>(psess: &'a ParseSess, tokens: TokenStream) -> Parser<'a> {
17 Parser::new(psess, tokens, MACRO_ARGUMENTS).recovery(Recovery::Forbidden)
18}
19
20fn build_parser<'a>(context: &RewriteContext<'a>, tokens: TokenStream) -> Parser<'a> {
21 build_stream_parser(context.psess.inner(), tokens)
22}
23
24fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
25 macro_rules! parse_macro_arg {
26 ($macro_arg:ident, $nt_kind:expr, $try_parse:expr, $then:expr) => {
27 let mut cloned_parser = (*parser).clone();
28 if Parser::nonterminal_may_begin_with($nt_kind, &cloned_parser.token) {
29 match $try_parse(&mut cloned_parser) {
30 Ok(x) => {
31 if parser.psess.dcx().has_errors().is_some() {
32 parser.psess.dcx().reset_err_count();
33 } else {
34 *parser = cloned_parser;
36 return Some(MacroArg::$macro_arg($then(x)?));
37 }
38 }
39 Err(e) => {
40 e.cancel();
41 parser.psess.dcx().reset_err_count();
42 }
43 }
44 }
45 };
46 }
47
48 parse_macro_arg!(
49 Expr,
50 NonterminalKind::Expr(Expr),
51 |parser: &mut Parser<'b>| parser.parse_expr(),
52 |x: ptr::P<ast::Expr>| Some(x)
53 );
54 parse_macro_arg!(
55 Ty,
56 NonterminalKind::Ty,
57 |parser: &mut Parser<'b>| parser.parse_ty(),
58 |x: ptr::P<ast::Ty>| Some(x)
59 );
60 parse_macro_arg!(
61 Pat,
62 NonterminalKind::Pat(PatParam { inferred: false }),
63 |parser: &mut Parser<'b>| parser.parse_pat_no_top_alt(None, None),
64 |x: ptr::P<ast::Pat>| Some(x)
65 );
66 parse_macro_arg!(
68 Item,
69 NonterminalKind::Item,
70 |parser: &mut Parser<'b>| parser.parse_item(ForceCollect::No),
71 |x: Option<ptr::P<ast::Item>>| x
72 );
73
74 None
75}
76
77pub(crate) struct ParsedMacroArgs {
78 pub(crate) vec_with_semi: bool,
79 pub(crate) trailing_comma: bool,
80 pub(crate) args: Vec<MacroArg>,
81}
82
83fn check_keyword<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
84 if parser.token.is_any_keyword()
85 && parser.look_ahead(1, |t| *t == TokenKind::Eof || *t == TokenKind::Comma)
86 {
87 let keyword = parser.token.ident().unwrap().0.name;
88 parser.bump();
89 Some(MacroArg::Keyword(
90 symbol::Ident::with_dummy_span(keyword),
91 parser.prev_token.span,
92 ))
93 } else {
94 None
95 }
96}
97
98pub(crate) fn parse_macro_args(
99 context: &RewriteContext<'_>,
100 tokens: TokenStream,
101 style: Delimiter,
102 forced_bracket: bool,
103) -> Option<ParsedMacroArgs> {
104 let mut parser = build_parser(context, tokens);
105 let mut args = Vec::new();
106 let mut vec_with_semi = false;
107 let mut trailing_comma = false;
108
109 if Delimiter::Brace != style {
110 loop {
111 if let Some(arg) = check_keyword(&mut parser) {
112 args.push(arg);
113 } else if let Some(arg) = parse_macro_arg(&mut parser) {
114 args.push(arg);
115 } else {
116 return None;
117 }
118
119 match parser.token.kind {
120 TokenKind::Eof => break,
121 TokenKind::Comma => (),
122 TokenKind::Semi => {
123 if forced_bracket {
125 parser.bump();
126 if parser.token.kind != TokenKind::Eof {
127 match parse_macro_arg(&mut parser) {
128 Some(arg) => {
129 args.push(arg);
130 parser.bump();
131 if parser.token == TokenKind::Eof && args.len() == 2 {
132 vec_with_semi = true;
133 break;
134 }
135 }
136 None => {
137 return None;
138 }
139 }
140 }
141 }
142 return None;
143 }
144 _ if args.last().map_or(false, MacroArg::is_item) => continue,
145 _ => return None,
146 }
147
148 parser.bump();
149
150 if parser.token == TokenKind::Eof {
151 trailing_comma = true;
152 break;
153 }
154 }
155 }
156
157 Some(ParsedMacroArgs {
158 vec_with_semi,
159 trailing_comma,
160 args,
161 })
162}
163
164pub(crate) fn parse_expr(
165 context: &RewriteContext<'_>,
166 tokens: TokenStream,
167) -> Option<ptr::P<ast::Expr>> {
168 let mut parser = build_parser(context, tokens);
169 parser.parse_expr().ok()
170}