]>
Commit | Line | Data |
---|---|---|
3dfed10e | 1 | use rustc_ast::ptr::P; |
04454e1e FG |
2 | use rustc_ast::token::{self, Delimiter, NonterminalKind, Token}; |
3 | use rustc_ast::HasTokens; | |
3dfed10e | 4 | use rustc_ast_pretty::pprust; |
9ffffee4 | 5 | use rustc_errors::IntoDiagnostic; |
3dfed10e XL |
6 | use rustc_errors::PResult; |
7 | use rustc_span::symbol::{kw, Ident}; | |
8 | ||
9ffffee4 | 9 | use crate::errors::UnexpectedNonterminal; |
5e7ed085 FG |
10 | use crate::parser::pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; |
11 | use crate::parser::{FollowedByType, ForceCollect, NtOrTt, Parser, PathStyle}; | |
3dfed10e XL |
12 | |
13 | impl<'a> Parser<'a> { | |
14 | /// Checks whether a non-terminal may begin with a particular token. | |
15 | /// | |
04454e1e FG |
16 | /// Returning `false` is a *stability guarantee* that such a matcher will *never* begin with |
17 | /// that token. Be conservative (return true) if not sure. Inlined because it has a single call | |
18 | /// site. | |
19 | #[inline] | |
5869c6ff | 20 | pub fn nonterminal_may_begin_with(kind: NonterminalKind, token: &Token) -> bool { |
3dfed10e XL |
21 | /// Checks whether the non-terminal may contain a single (non-keyword) identifier. |
22 | fn may_be_ident(nt: &token::Nonterminal) -> bool { | |
23 | match *nt { | |
24 | token::NtItem(_) | token::NtBlock(_) | token::NtVis(_) | token::NtLifetime(_) => { | |
25 | false | |
26 | } | |
27 | _ => true, | |
28 | } | |
29 | } | |
30 | ||
31 | match kind { | |
32 | NonterminalKind::Expr => { | |
33 | token.can_begin_expr() | |
34 | // This exception is here for backwards compatibility. | |
35 | && !token.is_keyword(kw::Let) | |
b9856134 XL |
36 | // This exception is here for backwards compatibility. |
37 | && !token.is_keyword(kw::Const) | |
3dfed10e XL |
38 | } |
39 | NonterminalKind::Ty => token.can_begin_type(), | |
40 | NonterminalKind::Ident => get_macro_ident(token).is_some(), | |
41 | NonterminalKind::Literal => token.can_begin_literal_maybe_minus(), | |
42 | NonterminalKind::Vis => match token.kind { | |
43 | // The follow-set of :vis + "priv" keyword + interpolated | |
44 | token::Comma | token::Ident(..) | token::Interpolated(..) => true, | |
45 | _ => token.can_begin_type(), | |
46 | }, | |
487cf647 | 47 | NonterminalKind::Block => match &token.kind { |
04454e1e | 48 | token::OpenDelim(Delimiter::Brace) => true, |
487cf647 | 49 | token::Interpolated(nt) => !matches!( |
5869c6ff XL |
50 | **nt, |
51 | token::NtItem(_) | |
52 | | token::NtPat(_) | |
53 | | token::NtTy(_) | |
54 | | token::NtIdent(..) | |
55 | | token::NtMeta(_) | |
56 | | token::NtPath(_) | |
57 | | token::NtVis(_) | |
58 | ), | |
3dfed10e XL |
59 | _ => false, |
60 | }, | |
487cf647 | 61 | NonterminalKind::Path | NonterminalKind::Meta => match &token.kind { |
3dfed10e | 62 | token::ModSep | token::Ident(..) => true, |
487cf647 | 63 | token::Interpolated(nt) => match **nt { |
3dfed10e XL |
64 | token::NtPath(_) | token::NtMeta(_) => true, |
65 | _ => may_be_ident(&nt), | |
66 | }, | |
67 | _ => false, | |
68 | }, | |
cdc7bbd5 | 69 | NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr { .. } => { |
487cf647 | 70 | match &token.kind { |
f2b60f7d FG |
71 | token::Ident(..) | // box, ref, mut, and other identifiers (can stricten) |
72 | token::OpenDelim(Delimiter::Parenthesis) | // tuple pattern | |
73 | token::OpenDelim(Delimiter::Bracket) | // slice pattern | |
74 | token::BinOp(token::And) | // reference | |
75 | token::BinOp(token::Minus) | // negative literal | |
76 | token::AndAnd | // double reference | |
77 | token::Literal(..) | // literal | |
78 | token::DotDot | // range pattern (future compat) | |
79 | token::DotDotDot | // range pattern (future compat) | |
80 | token::ModSep | // path | |
81 | token::Lt | // path (UFCS constant) | |
82 | token::BinOp(token::Shl) => true, // path (double UFCS) | |
fc512014 | 83 | // leading vert `|` or-pattern |
cdc7bbd5 | 84 | token::BinOp(token::Or) => matches!(kind, NonterminalKind::PatWithOr {..}), |
487cf647 | 85 | token::Interpolated(nt) => may_be_ident(nt), |
3dfed10e | 86 | _ => false, |
cdc7bbd5 XL |
87 | } |
88 | } | |
487cf647 | 89 | NonterminalKind::Lifetime => match &token.kind { |
3dfed10e | 90 | token::Lifetime(_) => true, |
487cf647 | 91 | token::Interpolated(nt) => { |
5e7ed085 | 92 | matches!(**nt, token::NtLifetime(_)) |
29967ef6 | 93 | } |
3dfed10e XL |
94 | _ => false, |
95 | }, | |
29967ef6 XL |
96 | NonterminalKind::TT | NonterminalKind::Item | NonterminalKind::Stmt => { |
97 | !matches!(token.kind, token::CloseDelim(_)) | |
98 | } | |
3dfed10e XL |
99 | } |
100 | } | |
101 | ||
04454e1e FG |
102 | /// Parse a non-terminal (e.g. MBE `:pat` or `:ident`). Inlined because there is only one call |
103 | /// site. | |
104 | #[inline] | |
5e7ed085 | 105 | pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, NtOrTt> { |
3dfed10e XL |
106 | // Any `Nonterminal` which stores its tokens (currently `NtItem` and `NtExpr`) |
107 | // needs to have them force-captured here. | |
108 | // A `macro_rules!` invocation may pass a captured item/expr to a proc-macro, | |
109 | // which requires having captured tokens available. Since we cannot determine | |
110 | // in advance whether or not a proc-macro will be (transitively) invoked, | |
111 | // we always capture tokens for any `Nonterminal` which needs them. | |
17df50a5 | 112 | let mut nt = match kind { |
5e7ed085 FG |
113 | // Note that TT is treated differently to all the others. |
114 | NonterminalKind::TT => return Ok(NtOrTt::Tt(self.parse_token_tree())), | |
5869c6ff XL |
115 | NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? { |
116 | Some(item) => token::NtItem(item), | |
117 | None => { | |
9ffffee4 FG |
118 | return Err(UnexpectedNonterminal::Item(self.token.span) |
119 | .into_diagnostic(&self.sess.span_diagnostic)); | |
3dfed10e XL |
120 | } |
121 | }, | |
1b1a35ee | 122 | NonterminalKind::Block => { |
6a06907d XL |
123 | // While a block *expression* may have attributes (e.g. `#[my_attr] { ... }`), |
124 | // the ':block' matcher does not support them | |
125 | token::NtBlock(self.collect_tokens_no_attrs(|this| this.parse_block())?) | |
1b1a35ee | 126 | } |
5869c6ff | 127 | NonterminalKind::Stmt => match self.parse_stmt(ForceCollect::Yes)? { |
04454e1e | 128 | Some(s) => token::NtStmt(P(s)), |
5869c6ff | 129 | None => { |
9ffffee4 FG |
130 | return Err(UnexpectedNonterminal::Statement(self.token.span) |
131 | .into_diagnostic(&self.sess.span_diagnostic)); | |
1b1a35ee | 132 | } |
5869c6ff | 133 | }, |
cdc7bbd5 | 134 | NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr { .. } => { |
6a06907d | 135 | token::NtPat(self.collect_tokens_no_attrs(|this| match kind { |
cdc7bbd5 | 136 | NonterminalKind::PatParam { .. } => this.parse_pat_no_top_alt(None), |
5e7ed085 FG |
137 | NonterminalKind::PatWithOr { .. } => this.parse_pat_allow_top_alt( |
138 | None, | |
139 | RecoverComma::No, | |
140 | RecoverColon::No, | |
141 | CommaRecoveryMode::EitherTupleOrPipe, | |
142 | ), | |
5869c6ff XL |
143 | _ => unreachable!(), |
144 | })?) | |
3dfed10e | 145 | } |
6a06907d | 146 | |
cdc7bbd5 | 147 | NonterminalKind::Expr => token::NtExpr(self.parse_expr_force_collect()?), |
1b1a35ee | 148 | NonterminalKind::Literal => { |
6a06907d XL |
149 | // The `:literal` matcher does not support attributes |
150 | token::NtLiteral( | |
151 | self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?, | |
152 | ) | |
153 | } | |
154 | ||
5e7ed085 FG |
155 | NonterminalKind::Ty => token::NtTy( |
156 | self.collect_tokens_no_attrs(|this| this.parse_no_question_mark_recover())?, | |
157 | ), | |
158 | ||
3dfed10e | 159 | // this could be handled like a token, since it is one |
94222f64 XL |
160 | NonterminalKind::Ident |
161 | if let Some((ident, is_raw)) = get_macro_ident(&self.token) => | |
162 | { | |
163 | self.bump(); | |
164 | token::NtIdent(ident, is_raw) | |
165 | } | |
3dfed10e | 166 | NonterminalKind::Ident => { |
9ffffee4 FG |
167 | return Err(UnexpectedNonterminal::Ident { |
168 | span: self.token.span, | |
169 | token: self.token.clone(), | |
170 | }.into_diagnostic(&self.sess.span_diagnostic)); | |
3dfed10e | 171 | } |
6a06907d | 172 | NonterminalKind::Path => token::NtPath( |
04454e1e | 173 | P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?), |
6a06907d | 174 | ), |
cdc7bbd5 | 175 | NonterminalKind::Meta => token::NtMeta(P(self.parse_attr_item(true)?)), |
5869c6ff | 176 | NonterminalKind::Vis => token::NtVis( |
04454e1e | 177 | P(self.collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?), |
5869c6ff | 178 | ), |
3dfed10e XL |
179 | NonterminalKind::Lifetime => { |
180 | if self.check_lifetime() { | |
181 | token::NtLifetime(self.expect_lifetime().ident) | |
182 | } else { | |
9ffffee4 FG |
183 | return Err(UnexpectedNonterminal::Lifetime { |
184 | span: self.token.span, | |
185 | token: self.token.clone(), | |
186 | }.into_diagnostic(&self.sess.span_diagnostic)); | |
3dfed10e XL |
187 | } |
188 | } | |
17df50a5 XL |
189 | }; |
190 | ||
191 | // If tokens are supported at all, they should be collected. | |
192 | if matches!(nt.tokens_mut(), Some(None)) { | |
193 | panic!( | |
194 | "Missing tokens for nt {:?} at {:?}: {:?}", | |
195 | nt, | |
196 | nt.span(), | |
197 | pprust::nonterminal_to_string(&nt) | |
198 | ); | |
199 | } | |
200 | ||
5e7ed085 | 201 | Ok(NtOrTt::Nt(nt)) |
3dfed10e XL |
202 | } |
203 | } | |
204 | ||
205 | /// The token is an identifier, but not `_`. | |
206 | /// We prohibit passing `_` to macros expecting `ident` for now. | |
207 | fn get_macro_ident(token: &Token) -> Option<(Ident, bool)> { | |
208 | token.ident().filter(|(ident, _)| ident.name != kw::Underscore) | |
209 | } |