]> git.lizzy.rs Git - rust.git/blob - src/librustc_expand/mbe/quoted.rs
Suggest defining type parameter when appropriate
[rust.git] / src / librustc_expand / mbe / quoted.rs
1 use crate::mbe::macro_parser;
2 use crate::mbe::{Delimited, KleeneOp, KleeneToken, SequenceRepetition, TokenTree};
3
4 use rustc_span::symbol::kw;
5 use syntax::ast;
6 use syntax::print::pprust;
7 use syntax::sess::ParseSess;
8 use syntax::token::{self, Token};
9 use syntax::tokenstream;
10
11 use rustc_span::Span;
12
13 use rustc_data_structures::sync::Lrc;
14
15 /// Takes a `tokenstream::TokenStream` and returns a `Vec<self::TokenTree>`. Specifically, this
16 /// takes a generic `TokenStream`, such as is used in the rest of the compiler, and returns a
17 /// collection of `TokenTree` for use in parsing a macro.
18 ///
19 /// # Parameters
20 ///
21 /// - `input`: a token stream to read from, the contents of which we are parsing.
22 /// - `expect_matchers`: `parse` can be used to parse either the "patterns" or the "body" of a
23 ///   macro. Both take roughly the same form _except_ that in a pattern, metavars are declared with
24 ///   their "matcher" type. For example `$var:expr` or `$id:ident`. In this example, `expr` and
25 ///   `ident` are "matchers". They are not present in the body of a macro rule -- just in the
26 ///   pattern, so we pass a parameter to indicate whether to expect them or not.
27 /// - `sess`: the parsing session. Any errors will be emitted to this session.
28 /// - `features`, `attrs`: language feature flags and attributes so that we know whether to use
29 ///   unstable features or not.
30 /// - `edition`: which edition are we in.
31 /// - `macro_node_id`: the NodeId of the macro we are parsing.
32 ///
33 /// # Returns
34 ///
35 /// A collection of `self::TokenTree`. There may also be some errors emitted to `sess`.
36 pub(super) fn parse(
37     input: tokenstream::TokenStream,
38     expect_matchers: bool,
39     sess: &ParseSess,
40 ) -> Vec<TokenTree> {
41     // Will contain the final collection of `self::TokenTree`
42     let mut result = Vec::new();
43
44     // For each token tree in `input`, parse the token into a `self::TokenTree`, consuming
45     // additional trees if need be.
46     let mut trees = input.trees();
47     while let Some(tree) = trees.next() {
48         // Given the parsed tree, if there is a metavar and we are expecting matchers, actually
49         // parse out the matcher (i.e., in `$id:ident` this would parse the `:` and `ident`).
50         let tree = parse_tree(tree, &mut trees, expect_matchers, sess);
51         match tree {
52             TokenTree::MetaVar(start_sp, ident) if expect_matchers => {
53                 let span = match trees.next() {
54                     Some(tokenstream::TokenTree::Token(Token { kind: token::Colon, span })) => {
55                         match trees.next() {
56                             Some(tokenstream::TokenTree::Token(token)) => match token.ident() {
57                                 Some((kind, _)) => {
58                                     let span = token.span.with_lo(start_sp.lo());
59                                     result.push(TokenTree::MetaVarDecl(span, ident, kind));
60                                     continue;
61                                 }
62                                 _ => token.span,
63                             },
64                             tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span),
65                         }
66                     }
67                     tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(start_sp),
68                 };
69                 sess.missing_fragment_specifiers.borrow_mut().insert(span);
70                 result.push(TokenTree::MetaVarDecl(span, ident, ast::Ident::invalid()));
71             }
72
73             // Not a metavar or no matchers allowed, so just return the tree
74             _ => result.push(tree),
75         }
76     }
77     result
78 }
79
80 /// Takes a `tokenstream::TokenTree` and returns a `self::TokenTree`. Specifically, this takes a
81 /// generic `TokenTree`, such as is used in the rest of the compiler, and returns a `TokenTree`
82 /// for use in parsing a macro.
83 ///
84 /// Converting the given tree may involve reading more tokens.
85 ///
86 /// # Parameters
87 ///
88 /// - `tree`: the tree we wish to convert.
89 /// - `trees`: an iterator over trees. We may need to read more tokens from it in order to finish
90 ///   converting `tree`
91 /// - `expect_matchers`: same as for `parse` (see above).
92 /// - `sess`: the parsing session. Any errors will be emitted to this session.
93 /// - `features`, `attrs`: language feature flags and attributes so that we know whether to use
94 ///   unstable features or not.
95 fn parse_tree(
96     tree: tokenstream::TokenTree,
97     trees: &mut impl Iterator<Item = tokenstream::TokenTree>,
98     expect_matchers: bool,
99     sess: &ParseSess,
100 ) -> TokenTree {
101     // Depending on what `tree` is, we could be parsing different parts of a macro
102     match tree {
103         // `tree` is a `$` token. Look at the next token in `trees`
104         tokenstream::TokenTree::Token(Token { kind: token::Dollar, span }) => match trees.next() {
105             // `tree` is followed by a delimited set of token trees. This indicates the beginning
106             // of a repetition sequence in the macro (e.g. `$(pat)*`).
107             Some(tokenstream::TokenTree::Delimited(span, delim, tts)) => {
108                 // Must have `(` not `{` or `[`
109                 if delim != token::Paren {
110                     let tok = pprust::token_kind_to_string(&token::OpenDelim(delim));
111                     let msg = format!("expected `(`, found `{}`", tok);
112                     sess.span_diagnostic.span_err(span.entire(), &msg);
113                 }
114                 // Parse the contents of the sequence itself
115                 let sequence = parse(tts.into(), expect_matchers, sess);
116                 // Get the Kleene operator and optional separator
117                 let (separator, kleene) = parse_sep_and_kleene_op(trees, span.entire(), sess);
118                 // Count the number of captured "names" (i.e., named metavars)
119                 let name_captures = macro_parser::count_names(&sequence);
120                 TokenTree::Sequence(
121                     span,
122                     Lrc::new(SequenceRepetition {
123                         tts: sequence,
124                         separator,
125                         kleene,
126                         num_captures: name_captures,
127                     }),
128                 )
129             }
130
131             // `tree` is followed by an `ident`. This could be `$meta_var` or the `$crate` special
132             // metavariable that names the crate of the invocation.
133             Some(tokenstream::TokenTree::Token(token)) if token.is_ident() => {
134                 let (ident, is_raw) = token.ident().unwrap();
135                 let span = ident.span.with_lo(span.lo());
136                 if ident.name == kw::Crate && !is_raw {
137                     TokenTree::token(token::Ident(kw::DollarCrate, is_raw), span)
138                 } else {
139                     TokenTree::MetaVar(span, ident)
140                 }
141             }
142
143             // `tree` is followed by a random token. This is an error.
144             Some(tokenstream::TokenTree::Token(token)) => {
145                 let msg =
146                     format!("expected identifier, found `{}`", pprust::token_to_string(&token),);
147                 sess.span_diagnostic.span_err(token.span, &msg);
148                 TokenTree::MetaVar(token.span, ast::Ident::invalid())
149             }
150
151             // There are no more tokens. Just return the `$` we already have.
152             None => TokenTree::token(token::Dollar, span),
153         },
154
155         // `tree` is an arbitrary token. Keep it.
156         tokenstream::TokenTree::Token(token) => TokenTree::Token(token),
157
158         // `tree` is the beginning of a delimited set of tokens (e.g., `(` or `{`). We need to
159         // descend into the delimited set and further parse it.
160         tokenstream::TokenTree::Delimited(span, delim, tts) => TokenTree::Delimited(
161             span,
162             Lrc::new(Delimited { delim, tts: parse(tts.into(), expect_matchers, sess) }),
163         ),
164     }
165 }
166
167 /// Takes a token and returns `Some(KleeneOp)` if the token is `+` `*` or `?`. Otherwise, return
168 /// `None`.
169 fn kleene_op(token: &Token) -> Option<KleeneOp> {
170     match token.kind {
171         token::BinOp(token::Star) => Some(KleeneOp::ZeroOrMore),
172         token::BinOp(token::Plus) => Some(KleeneOp::OneOrMore),
173         token::Question => Some(KleeneOp::ZeroOrOne),
174         _ => None,
175     }
176 }
177
178 /// Parse the next token tree of the input looking for a KleeneOp. Returns
179 ///
180 /// - Ok(Ok((op, span))) if the next token tree is a KleeneOp
181 /// - Ok(Err(tok, span)) if the next token tree is a token but not a KleeneOp
182 /// - Err(span) if the next token tree is not a token
183 fn parse_kleene_op(
184     input: &mut impl Iterator<Item = tokenstream::TokenTree>,
185     span: Span,
186 ) -> Result<Result<(KleeneOp, Span), Token>, Span> {
187     match input.next() {
188         Some(tokenstream::TokenTree::Token(token)) => match kleene_op(&token) {
189             Some(op) => Ok(Ok((op, token.span))),
190             None => Ok(Err(token)),
191         },
192         tree => Err(tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span)),
193     }
194 }
195
196 /// Attempt to parse a single Kleene star, possibly with a separator.
197 ///
198 /// For example, in a pattern such as `$(a),*`, `a` is the pattern to be repeated, `,` is the
199 /// separator, and `*` is the Kleene operator. This function is specifically concerned with parsing
200 /// the last two tokens of such a pattern: namely, the optional separator and the Kleene operator
201 /// itself. Note that here we are parsing the _macro_ itself, rather than trying to match some
202 /// stream of tokens in an invocation of a macro.
203 ///
204 /// This function will take some input iterator `input` corresponding to `span` and a parsing
205 /// session `sess`. If the next one (or possibly two) tokens in `input` correspond to a Kleene
206 /// operator and separator, then a tuple with `(separator, KleeneOp)` is returned. Otherwise, an
207 /// error with the appropriate span is emitted to `sess` and a dummy value is returned.
208 fn parse_sep_and_kleene_op(
209     input: &mut impl Iterator<Item = tokenstream::TokenTree>,
210     span: Span,
211     sess: &ParseSess,
212 ) -> (Option<Token>, KleeneToken) {
213     // We basically look at two token trees here, denoted as #1 and #2 below
214     let span = match parse_kleene_op(input, span) {
215         // #1 is a `?`, `+`, or `*` KleeneOp
216         Ok(Ok((op, span))) => return (None, KleeneToken::new(op, span)),
217
218         // #1 is a separator followed by #2, a KleeneOp
219         Ok(Err(token)) => match parse_kleene_op(input, token.span) {
220             // #2 is the `?` Kleene op, which does not take a separator (error)
221             Ok(Ok((KleeneOp::ZeroOrOne, span))) => {
222                 // Error!
223                 sess.span_diagnostic.span_err(
224                     token.span,
225                     "the `?` macro repetition operator does not take a separator",
226                 );
227
228                 // Return a dummy
229                 return (None, KleeneToken::new(KleeneOp::ZeroOrMore, span));
230             }
231
232             // #2 is a KleeneOp :D
233             Ok(Ok((op, span))) => return (Some(token), KleeneToken::new(op, span)),
234
235             // #2 is a random token or not a token at all :(
236             Ok(Err(Token { span, .. })) | Err(span) => span,
237         },
238
239         // #1 is not a token
240         Err(span) => span,
241     };
242
243     // If we ever get to this point, we have experienced an "unexpected token" error
244     sess.span_diagnostic.span_err(span, "expected one of: `*`, `+`, or `?`");
245
246     // Return a dummy
247     (None, KleeneToken::new(KleeneOp::ZeroOrMore, span))
248 }