2 use rustc_ast
::token
::{self, Nonterminal, NonterminalKind, Token}
;
3 use rustc_ast_pretty
::pprust
;
4 use rustc_errors
::PResult
;
5 use rustc_span
::symbol
::{kw, Ident}
;
7 use crate::parser
::{FollowedByType, Parser, PathStyle}
;
10 /// Checks whether a non-terminal may begin with a particular token.
12 /// Returning `false` is a *stability guarantee* that such a matcher will *never* begin with that
13 /// token. Be conservative (return true) if not sure.
14 pub fn nonterminal_may_begin_with(kind
: NonterminalKind
, token
: &Token
) -> bool
{
15 /// Checks whether the non-terminal may contain a single (non-keyword) identifier.
16 fn may_be_ident(nt
: &token
::Nonterminal
) -> bool
{
18 token
::NtItem(_
) | token
::NtBlock(_
) | token
::NtVis(_
) | token
::NtLifetime(_
) => {
26 NonterminalKind
::Expr
=> {
27 token
.can_begin_expr()
28 // This exception is here for backwards compatibility.
29 && !token
.is_keyword(kw
::Let
)
31 NonterminalKind
::Ty
=> token
.can_begin_type(),
32 NonterminalKind
::Ident
=> get_macro_ident(token
).is_some(),
33 NonterminalKind
::Literal
=> token
.can_begin_literal_maybe_minus(),
34 NonterminalKind
::Vis
=> match token
.kind
{
35 // The follow-set of :vis + "priv" keyword + interpolated
36 token
::Comma
| token
::Ident(..) | token
::Interpolated(..) => true,
37 _
=> token
.can_begin_type(),
39 NonterminalKind
::Block
=> match token
.kind
{
40 token
::OpenDelim(token
::Brace
) => true,
41 token
::Interpolated(ref nt
) => match **nt
{
48 | token
::NtVis(_
) => false, // none of these may start with '{'.
53 NonterminalKind
::Path
| NonterminalKind
::Meta
=> match token
.kind
{
54 token
::ModSep
| token
::Ident(..) => true,
55 token
::Interpolated(ref nt
) => match **nt
{
56 token
::NtPath(_
) | token
::NtMeta(_
) => true,
57 _
=> may_be_ident(&nt
),
61 NonterminalKind
::Pat
=> match token
.kind
{
62 token
::Ident(..) | // box, ref, mut, and other identifiers (can stricten)
63 token
::OpenDelim(token
::Paren
) | // tuple pattern
64 token
::OpenDelim(token
::Bracket
) | // slice pattern
65 token
::BinOp(token
::And
) | // reference
66 token
::BinOp(token
::Minus
) | // negative literal
67 token
::AndAnd
| // double reference
68 token
::Literal(..) | // literal
69 token
::DotDot
| // range pattern (future compat)
70 token
::DotDotDot
| // range pattern (future compat)
71 token
::ModSep
| // path
72 token
::Lt
| // path (UFCS constant)
73 token
::BinOp(token
::Shl
) => true, // path (double UFCS)
74 token
::Interpolated(ref nt
) => may_be_ident(nt
),
77 NonterminalKind
::Lifetime
=> match token
.kind
{
78 token
::Lifetime(_
) => true,
79 token
::Interpolated(ref nt
) => match **nt
{
80 token
::NtLifetime(_
) | token
::NtTT(_
) => true,
85 NonterminalKind
::TT
| NonterminalKind
::Item
| NonterminalKind
::Stmt
=> match token
.kind
87 token
::CloseDelim(_
) => false,
93 pub fn parse_nonterminal(&mut self, kind
: NonterminalKind
) -> PResult
<'a
, Nonterminal
> {
94 // Any `Nonterminal` which stores its tokens (currently `NtItem` and `NtExpr`)
95 // needs to have them force-captured here.
96 // A `macro_rules!` invocation may pass a captured item/expr to a proc-macro,
97 // which requires having captured tokens available. Since we cannot determine
98 // in advance whether or not a proc-macro will be (transitively) invoked,
99 // we always capture tokens for any `Nonterminal` which needs them.
101 NonterminalKind
::Item
=> match self.collect_tokens(|this
| this
.parse_item())?
{
102 (Some(mut item
), tokens
) => {
103 // If we captured tokens during parsing (due to outer attributes),
105 if item
.tokens
.is_none() {
106 item
.tokens
= Some(tokens
);
111 return Err(self.struct_span_err(self.token
.span
, "expected an item keyword"));
114 NonterminalKind
::Block
=> {
115 let (mut block
, tokens
) = self.collect_tokens(|this
| this
.parse_block())?
;
116 // We have have eaten an NtBlock, which could already have tokens
117 if block
.tokens
.is_none() {
118 block
.tokens
= Some(tokens
);
120 token
::NtBlock(block
)
122 NonterminalKind
::Stmt
=> {
123 let (stmt
, tokens
) = self.collect_tokens(|this
| this
.parse_stmt())?
;
126 if s
.tokens
.is_none() {
127 s
.tokens
= Some(tokens
);
132 return Err(self.struct_span_err(self.token
.span
, "expected a statement"));
136 NonterminalKind
::Pat
=> {
137 let (mut pat
, tokens
) = self.collect_tokens(|this
| this
.parse_pat(None
))?
;
138 // We have have eaten an NtPat, which could already have tokens
139 if pat
.tokens
.is_none() {
140 pat
.tokens
= Some(tokens
);
144 NonterminalKind
::Expr
=> {
145 let (mut expr
, tokens
) = self.collect_tokens(|this
| this
.parse_expr())?
;
146 // If we captured tokens during parsing (due to outer attributes),
148 if expr
.tokens
.is_none() {
149 expr
.tokens
= Some(tokens
);
153 NonterminalKind
::Literal
=> {
154 let (mut lit
, tokens
) =
155 self.collect_tokens(|this
| this
.parse_literal_maybe_minus())?
;
156 // We have have eaten a nonterminal, which could already have tokens
157 if lit
.tokens
.is_none() {
158 lit
.tokens
= Some(tokens
);
160 token
::NtLiteral(lit
)
162 NonterminalKind
::Ty
=> {
163 let (mut ty
, tokens
) = self.collect_tokens(|this
| this
.parse_ty())?
;
164 // We have an eaten an NtTy, which could already have tokens
165 if ty
.tokens
.is_none() {
166 ty
.tokens
= Some(tokens
);
170 // this could be handled like a token, since it is one
171 NonterminalKind
::Ident
=> {
172 if let Some((ident
, is_raw
)) = get_macro_ident(&self.token
) {
174 token
::NtIdent(ident
, is_raw
)
176 let token_str
= pprust
::token_to_string(&self.token
);
177 let msg
= &format
!("expected ident, found {}", &token_str
);
178 return Err(self.struct_span_err(self.token
.span
, msg
));
181 NonterminalKind
::Path
=> {
182 let (mut path
, tokens
) =
183 self.collect_tokens(|this
| this
.parse_path(PathStyle
::Type
))?
;
184 // We have have eaten an NtPath, which could already have tokens
185 if path
.tokens
.is_none() {
186 path
.tokens
= Some(tokens
);
190 NonterminalKind
::Meta
=> {
191 let (mut attr
, tokens
) = self.collect_tokens(|this
| this
.parse_attr_item())?
;
192 // We may have eaten a nonterminal, which could already have tokens
193 if attr
.tokens
.is_none() {
194 attr
.tokens
= Some(tokens
);
196 token
::NtMeta(P(attr
))
198 NonterminalKind
::TT
=> token
::NtTT(self.parse_token_tree()),
199 NonterminalKind
::Vis
=> {
200 let (mut vis
, tokens
) =
201 self.collect_tokens(|this
| this
.parse_visibility(FollowedByType
::Yes
))?
;
202 // We may have etan an `NtVis`, which could already have tokens
203 if vis
.tokens
.is_none() {
204 vis
.tokens
= Some(tokens
);
208 NonterminalKind
::Lifetime
=> {
209 if self.check_lifetime() {
210 token
::NtLifetime(self.expect_lifetime().ident
)
212 let token_str
= pprust
::token_to_string(&self.token
);
213 let msg
= &format
!("expected a lifetime, found `{}`", &token_str
);
214 return Err(self.struct_span_err(self.token
.span
, msg
));
221 /// The token is an identifier, but not `_`.
222 /// We prohibit passing `_` to macros expecting `ident` for now.
223 fn get_macro_ident(token
: &Token
) -> Option
<(Ident
, bool
)> {
224 token
.ident().filter(|(ident
, _
)| ident
.name
!= kw
::Underscore
)