Skip to content

Commit 6f20e45

Browse files
compiler: add Parser::debug_lookahead
I tried debugging a parser-related issue but found it annoying to not be able to easily peek into the Parser's token stream. Add a convenience fn that offers an opinionated view into the parser, but one that is useful for answering basic questions about parser state.
1 parent 0b8f9e5 commit 6f20e45

File tree

2 files changed

+42
-0
lines changed

2 files changed

+42
-0
lines changed

compiler/rustc_parse/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#![allow(rustc::untranslatable_diagnostic)]
66
#![feature(array_windows)]
77
#![feature(box_patterns)]
8+
#![feature(debug_closure_helpers)]
89
#![feature(if_let_guard)]
910
#![feature(iter_intersperse)]
1011
#![feature(let_chains)]

compiler/rustc_parse/src/parser/mod.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,6 +1538,47 @@ impl<'a> Parser<'a> {
15381538
})
15391539
}
15401540

1541+
// debug view of the parser's token stream, up to `{lookahead}` tokens
1542+
pub fn debug_lookahead(&self, lookahead: usize) -> impl fmt::Debug + '_ {
1543+
struct DebugParser<'dbg> {
1544+
parser: &'dbg Parser<'dbg>,
1545+
lookahead: usize,
1546+
}
1547+
1548+
impl fmt::Debug for DebugParser<'_> {
1549+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1550+
let Self { parser, lookahead } = self;
1551+
let mut dbg_fmt = f.debug_struct("Parser"); // or at least, one view of
1552+
1553+
// we don't need N spans, but we want at least one, so print all of prev_token
1554+
dbg_fmt.field("prev_token", &parser.prev_token);
1555+
// make it easier to peek farther ahead by taking TokenKinds only until EOF
1556+
let tokens = (0..*lookahead)
1557+
.map(|i| parser.look_ahead(i, |tok| tok.kind.clone()))
1558+
.scan(parser.prev_token == TokenKind::Eof, |eof, tok| {
1559+
let current = eof.then_some(tok); // include a trailing EOF token
1560+
*eof |= tok == TokenKind::Eof;
1561+
current
1562+
});
1563+
dbg_fmt.field_with("tokens", |field| field.debug_list().entries(tokens).finish());
1564+
dbg_fmt.field("approx_token_stream_pos", &parser.num_bump_calls);
1565+
1566+
// some fields are interesting for certain values, as they relate to macro parsing
1567+
if let Some(subparser) = parser.subparser_name {
1568+
dbg_fmt.field("subparser_name", &subparser);
1569+
}
1570+
if parser.recovery == Recovery::Forbidden {
1571+
dbg_fmt.field("recovery", &parser.recovery);
1572+
}
1573+
1574+
// imply there's "more to know" than this view
1575+
dbg_fmt.finish_non_exhaustive()
1576+
}
1577+
}
1578+
1579+
DebugParser { parser: self, lookahead }
1580+
}
1581+
15411582
pub fn clear_expected_tokens(&mut self) {
15421583
self.expected_tokens.clear();
15431584
}

0 commit comments

Comments
 (0)