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 lex_token_tree_open_delim(
55 &mut self,
56 open_delim: Delimiter,
57 ) -> Result<TokenTree, Vec<Diag<'psess>>> {
58 let pre_span = self.token.span;
60
61 self.diag_info.open_delimiters.push((open_delim, self.token.span));
62
63 let (open_spacing, tts) = self.lex_token_trees(true)?;
67
68 let delim_span = DelimSpan::from_pair(pre_span, self.token.span);
70 let sm = self.psess.source_map();
71
72 let close_spacing = if let Some(close_delim) = self.token.kind.close_delim() {
73 if close_delim == open_delim {
74 let (open_delimiter, open_delimiter_span) =
76 self.diag_info.open_delimiters.pop().unwrap();
77 let close_delimiter_span = self.token.span;
78
79 if tts.is_empty() && close_delim == Delimiter::Brace {
80 let empty_block_span = open_delimiter_span.to(close_delimiter_span);
81 if !sm.is_multiline(empty_block_span) {
82 self.diag_info.empty_block_spans.push(empty_block_span);
85 }
86 }
87
88 if let (Delimiter::Brace, Delimiter::Brace) = (open_delimiter, open_delim) {
90 self.diag_info
92 .matching_block_spans
93 .push((open_delimiter_span, close_delimiter_span));
94 }
95
96 self.bump_minimal()
98 } else {
99 let mut unclosed_delimiter = None;
101 let mut candidate = None;
102
103 if self.diag_info.last_unclosed_found_span != Some(self.token.span) {
104 self.diag_info.last_unclosed_found_span = Some(self.token.span);
106 if let Some(&(_, sp)) = self.diag_info.open_delimiters.last() {
110 unclosed_delimiter = Some(sp);
111 };
112 for (delimiter, delimiter_span) in &self.diag_info.open_delimiters {
113 if same_indentation_level(sm, self.token.span, *delimiter_span)
114 && delimiter == &close_delim
115 {
116 candidate = Some(*delimiter_span);
118 }
119 }
120 let (_, _) = self.diag_info.open_delimiters.pop().unwrap();
121 self.diag_info.unmatched_delims.push(UnmatchedDelim {
122 found_delim: Some(close_delim),
123 found_span: self.token.span,
124 unclosed_span: unclosed_delimiter,
125 candidate_span: candidate,
126 });
127 } else {
128 self.diag_info.open_delimiters.pop();
129 }
130
131 if !self.diag_info.open_delimiters.iter().any(|&(d, _)| d == close_delim) {
139 self.bump_minimal()
140 } else {
141 Spacing::Alone
143 }
144 }
145 } else {
146 assert_eq!(self.token.kind, token::Eof);
147 Spacing::Alone
152 };
153
154 let spacing = DelimSpacing::new(open_spacing, close_spacing);
155
156 Ok(TokenTree::Delimited(delim_span, spacing, open_delim, tts))
157 }
158
159 fn bump(&mut self) -> (Token, Spacing) {
162 let (this_spacing, next_tok) = loop {
163 let (next_tok, is_next_tok_preceded_by_whitespace) = self.next_token_from_cursor();
164
165 if is_next_tok_preceded_by_whitespace {
166 break (Spacing::Alone, next_tok);
167 } else if let Some(glued) = self.token.glue(&next_tok) {
168 self.token = glued;
169 } else {
170 let this_spacing = self.calculate_spacing(&next_tok);
171 break (this_spacing, next_tok);
172 }
173 };
174 let this_tok = std::mem::replace(&mut self.token, next_tok);
175 (this_tok, this_spacing)
176 }
177
178 fn bump_minimal(&mut self) -> Spacing {
180 let (next_tok, is_next_tok_preceded_by_whitespace) = self.next_token_from_cursor();
181 let this_spacing = if is_next_tok_preceded_by_whitespace {
182 Spacing::Alone
183 } else {
184 self.calculate_spacing(&next_tok)
185 };
186 self.token = next_tok;
187 this_spacing
188 }
189
190 fn calculate_spacing(&self, next_tok: &Token) -> Spacing {
191 if next_tok.is_punct() {
192 Spacing::Joint
193 } else if *next_tok == token::Eof {
194 Spacing::Alone
195 } else {
196 Spacing::JointHidden
197 }
198 }
199
200 fn eof_err(&mut self) -> Diag<'psess> {
201 const UNCLOSED_DELIMITER_SHOW_LIMIT: usize = 5;
202 let msg = "this file contains an unclosed delimiter";
203 let mut err = self.dcx().struct_span_err(self.token.span, msg);
204
205 let len = usize::min(UNCLOSED_DELIMITER_SHOW_LIMIT, self.diag_info.open_delimiters.len());
206 for &(_, span) in &self.diag_info.open_delimiters[..len] {
207 err.span_label(span, "unclosed delimiter");
208 self.diag_info.unmatched_delims.push(UnmatchedDelim {
209 found_delim: None,
210 found_span: self.token.span,
211 unclosed_span: Some(span),
212 candidate_span: None,
213 });
214 }
215
216 if let Some((_, span)) = self.diag_info.open_delimiters.get(UNCLOSED_DELIMITER_SHOW_LIMIT)
217 && self.diag_info.open_delimiters.len() >= UNCLOSED_DELIMITER_SHOW_LIMIT + 2
218 {
219 err.span_label(
220 *span,
221 format!(
222 "another {} unclosed delimiters begin from here",
223 self.diag_info.open_delimiters.len() - UNCLOSED_DELIMITER_SHOW_LIMIT
224 ),
225 );
226 }
227
228 if let Some((delim, _)) = self.diag_info.open_delimiters.last() {
229 report_suspicious_mismatch_block(
230 &mut err,
231 &self.diag_info,
232 self.psess.source_map(),
233 *delim,
234 )
235 }
236 err
237 }
238
239 fn close_delim_err(&mut self, delim: Delimiter) -> Diag<'psess> {
240 let token_str = token_to_string(&self.token);
242 let msg = format!("unexpected closing delimiter: `{token_str}`");
243 let mut err = self.dcx().struct_span_err(self.token.span, msg);
244
245 if !report_missing_open_delim(&mut err, &mut self.diag_info.unmatched_delims) {
247 report_suspicious_mismatch_block(
248 &mut err,
249 &self.diag_info,
250 self.psess.source_map(),
251 delim,
252 );
253 }
254
255 err.span_label(self.token.span, "unexpected closing delimiter");
256 err
257 }
258}