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}