rustc_parse/lexer/
tokentrees.rs1use rustc_ast::token::{self, Delimiter, Token};
2use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
3use rustc_ast_pretty::pprust::token_to_string;
4use rustc_errors::Diag;
5
6use super::diagnostics::{
7    report_missing_open_delim, report_suspicious_mismatch_block, same_indentation_level,
8};
9use super::{Lexer, UnmatchedDelim};
10
11impl<'psess, 'src> Lexer<'psess, 'src> {
12    pub(super) fn lex_token_trees(
15        &mut self,
16        is_delimited: bool,
17    ) -> Result<(Spacing, TokenStream), Vec<Diag<'psess>>> {
18        let open_spacing = self.bump_minimal();
20
21        let mut buf = Vec::new();
22        loop {
23            if let Some(delim) = self.token.kind.open_delim() {
24                debug_assert!(!matches!(delim, Delimiter::Invisible(_)));
27                buf.push(match self.lex_token_tree_open_delim(delim) {
28                    Ok(val) => val,
29                    Err(errs) => return Err(errs),
30                })
31            } else if let Some(delim) = self.token.kind.close_delim() {
32                debug_assert!(!matches!(delim, Delimiter::Invisible(_)));
35                return if is_delimited {
36                    Ok((open_spacing, TokenStream::new(buf)))
37                } else {
38                    Err(vec![self.close_delim_err(delim)])
39                };
40            } else if self.token.kind == token::Eof {
41                return if is_delimited {
42                    Err(vec![self.eof_err()])
43                } else {
44                    Ok((open_spacing, TokenStream::new(buf)))
45                };
46            } else {
47                let (this_tok, this_spacing) = self.bump();
49                buf.push(TokenTree::Token(this_tok, this_spacing));
50            }
51        }
52    }
53
54    fn eof_err(&mut self) -> Diag<'psess> {
55        let msg = "this file contains an unclosed delimiter";
56        let mut err = self.dcx().struct_span_err(self.token.span, msg);
57
58        let unclosed_delimiter_show_limit = 5;
59        let len = usize::min(unclosed_delimiter_show_limit, self.diag_info.open_delimiters.len());
60        for &(_, span) in &self.diag_info.open_delimiters[..len] {
61            err.span_label(span, "unclosed delimiter");
62            self.diag_info.unmatched_delims.push(UnmatchedDelim {
63                found_delim: None,
64                found_span: self.token.span,
65                unclosed_span: Some(span),
66                candidate_span: None,
67            });
68        }
69
70        if let Some((_, span)) = self.diag_info.open_delimiters.get(unclosed_delimiter_show_limit)
71            && self.diag_info.open_delimiters.len() >= unclosed_delimiter_show_limit + 2
72        {
73            err.span_label(
74                *span,
75                format!(
76                    "another {} unclosed delimiters begin from here",
77                    self.diag_info.open_delimiters.len() - unclosed_delimiter_show_limit
78                ),
79            );
80        }
81
82        if let Some((delim, _)) = self.diag_info.open_delimiters.last() {
83            report_suspicious_mismatch_block(
84                &mut err,
85                &self.diag_info,
86                self.psess.source_map(),
87                *delim,
88            )
89        }
90        err
91    }
92
93    fn lex_token_tree_open_delim(
94        &mut self,
95        open_delim: Delimiter,
96    ) -> Result<TokenTree, Vec<Diag<'psess>>> {
97        let pre_span = self.token.span;
99
100        self.diag_info.open_delimiters.push((open_delim, self.token.span));
101
102        let (open_spacing, tts) = self.lex_token_trees(true)?;
106
107        let delim_span = DelimSpan::from_pair(pre_span, self.token.span);
109        let sm = self.psess.source_map();
110
111        let close_spacing = if let Some(close_delim) = self.token.kind.close_delim() {
112            if close_delim == open_delim {
113                let (open_delimiter, open_delimiter_span) =
115                    self.diag_info.open_delimiters.pop().unwrap();
116                let close_delimiter_span = self.token.span;
117
118                if tts.is_empty() && close_delim == Delimiter::Brace {
119                    let empty_block_span = open_delimiter_span.to(close_delimiter_span);
120                    if !sm.is_multiline(empty_block_span) {
121                        self.diag_info.empty_block_spans.push(empty_block_span);
124                    }
125                }
126
127                if let (Delimiter::Brace, Delimiter::Brace) = (open_delimiter, open_delim) {
129                    self.diag_info
131                        .matching_block_spans
132                        .push((open_delimiter_span, close_delimiter_span));
133                }
134
135                self.bump_minimal()
137            } else {
138                let mut unclosed_delimiter = None;
140                let mut candidate = None;
141
142                if self.diag_info.last_unclosed_found_span != Some(self.token.span) {
143                    self.diag_info.last_unclosed_found_span = Some(self.token.span);
145                    if let Some(&(_, sp)) = self.diag_info.open_delimiters.last() {
149                        unclosed_delimiter = Some(sp);
150                    };
151                    for (delimiter, delimiter_span) in &self.diag_info.open_delimiters {
152                        if same_indentation_level(sm, self.token.span, *delimiter_span)
153                            && delimiter == &close_delim
154                        {
155                            candidate = Some(*delimiter_span);
157                        }
158                    }
159                    let (_, _) = self.diag_info.open_delimiters.pop().unwrap();
160                    self.diag_info.unmatched_delims.push(UnmatchedDelim {
161                        found_delim: Some(close_delim),
162                        found_span: self.token.span,
163                        unclosed_span: unclosed_delimiter,
164                        candidate_span: candidate,
165                    });
166                } else {
167                    self.diag_info.open_delimiters.pop();
168                }
169
170                if !self.diag_info.open_delimiters.iter().any(|&(d, _)| d == close_delim) {
178                    self.bump_minimal()
179                } else {
180                    Spacing::Alone
182                }
183            }
184        } else {
185            assert_eq!(self.token.kind, token::Eof);
186            Spacing::Alone
191        };
192
193        let spacing = DelimSpacing::new(open_spacing, close_spacing);
194
195        Ok(TokenTree::Delimited(delim_span, spacing, open_delim, tts))
196    }
197
198    fn bump(&mut self) -> (Token, Spacing) {
201        let (this_spacing, next_tok) = loop {
202            let (next_tok, is_next_tok_preceded_by_whitespace) = self.next_token_from_cursor();
203
204            if is_next_tok_preceded_by_whitespace {
205                break (Spacing::Alone, next_tok);
206            } else if let Some(glued) = self.token.glue(&next_tok) {
207                self.token = glued;
208            } else {
209                let this_spacing = if next_tok.is_punct() {
210                    Spacing::Joint
211                } else if next_tok == token::Eof {
212                    Spacing::Alone
213                } else {
214                    Spacing::JointHidden
215                };
216                break (this_spacing, next_tok);
217            }
218        };
219        let this_tok = std::mem::replace(&mut self.token, next_tok);
220        (this_tok, this_spacing)
221    }
222
223    fn bump_minimal(&mut self) -> Spacing {
225        let (next_tok, is_next_tok_preceded_by_whitespace) = self.next_token_from_cursor();
226
227        let this_spacing = if is_next_tok_preceded_by_whitespace {
228            Spacing::Alone
229        } else {
230            if next_tok.is_punct() {
231                Spacing::Joint
232            } else if next_tok == token::Eof {
233                Spacing::Alone
234            } else {
235                Spacing::JointHidden
236            }
237        };
238
239        self.token = next_tok;
240        this_spacing
241    }
242
243    fn close_delim_err(&mut self, delim: Delimiter) -> Diag<'psess> {
244        let token_str = token_to_string(&self.token);
246        let msg = format!("unexpected closing delimiter: `{token_str}`");
247        let mut err = self.dcx().struct_span_err(self.token.span, msg);
248
249        if !report_missing_open_delim(&mut err, &mut self.diag_info.unmatched_delims) {
251            report_suspicious_mismatch_block(
252                &mut err,
253                &self.diag_info,
254                self.psess.source_map(),
255                delim,
256            );
257        }
258
259        err.span_label(self.token.span, "unexpected closing delimiter");
260        err
261    }
262}