• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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