2019-10-11 12:01:02 +00:00
|
|
|
use super::{StringReader, UnmatchedBrace};
|
2022-04-26 12:40:14 +00:00
|
|
|
use rustc_ast::token::{self, Delimiter, Token};
|
Remove `TreeAndSpacing`.
A `TokenStream` contains a `Lrc<Vec<(TokenTree, Spacing)>>`. But this is
not quite right. `Spacing` makes sense for `TokenTree::Token`, but does
not make sense for `TokenTree::Delimited`, because a
`TokenTree::Delimited` cannot be joined with another `TokenTree`.
This commit fixes this problem, by adding `Spacing` to `TokenTree::Token`,
changing `TokenStream` to contain a `Lrc<Vec<TokenTree>>`, and removing the
`TreeAndSpacing` typedef.
The commit removes these two impls:
- `impl From<TokenTree> for TokenStream`
- `impl From<TokenTree> for TreeAndSpacing`
These were useful, but also resulted in code with many `.into()` calls
that was hard to read, particularly for anyone not highly familiar with
the relevant types. This commit makes some other changes to compensate:
- `TokenTree::token()` becomes `TokenTree::token_{alone,joint}()`.
- `TokenStream::token_{alone,joint}()` are added.
- `TokenStream::delimited` is added.
This results in things like this:
```rust
TokenTree::token(token::Semi, stmt.span).into()
```
changing to this:
```rust
TokenStream::token_alone(token::Semi, stmt.span)
```
This makes the type of the result, and its spacing, clearer.
These changes also simplifies `Cursor` and `CursorRef`, because they no longer
need to distinguish between `next` and `next_with_spacing`.
2022-07-28 00:31:04 +00:00
|
|
|
use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenStream, TokenTree};
|
2020-02-29 17:37:32 +00:00
|
|
|
use rustc_ast_pretty::pprust::token_to_string;
|
|
|
|
use rustc_data_structures::fx::FxHashMap;
|
2022-09-21 04:01:39 +00:00
|
|
|
use rustc_errors::{PErr, PResult};
|
2020-02-29 17:37:32 +00:00
|
|
|
use rustc_span::Span;
|
2019-10-11 11:06:36 +00:00
|
|
|
|
2022-09-25 22:50:52 +00:00
|
|
|
pub(super) struct TokenTreesReader<'a> {
|
2019-05-12 16:55:16 +00:00
|
|
|
string_reader: StringReader<'a>,
|
2022-09-26 23:53:04 +00:00
|
|
|
/// The "next" token, which has been obtained from the `StringReader` but
|
|
|
|
/// not yet handled by the `TokenTreesReader`.
|
2019-06-04 21:02:59 +00:00
|
|
|
token: Token,
|
2019-05-12 16:55:16 +00:00
|
|
|
/// Stack of open delimiters and their spans. Used for error message.
|
2022-04-26 12:40:14 +00:00
|
|
|
open_braces: Vec<(Delimiter, Span)>,
|
2019-05-12 16:55:16 +00:00
|
|
|
unmatched_braces: Vec<UnmatchedBrace>,
|
|
|
|
/// The type and spans for all braces
|
|
|
|
///
|
|
|
|
/// Used only for error recovery when arriving to EOF with mismatched braces.
|
2022-04-26 12:40:14 +00:00
|
|
|
matching_delim_spans: Vec<(Delimiter, Span, Span)>,
|
2019-05-12 16:55:16 +00:00
|
|
|
last_unclosed_found_span: Option<Span>,
|
2020-03-03 23:07:33 +00:00
|
|
|
/// Collect empty block spans that might have been auto-inserted by editors.
|
2022-04-26 12:40:14 +00:00
|
|
|
last_delim_empty_block_spans: FxHashMap<Delimiter, Span>,
|
2020-04-02 06:42:21 +00:00
|
|
|
/// Collect the spans of braces (Open, Close). Used only
|
2020-04-04 07:55:07 +00:00
|
|
|
/// for detecting if blocks are empty and only braces.
|
2020-04-02 06:42:21 +00:00
|
|
|
matching_block_spans: Vec<(Span, Span)>,
|
2019-05-12 16:55:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> TokenTreesReader<'a> {
|
2022-09-30 06:43:11 +00:00
|
|
|
pub(super) fn parse_all_token_trees(
|
2022-09-25 22:50:52 +00:00
|
|
|
string_reader: StringReader<'a>,
|
|
|
|
) -> (PResult<'a, TokenStream>, Vec<UnmatchedBrace>) {
|
|
|
|
let mut tt_reader = TokenTreesReader {
|
|
|
|
string_reader,
|
|
|
|
token: Token::dummy(),
|
|
|
|
open_braces: Vec::new(),
|
|
|
|
unmatched_braces: Vec::new(),
|
|
|
|
matching_delim_spans: Vec::new(),
|
|
|
|
last_unclosed_found_span: None,
|
|
|
|
last_delim_empty_block_spans: FxHashMap::default(),
|
|
|
|
matching_block_spans: Vec::new(),
|
|
|
|
};
|
2022-09-30 21:57:22 +00:00
|
|
|
let res = tt_reader.parse_token_trees(/* is_delimited */ false);
|
2022-09-25 22:50:52 +00:00
|
|
|
(res, tt_reader.unmatched_braces)
|
|
|
|
}
|
|
|
|
|
2022-09-30 06:43:11 +00:00
|
|
|
// Parse a stream of tokens into a list of `TokenTree`s.
|
2022-09-30 21:57:22 +00:00
|
|
|
fn parse_token_trees(&mut self, is_delimited: bool) -> PResult<'a, TokenStream> {
|
2022-09-21 07:03:09 +00:00
|
|
|
self.token = self.string_reader.next_token().0;
|
2022-09-30 06:51:35 +00:00
|
|
|
let mut buf = Vec::new();
|
2022-09-21 04:01:39 +00:00
|
|
|
loop {
|
|
|
|
match self.token.kind {
|
|
|
|
token::OpenDelim(delim) => buf.push(self.parse_token_tree_open_delim(delim)),
|
2022-09-30 06:43:11 +00:00
|
|
|
token::CloseDelim(delim) => {
|
2022-09-30 21:57:22 +00:00
|
|
|
return if is_delimited {
|
2022-09-30 06:51:35 +00:00
|
|
|
Ok(TokenStream::new(buf))
|
2022-09-30 06:43:11 +00:00
|
|
|
} else {
|
|
|
|
Err(self.close_delim_err(delim))
|
|
|
|
};
|
|
|
|
}
|
2022-09-21 04:01:39 +00:00
|
|
|
token::Eof => {
|
2022-09-30 21:57:22 +00:00
|
|
|
if is_delimited {
|
2022-09-30 06:43:11 +00:00
|
|
|
self.eof_err().emit();
|
|
|
|
}
|
2022-09-30 06:51:35 +00:00
|
|
|
return Ok(TokenStream::new(buf));
|
2017-01-12 23:32:00 +00:00
|
|
|
}
|
2022-09-30 06:50:02 +00:00
|
|
|
_ => {
|
2022-09-30 06:51:35 +00:00
|
|
|
// Get the next normal token. This might require getting multiple adjacent
|
|
|
|
// single-char tokens and joining them together.
|
|
|
|
let (this_spacing, next_tok) = loop {
|
|
|
|
let (next_tok, is_next_tok_preceded_by_whitespace) =
|
|
|
|
self.string_reader.next_token();
|
|
|
|
if !is_next_tok_preceded_by_whitespace {
|
|
|
|
if let Some(glued) = self.token.glue(&next_tok) {
|
|
|
|
self.token = glued;
|
|
|
|
} else {
|
|
|
|
let this_spacing =
|
|
|
|
if next_tok.is_op() { Spacing::Joint } else { Spacing::Alone };
|
|
|
|
break (this_spacing, next_tok);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
break (Spacing::Alone, next_tok);
|
|
|
|
}
|
2022-09-30 06:50:02 +00:00
|
|
|
};
|
|
|
|
let this_tok = std::mem::replace(&mut self.token, next_tok);
|
2022-09-30 06:51:35 +00:00
|
|
|
buf.push(TokenTree::Token(this_tok, this_spacing));
|
2022-09-30 06:50:02 +00:00
|
|
|
}
|
2018-05-17 16:30:43 +00:00
|
|
|
}
|
2017-01-12 23:32:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-21 04:01:39 +00:00
|
|
|
fn eof_err(&mut self) -> PErr<'a> {
|
|
|
|
let msg = "this file contains an unclosed delimiter";
|
|
|
|
let mut err = self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, msg);
|
|
|
|
for &(_, sp) in &self.open_braces {
|
|
|
|
err.span_label(sp, "unclosed delimiter");
|
|
|
|
self.unmatched_braces.push(UnmatchedBrace {
|
|
|
|
expected_delim: Delimiter::Brace,
|
|
|
|
found_delim: None,
|
|
|
|
found_span: self.token.span,
|
|
|
|
unclosed_span: Some(sp),
|
|
|
|
candidate_span: None,
|
|
|
|
});
|
|
|
|
}
|
2018-08-12 13:43:51 +00:00
|
|
|
|
2022-09-21 04:01:39 +00:00
|
|
|
if let Some((delim, _)) = self.open_braces.last() {
|
|
|
|
if let Some((_, open_sp, close_sp)) =
|
|
|
|
self.matching_delim_spans.iter().find(|(d, open_sp, close_sp)| {
|
|
|
|
let sm = self.string_reader.sess.source_map();
|
|
|
|
if let Some(close_padding) = sm.span_to_margin(*close_sp) {
|
|
|
|
if let Some(open_padding) = sm.span_to_margin(*open_sp) {
|
|
|
|
return delim == d && close_padding != open_padding;
|
|
|
|
}
|
2018-09-04 15:09:49 +00:00
|
|
|
}
|
2022-09-21 04:01:39 +00:00
|
|
|
false
|
|
|
|
})
|
|
|
|
// these are in reverse order as they get inserted on close, but
|
|
|
|
{
|
|
|
|
// we want the last open/first close
|
|
|
|
err.span_label(*open_sp, "this delimiter might not be properly closed...");
|
|
|
|
err.span_label(*close_sp, "...as it matches this but it has different indentation");
|
2017-01-12 23:32:00 +00:00
|
|
|
}
|
2022-09-21 04:01:39 +00:00
|
|
|
}
|
|
|
|
err
|
|
|
|
}
|
2017-01-12 23:32:00 +00:00
|
|
|
|
2022-09-27 02:04:03 +00:00
|
|
|
fn parse_token_tree_open_delim(&mut self, open_delim: Delimiter) -> TokenTree {
|
2022-09-21 04:01:39 +00:00
|
|
|
// The span for beginning of the delimited section
|
|
|
|
let pre_span = self.token.span;
|
2017-01-12 23:32:00 +00:00
|
|
|
|
2022-09-27 02:04:03 +00:00
|
|
|
self.open_braces.push((open_delim, self.token.span));
|
2017-01-12 23:32:00 +00:00
|
|
|
|
2022-09-21 04:01:39 +00:00
|
|
|
// Parse the token trees within the delimiters.
|
|
|
|
// We stop at any delimiter so we can try to recover if the user
|
|
|
|
// uses an incorrect delimiter.
|
2022-09-30 21:57:22 +00:00
|
|
|
let tts = self.parse_token_trees(/* is_delimited */ true).unwrap();
|
2019-10-13 04:59:23 +00:00
|
|
|
|
2022-09-21 04:01:39 +00:00
|
|
|
// Expand to cover the entire delimited token tree
|
|
|
|
let delim_span = DelimSpan::from_pair(pre_span, self.token.span);
|
2019-10-13 04:59:23 +00:00
|
|
|
|
2022-09-21 04:01:39 +00:00
|
|
|
match self.token.kind {
|
|
|
|
// Correct delimiter.
|
2022-09-27 02:04:03 +00:00
|
|
|
token::CloseDelim(close_delim) if close_delim == open_delim => {
|
2022-09-21 04:01:39 +00:00
|
|
|
let (open_brace, open_brace_span) = self.open_braces.pop().unwrap();
|
|
|
|
let close_brace_span = self.token.span;
|
2020-04-02 06:42:21 +00:00
|
|
|
|
2022-09-21 04:01:39 +00:00
|
|
|
if tts.is_empty() {
|
|
|
|
let empty_block_span = open_brace_span.to(close_brace_span);
|
|
|
|
let sm = self.string_reader.sess.source_map();
|
|
|
|
if !sm.is_multiline(empty_block_span) {
|
|
|
|
// Only track if the block is in the form of `{}`, otherwise it is
|
|
|
|
// likely that it was written on purpose.
|
2022-09-27 02:04:03 +00:00
|
|
|
self.last_delim_empty_block_spans.insert(open_delim, empty_block_span);
|
2017-01-12 23:32:00 +00:00
|
|
|
}
|
2022-09-21 04:01:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//only add braces
|
2022-09-27 02:04:03 +00:00
|
|
|
if let (Delimiter::Brace, Delimiter::Brace) = (open_brace, open_delim) {
|
2022-09-21 04:01:39 +00:00
|
|
|
self.matching_block_spans.push((open_brace_span, close_brace_span));
|
|
|
|
}
|
|
|
|
|
|
|
|
if self.open_braces.is_empty() {
|
|
|
|
// Clear up these spans to avoid suggesting them as we've found
|
|
|
|
// properly matched delimiters so far for an entire block.
|
|
|
|
self.matching_delim_spans.clear();
|
|
|
|
} else {
|
|
|
|
self.matching_delim_spans.push((open_brace, open_brace_span, close_brace_span));
|
|
|
|
}
|
2022-09-26 23:53:04 +00:00
|
|
|
// Move past the closing delimiter.
|
2022-09-21 07:03:09 +00:00
|
|
|
self.token = self.string_reader.next_token().0;
|
2022-09-21 04:01:39 +00:00
|
|
|
}
|
|
|
|
// Incorrect delimiter.
|
2022-09-27 02:04:03 +00:00
|
|
|
token::CloseDelim(close_delim) => {
|
2022-09-21 04:01:39 +00:00
|
|
|
let mut unclosed_delimiter = None;
|
|
|
|
let mut candidate = None;
|
2020-04-02 06:42:21 +00:00
|
|
|
|
2022-09-21 04:01:39 +00:00
|
|
|
if self.last_unclosed_found_span != Some(self.token.span) {
|
|
|
|
// do not complain about the same unclosed delimiter multiple times
|
|
|
|
self.last_unclosed_found_span = Some(self.token.span);
|
|
|
|
// This is a conservative error: only report the last unclosed
|
|
|
|
// delimiter. The previous unclosed delimiters could actually be
|
|
|
|
// closed! The parser just hasn't gotten to them yet.
|
|
|
|
if let Some(&(_, sp)) = self.open_braces.last() {
|
|
|
|
unclosed_delimiter = Some(sp);
|
|
|
|
};
|
|
|
|
let sm = self.string_reader.sess.source_map();
|
|
|
|
if let Some(current_padding) = sm.span_to_margin(self.token.span) {
|
|
|
|
for (brace, brace_span) in &self.open_braces {
|
|
|
|
if let Some(padding) = sm.span_to_margin(*brace_span) {
|
|
|
|
// high likelihood of these two corresponding
|
2022-09-27 02:04:03 +00:00
|
|
|
if current_padding == padding && brace == &close_delim {
|
2022-09-21 04:01:39 +00:00
|
|
|
candidate = Some(*brace_span);
|
2018-09-04 15:09:49 +00:00
|
|
|
}
|
|
|
|
}
|
2017-01-12 23:32:00 +00:00
|
|
|
}
|
|
|
|
}
|
2022-09-21 04:01:39 +00:00
|
|
|
let (tok, _) = self.open_braces.pop().unwrap();
|
|
|
|
self.unmatched_braces.push(UnmatchedBrace {
|
|
|
|
expected_delim: tok,
|
2022-09-27 02:04:03 +00:00
|
|
|
found_delim: Some(close_delim),
|
2022-09-21 04:01:39 +00:00
|
|
|
found_span: self.token.span,
|
|
|
|
unclosed_span: unclosed_delimiter,
|
|
|
|
candidate_span: candidate,
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
self.open_braces.pop();
|
2017-01-12 23:32:00 +00:00
|
|
|
}
|
|
|
|
|
2022-09-21 04:01:39 +00:00
|
|
|
// If the incorrect delimiter matches an earlier opening
|
|
|
|
// delimiter, then don't consume it (it can be used to
|
|
|
|
// close the earlier one). Otherwise, consume it.
|
|
|
|
// E.g., we try to recover from:
|
|
|
|
// fn foo() {
|
|
|
|
// bar(baz(
|
|
|
|
// } // Incorrect delimiter but matches the earlier `{`
|
2022-09-27 02:04:03 +00:00
|
|
|
if !self.open_braces.iter().any(|&(b, _)| b == close_delim) {
|
2022-09-21 07:03:09 +00:00
|
|
|
self.token = self.string_reader.next_token().0;
|
2022-09-21 04:01:39 +00:00
|
|
|
}
|
2017-01-12 23:32:00 +00:00
|
|
|
}
|
2022-09-21 04:01:39 +00:00
|
|
|
token::Eof => {
|
|
|
|
// Silently recover, the EOF token will be seen again
|
|
|
|
// and an error emitted then. Thus we don't pop from
|
|
|
|
// self.open_braces here.
|
|
|
|
}
|
2022-09-26 23:53:04 +00:00
|
|
|
_ => unreachable!(),
|
2022-09-21 04:01:39 +00:00
|
|
|
}
|
2019-10-13 04:59:23 +00:00
|
|
|
|
2022-09-27 02:04:03 +00:00
|
|
|
TokenTree::Delimited(delim_span, open_delim, tts)
|
2022-09-21 04:01:39 +00:00
|
|
|
}
|
2020-04-04 07:55:07 +00:00
|
|
|
|
2022-09-21 04:01:39 +00:00
|
|
|
fn close_delim_err(&mut self, delim: Delimiter) -> PErr<'a> {
|
|
|
|
// An unexpected closing delimiter (i.e., there is no
|
|
|
|
// matching opening delimiter).
|
|
|
|
let token_str = token_to_string(&self.token);
|
|
|
|
let msg = format!("unexpected closing delimiter: `{}`", token_str);
|
|
|
|
let mut err =
|
|
|
|
self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, &msg);
|
2020-04-04 08:39:17 +00:00
|
|
|
|
2022-09-21 04:01:39 +00:00
|
|
|
// Braces are added at the end, so the last element is the biggest block
|
|
|
|
if let Some(parent) = self.matching_block_spans.last() {
|
|
|
|
if let Some(span) = self.last_delim_empty_block_spans.remove(&delim) {
|
|
|
|
// Check if the (empty block) is in the last properly closed block
|
|
|
|
if (parent.0.to(parent.1)).contains(span) {
|
|
|
|
err.span_label(span, "block is empty, you might have not meant to close it");
|
|
|
|
} else {
|
|
|
|
err.span_label(parent.0, "this opening brace...");
|
|
|
|
err.span_label(parent.1, "...matches this closing brace");
|
2020-04-01 06:16:23 +00:00
|
|
|
}
|
2022-09-21 04:01:39 +00:00
|
|
|
} else {
|
|
|
|
err.span_label(parent.0, "this opening brace...");
|
|
|
|
err.span_label(parent.1, "...matches this closing brace");
|
2017-01-12 23:32:00 +00:00
|
|
|
}
|
|
|
|
}
|
2022-09-21 04:01:39 +00:00
|
|
|
|
|
|
|
err.span_label(self.token.span, "unexpected closing delimiter");
|
|
|
|
err
|
|
|
|
}
|
2019-08-19 16:30:44 +00:00
|
|
|
}
|