1 use super::{StringReader, UnmatchedBrace}
;
3 use rustc_ast
::token
::{self, DelimToken, Token}
;
4 use rustc_ast
::tokenstream
::{
7 TokenStream
, TokenTree
, TreeAndSpacing
,
9 use rustc_ast_pretty
::pprust
::token_to_string
;
10 use rustc_data_structures
::fx
::FxHashMap
;
11 use rustc_errors
::PResult
;
14 impl<'a
> StringReader
<'a
> {
15 pub(super) fn into_token_trees(self) -> (PResult
<'a
, TokenStream
>, Vec
<UnmatchedBrace
>) {
16 let mut tt_reader
= TokenTreesReader
{
18 token
: Token
::dummy(),
19 open_braces
: Vec
::new(),
20 unmatched_braces
: Vec
::new(),
21 matching_delim_spans
: Vec
::new(),
22 last_unclosed_found_span
: None
,
23 last_delim_empty_block_spans
: FxHashMap
::default(),
24 matching_block_spans
: Vec
::new(),
26 let res
= tt_reader
.parse_all_token_trees();
27 (res
, tt_reader
.unmatched_braces
)
31 struct TokenTreesReader
<'a
> {
32 string_reader
: StringReader
<'a
>,
34 /// Stack of open delimiters and their spans. Used for error message.
35 open_braces
: Vec
<(token
::DelimToken
, Span
)>,
36 unmatched_braces
: Vec
<UnmatchedBrace
>,
37 /// The type and spans for all braces
39 /// Used only for error recovery when arriving to EOF with mismatched braces.
40 matching_delim_spans
: Vec
<(token
::DelimToken
, Span
, Span
)>,
41 last_unclosed_found_span
: Option
<Span
>,
42 /// Collect empty block spans that might have been auto-inserted by editors.
43 last_delim_empty_block_spans
: FxHashMap
<token
::DelimToken
, Span
>,
44 /// Collect the spans of braces (Open, Close). Used only
45 /// for detecting if blocks are empty and only braces.
46 matching_block_spans
: Vec
<(Span
, Span
)>,
49 impl<'a
> TokenTreesReader
<'a
> {
50 // Parse a stream of tokens into a list of `TokenTree`s, up to an `Eof`.
51 fn parse_all_token_trees(&mut self) -> PResult
<'a
, TokenStream
> {
52 let mut buf
= TokenStreamBuilder
::default();
55 while self.token
!= token
::Eof
{
56 buf
.push(self.parse_token_tree()?
);
59 Ok(buf
.into_token_stream())
62 // Parse a stream of tokens into a list of `TokenTree`s, up to a `CloseDelim`.
63 fn parse_token_trees_until_close_delim(&mut self) -> TokenStream
{
64 let mut buf
= TokenStreamBuilder
::default();
66 if let token
::CloseDelim(..) = self.token
.kind
{
67 return buf
.into_token_stream();
70 match self.parse_token_tree() {
71 Ok(tree
) => buf
.push(tree
),
74 return buf
.into_token_stream();
80 fn parse_token_tree(&mut self) -> PResult
<'a
, TreeAndSpacing
> {
81 let sm
= self.string_reader
.sess
.source_map();
83 match self.token
.kind
{
85 let msg
= "this file contains an unclosed delimiter";
87 self.string_reader
.sess
.span_diagnostic
.struct_span_err(self.token
.span
, msg
);
88 for &(_
, sp
) in &self.open_braces
{
89 err
.span_label(sp
, "unclosed delimiter");
90 self.unmatched_braces
.push(UnmatchedBrace
{
91 expected_delim
: token
::DelimToken
::Brace
,
93 found_span
: self.token
.span
,
94 unclosed_span
: Some(sp
),
99 if let Some((delim
, _
)) = self.open_braces
.last() {
100 if let Some((_
, open_sp
, close_sp
)) =
101 self.matching_delim_spans
.iter().find(|(d
, open_sp
, close_sp
)| {
102 if let Some(close_padding
) = sm
.span_to_margin(*close_sp
) {
103 if let Some(open_padding
) = sm
.span_to_margin(*open_sp
) {
104 return delim
== d
&& close_padding
!= open_padding
;
109 // these are in reverse order as they get inserted on close, but
111 // we want the last open/first close
112 err
.span_label(*open_sp
, "this delimiter might not be properly closed...");
115 "...as it matches this but it has different indentation",
121 token
::OpenDelim(delim
) => {
122 // The span for beginning of the delimited section
123 let pre_span
= self.token
.span
;
125 // Parse the open delimiter.
126 self.open_braces
.push((delim
, self.token
.span
));
129 // Parse the token trees within the delimiters.
130 // We stop at any delimiter so we can try to recover if the user
131 // uses an incorrect delimiter.
132 let tts
= self.parse_token_trees_until_close_delim();
134 // Expand to cover the entire delimited token tree
135 let delim_span
= DelimSpan
::from_pair(pre_span
, self.token
.span
);
137 match self.token
.kind
{
138 // Correct delimiter.
139 token
::CloseDelim(d
) if d
== delim
=> {
140 let (open_brace
, open_brace_span
) = self.open_braces
.pop().unwrap();
141 let close_brace_span
= self.token
.span
;
144 let empty_block_span
= open_brace_span
.to(close_brace_span
);
145 if !sm
.is_multiline(empty_block_span
) {
146 // Only track if the block is in the form of `{}`, otherwise it is
147 // likely that it was written on purpose.
148 self.last_delim_empty_block_spans
.insert(delim
, empty_block_span
);
153 if let (DelimToken
::Brace
, DelimToken
::Brace
) = (open_brace
, delim
) {
154 self.matching_block_spans
.push((open_brace_span
, close_brace_span
));
157 if self.open_braces
.is_empty() {
158 // Clear up these spans to avoid suggesting them as we've found
159 // properly matched delimiters so far for an entire block.
160 self.matching_delim_spans
.clear();
162 self.matching_delim_spans
.push((
168 // Parse the closing delimiter.
171 // Incorrect delimiter.
172 token
::CloseDelim(other
) => {
173 let mut unclosed_delimiter
= None
;
174 let mut candidate
= None
;
176 if self.last_unclosed_found_span
!= Some(self.token
.span
) {
177 // do not complain about the same unclosed delimiter multiple times
178 self.last_unclosed_found_span
= Some(self.token
.span
);
179 // This is a conservative error: only report the last unclosed
180 // delimiter. The previous unclosed delimiters could actually be
181 // closed! The parser just hasn't gotten to them yet.
182 if let Some(&(_
, sp
)) = self.open_braces
.last() {
183 unclosed_delimiter
= Some(sp
);
185 if let Some(current_padding
) = sm
.span_to_margin(self.token
.span
) {
186 for (brace
, brace_span
) in &self.open_braces
{
187 if let Some(padding
) = sm
.span_to_margin(*brace_span
) {
188 // high likelihood of these two corresponding
189 if current_padding
== padding
&& brace
== &other
{
190 candidate
= Some(*brace_span
);
195 let (tok
, _
) = self.open_braces
.pop().unwrap();
196 self.unmatched_braces
.push(UnmatchedBrace
{
198 found_delim
: Some(other
),
199 found_span
: self.token
.span
,
200 unclosed_span
: unclosed_delimiter
,
201 candidate_span
: candidate
,
204 self.open_braces
.pop();
207 // If the incorrect delimiter matches an earlier opening
208 // delimiter, then don't consume it (it can be used to
209 // close the earlier one). Otherwise, consume it.
210 // E.g., we try to recover from:
213 // } // Incorrect delimiter but matches the earlier `{`
214 if !self.open_braces
.iter().any(|&(b
, _
)| b
== other
) {
219 // Silently recover, the EOF token will be seen again
220 // and an error emitted then. Thus we don't pop from
221 // self.open_braces here.
226 Ok(TokenTree
::Delimited(delim_span
, delim
, tts
).into())
228 token
::CloseDelim(delim
) => {
229 // An unexpected closing delimiter (i.e., there is no
230 // matching opening delimiter).
231 let token_str
= token_to_string(&self.token
);
232 let msg
= format
!("unexpected closing delimiter: `{}`", token_str
);
234 self.string_reader
.sess
.span_diagnostic
.struct_span_err(self.token
.span
, &msg
);
236 // Braces are added at the end, so the last element is the biggest block
237 if let Some(parent
) = self.matching_block_spans
.last() {
238 if let Some(span
) = self.last_delim_empty_block_spans
.remove(&delim
) {
239 // Check if the (empty block) is in the last properly closed block
240 if (parent
.0.to(parent
.1)).contains(span
) {
243 "block is empty, you might have not meant to close it",
246 err
.span_label(parent
.0, "this opening brace...");
248 err
.span_label(parent
.1, "...matches this closing brace");
251 err
.span_label(parent
.0, "this opening brace...");
253 err
.span_label(parent
.1, "...matches this closing brace");
257 err
.span_label(self.token
.span
, "unexpected closing delimiter");
261 let tt
= TokenTree
::Token(self.token
.take());
262 let mut spacing
= self.bump();
263 if !self.token
.is_op() {
271 fn bump(&mut self) -> Spacing
{
272 let (spacing
, token
) = self.string_reader
.next_token();
279 struct TokenStreamBuilder
{
280 buf
: Vec
<TreeAndSpacing
>,
283 impl TokenStreamBuilder
{
284 fn push(&mut self, (tree
, joint
): TreeAndSpacing
) {
285 if let Some((TokenTree
::Token(prev_token
), Joint
)) = self.buf
.last() {
286 if let TokenTree
::Token(token
) = &tree
{
287 if let Some(glued
) = prev_token
.glue(token
) {
289 self.buf
.push((TokenTree
::Token(glued
), joint
));
294 self.buf
.push((tree
, joint
))
297 fn into_token_stream(self) -> TokenStream
{
298 TokenStream
::new(self.buf
)