1 use rustc_ast::token::{Delimiter, TokenKind};
2 use rustc_ast::tokenstream::TokenStream;
3 use rustc_ast::{ast, ptr};
4 use rustc_parse::parser::{ForceCollect, Parser};
5 use rustc_parse::{stream_to_parser, MACRO_ARGUMENTS};
6 use rustc_session::parse::ParseSess;
7 use rustc_span::symbol::{self, kw};
8 use rustc_span::Symbol;
9
10 use crate::macros::MacroArg;
11 use crate::rewrite::RewriteContext;
12
13 pub(crate) mod asm;
14 pub(crate) mod cfg_if;
15 pub(crate) mod lazy_static;
16
build_stream_parser<'a>(sess: &'a ParseSess, tokens: TokenStream) -> Parser<'a>17 fn build_stream_parser<'a>(sess: &'a ParseSess, tokens: TokenStream) -> Parser<'a> {
18 stream_to_parser(sess, tokens, MACRO_ARGUMENTS)
19 }
20
build_parser<'a>(context: &RewriteContext<'a>, tokens: TokenStream) -> Parser<'a>21 fn build_parser<'a>(context: &RewriteContext<'a>, tokens: TokenStream) -> Parser<'a> {
22 build_stream_parser(context.parse_sess.inner(), tokens)
23 }
24
parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg>25 fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
26 macro_rules! parse_macro_arg {
27 ($macro_arg:ident, $parser:expr, $f:expr) => {
28 let mut cloned_parser = (*parser).clone();
29 match $parser(&mut cloned_parser) {
30 Ok(x) => {
31 if parser.sess.span_diagnostic.has_errors().is_some() {
32 parser.sess.span_diagnostic.reset_err_count();
33 } else {
34 // Parsing succeeded.
35 *parser = cloned_parser;
36 return Some(MacroArg::$macro_arg($f(x)?));
37 }
38 }
39 Err(e) => {
40 e.cancel();
41 parser.sess.span_diagnostic.reset_err_count();
42 }
43 }
44 };
45 }
46
47 parse_macro_arg!(
48 Expr,
49 |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_expr(),
50 |x: ptr::P<ast::Expr>| Some(x)
51 );
52 parse_macro_arg!(
53 Ty,
54 |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_ty(),
55 |x: ptr::P<ast::Ty>| Some(x)
56 );
57 parse_macro_arg!(
58 Pat,
59 |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_pat_no_top_alt(None),
60 |x: ptr::P<ast::Pat>| Some(x)
61 );
62 // `parse_item` returns `Option<ptr::P<ast::Item>>`.
63 parse_macro_arg!(
64 Item,
65 |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_item(ForceCollect::No),
66 |x: Option<ptr::P<ast::Item>>| x
67 );
68
69 None
70 }
71
72 pub(crate) struct ParsedMacroArgs {
73 pub(crate) vec_with_semi: bool,
74 pub(crate) trailing_comma: bool,
75 pub(crate) args: Vec<MacroArg>,
76 }
77
check_keyword<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg>78 fn check_keyword<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
79 for &keyword in RUST_KW.iter() {
80 if parser.token.is_keyword(keyword)
81 && parser.look_ahead(1, |t| {
82 t.kind == TokenKind::Eof || t.kind == TokenKind::Comma
83 })
84 {
85 parser.bump();
86 return Some(MacroArg::Keyword(
87 symbol::Ident::with_dummy_span(keyword),
88 parser.prev_token.span,
89 ));
90 }
91 }
92 None
93 }
94
parse_macro_args( context: &RewriteContext<'_>, tokens: TokenStream, style: Delimiter, forced_bracket: bool, ) -> Option<ParsedMacroArgs>95 pub(crate) fn parse_macro_args(
96 context: &RewriteContext<'_>,
97 tokens: TokenStream,
98 style: Delimiter,
99 forced_bracket: bool,
100 ) -> Option<ParsedMacroArgs> {
101 let mut parser = build_parser(context, tokens);
102 let mut args = Vec::new();
103 let mut vec_with_semi = false;
104 let mut trailing_comma = false;
105
106 if Delimiter::Brace != style {
107 loop {
108 if let Some(arg) = check_keyword(&mut parser) {
109 args.push(arg);
110 } else if let Some(arg) = parse_macro_arg(&mut parser) {
111 args.push(arg);
112 } else {
113 return None;
114 }
115
116 match parser.token.kind {
117 TokenKind::Eof => break,
118 TokenKind::Comma => (),
119 TokenKind::Semi => {
120 // Try to parse `vec![expr; expr]`
121 if forced_bracket {
122 parser.bump();
123 if parser.token.kind != TokenKind::Eof {
124 match parse_macro_arg(&mut parser) {
125 Some(arg) => {
126 args.push(arg);
127 parser.bump();
128 if parser.token.kind == TokenKind::Eof && args.len() == 2 {
129 vec_with_semi = true;
130 break;
131 }
132 }
133 None => {
134 return None;
135 }
136 }
137 }
138 }
139 return None;
140 }
141 _ if args.last().map_or(false, MacroArg::is_item) => continue,
142 _ => return None,
143 }
144
145 parser.bump();
146
147 if parser.token.kind == TokenKind::Eof {
148 trailing_comma = true;
149 break;
150 }
151 }
152 }
153
154 Some(ParsedMacroArgs {
155 vec_with_semi,
156 trailing_comma,
157 args,
158 })
159 }
160
parse_expr( context: &RewriteContext<'_>, tokens: TokenStream, ) -> Option<ptr::P<ast::Expr>>161 pub(crate) fn parse_expr(
162 context: &RewriteContext<'_>,
163 tokens: TokenStream,
164 ) -> Option<ptr::P<ast::Expr>> {
165 let mut parser = build_parser(context, tokens);
166 parser.parse_expr().ok()
167 }
168
169 const RUST_KW: [Symbol; 59] = [
170 kw::PathRoot,
171 kw::DollarCrate,
172 kw::Underscore,
173 kw::As,
174 kw::Box,
175 kw::Break,
176 kw::Const,
177 kw::Continue,
178 kw::Crate,
179 kw::Else,
180 kw::Enum,
181 kw::Extern,
182 kw::False,
183 kw::Fn,
184 kw::For,
185 kw::If,
186 kw::Impl,
187 kw::In,
188 kw::Let,
189 kw::Loop,
190 kw::Match,
191 kw::Mod,
192 kw::Move,
193 kw::Mut,
194 kw::Pub,
195 kw::Ref,
196 kw::Return,
197 kw::SelfLower,
198 kw::SelfUpper,
199 kw::Static,
200 kw::Struct,
201 kw::Super,
202 kw::Trait,
203 kw::True,
204 kw::Type,
205 kw::Unsafe,
206 kw::Use,
207 kw::Where,
208 kw::While,
209 kw::Abstract,
210 kw::Become,
211 kw::Do,
212 kw::Final,
213 kw::Macro,
214 kw::Override,
215 kw::Priv,
216 kw::Typeof,
217 kw::Unsized,
218 kw::Virtual,
219 kw::Yield,
220 kw::Dyn,
221 kw::Async,
222 kw::Try,
223 kw::UnderscoreLifetime,
224 kw::StaticLifetime,
225 kw::Auto,
226 kw::Catch,
227 kw::Default,
228 kw::Union,
229 ];
230