Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 59 additions & 9 deletions compiler/rustc_ast/src/tokenstream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,7 @@ pub enum Spacing {

/// A `TokenStream` is an abstract sequence of tokens, organized into [`TokenTree`]s.
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Encodable, Decodable)]
pub struct TokenStream(pub(crate) Arc<Vec<TokenTree>>);
pub struct TokenStream(Arc<Vec<TokenTree>>);

impl TokenStream {
pub fn new(tts: Vec<TokenTree>) -> TokenStream {
Expand Down Expand Up @@ -880,7 +880,7 @@ impl<'t> Iterator for TokenStreamIter<'t> {
}

#[derive(Clone, Debug)]
pub struct TokenTreeCursor {
struct TokenTreeCursor {
stream: TokenStream,
/// Points to the current token tree in the stream. In `TokenCursor::curr`,
/// this can be any token tree. In `TokenCursor::stack`, this is always a
Expand All @@ -890,27 +890,27 @@ pub struct TokenTreeCursor {

impl TokenTreeCursor {
#[inline]
pub fn new(stream: TokenStream) -> Self {
fn new(stream: TokenStream) -> Self {
TokenTreeCursor { stream, index: 0 }
}

#[inline]
pub fn curr(&self) -> Option<&TokenTree> {
fn curr(&self) -> Option<&TokenTree> {
self.stream.get(self.index)
}

pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> {
fn look_ahead(&self, n: usize) -> Option<&TokenTree> {
self.stream.get(self.index + n)
}

#[inline]
pub fn bump(&mut self) {
fn bump(&mut self) {
self.index += 1;
}

// For skipping ahead in rare circumstances.
#[inline]
pub fn bump_to_end(&mut self) {
fn bump_to_end(&mut self) {
self.index = self.stream.len();
}
}
Expand All @@ -926,18 +926,68 @@ pub struct TokenCursor {
// The delimiters for this token stream are found in `self.stack.last()`;
// if that is `None` we are in the outermost token stream which never has
// delimiters.
pub curr: TokenTreeCursor,
curr: TokenTreeCursor,

// Token streams surrounding the current one. The index within each cursor
// always points to a `TokenTree::Delimited`.
pub stack: Vec<TokenTreeCursor>,
stack: Vec<TokenTreeCursor>,
}

impl TokenCursor {
#[inline]
pub fn new(stream: TokenStream) -> Self {
TokenCursor { curr: TokenTreeCursor::new(stream), stack: vec![] }
}

pub fn next(&mut self) -> (Token, Spacing) {
self.inlined_next()
}

/// An `n` of zero is the next token tree in the current token stream; won't look outside the
/// current token stream.
#[inline]
pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> {
self.curr.look_ahead(n)
}

/// Returns the first token tree (if there is one) past the close delimiter of the enclosing
/// delimited sequence. Panics if we are not within a delimited sequence.
#[inline]
pub fn look_ahead_past_close_delim(&self) -> Option<&TokenTree> {
self.stack.last().unwrap().look_ahead(1)
}

/// Clones the `TokenTree::Delimited` that we are currently within. Panics if we are not within
/// a delimited sequence.
#[inline]
pub fn clone_enclosing_delim(&self) -> TokenTree {
self.stack.last().unwrap().curr().unwrap().clone()
}

/// For skipping to the end of the current sequence, in rare circumstances.
#[inline]
pub fn bump_to_end(&mut self) {
self.curr.bump_to_end()
}

/// Note: the outermost stream has depth of 0.
#[inline]
pub fn depth(&self) -> usize {
self.stack.len()
}

/// Returns details about the parent delimited sequence, if there is one.
#[inline]
pub fn parent_delim_and_span(&self) -> Option<(Delimiter, DelimSpan)> {
if let Some(last) = self.stack.last()
&& let Some(TokenTree::Delimited(span, _, delim, _)) = last.curr()
{
Some((*delim, *span))
} else {
None
}
}

/// This always-inlined version should only be used on hot code paths.
#[inline(always)]
pub fn inlined_next(&mut self) -> (Token, Spacing) {
Expand Down
9 changes: 3 additions & 6 deletions compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use ast::mut_visit::{self, MutVisitor};
use ast::token::IdentIsRaw;
use ast::{CoroutineKind, ForLoopKind, GenBlockKind, MatchKind, Pat, Path, PathSegment, Recovered};
use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, Token, TokenKind};
use rustc_ast::tokenstream::TokenTree;
use rustc_ast::util::case::Case;
use rustc_ast::util::classify;
use rustc_ast::util::parser::{AssocOp, ExprPrecedence, Fixity, prec_let_scrutinee_needs_par};
Expand Down Expand Up @@ -1276,13 +1275,12 @@ impl<'a> Parser<'a> {
None
};
let open_paren = self.token.span;
let call_depth = self.token_cursor.stack.len();
let call_depth = self.token_cursor.depth();

let seq = match self.parse_expr_paren_seq() {
Ok(args) => Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args))),
Err(err)
if self.is_expected_raw_ref_mut()
&& self.token_cursor.stack.len() == call_depth =>
if self.is_expected_raw_ref_mut() && self.token_cursor.depth() == call_depth =>
{
let guar = err.emit();
// Preserve the call expression so later passes can still diagnose the callee,
Expand Down Expand Up @@ -2510,8 +2508,7 @@ impl<'a> Parser<'a> {
}

if self.token == TokenKind::Semi
&& let Some(last) = self.token_cursor.stack.last()
&& let Some(TokenTree::Delimited(_, _, Delimiter::Parenthesis, _)) = last.curr()
&& let Some((Delimiter::Parenthesis, _)) = self.token_cursor.parent_delim_and_span()
&& self.may_recover()
{
// It is likely that the closure body is a block but where the
Expand Down
31 changes: 13 additions & 18 deletions compiler/rustc_parse/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ use rustc_ast::token::{
self, IdentIsRaw, InvisibleOrigin, MetaVarKind, NtExprKind, NtPatKind, Token, TokenKind,
};
use rustc_ast::tokenstream::{
ParserRange, ParserReplacement, Spacing, TokenCursor, TokenStream, TokenTree, TokenTreeCursor,
WithTokens,
ParserRange, ParserReplacement, Spacing, TokenCursor, TokenStream, TokenTree, WithTokens,
};
use rustc_ast::util::case::Case;
use rustc_ast::util::classify;
Expand Down Expand Up @@ -346,7 +345,7 @@ impl<'a> Parser<'a> {
) -> Self {
let mut parser = Parser {
psess,
token_cursor: TokenCursor { curr: TokenTreeCursor::new(stream), stack: Vec::new() },
token_cursor: TokenCursor::new(stream),
subparser_name,
capture_state: CaptureState {
capturing: Capturing::No,
Expand Down Expand Up @@ -502,10 +501,8 @@ impl<'a> Parser<'a> {
// Primarily used when `self.token` matches `OpenInvisible(_))`, to look
// ahead through the current metavar expansion.
fn check_noexpect_past_close_delim(&self, tok: &TokenKind) -> bool {
let mut tree_cursor = self.token_cursor.stack.last().unwrap().clone();
tree_cursor.bump();
matches!(
tree_cursor.curr(),
self.token_cursor.look_ahead_past_close_delim(),
Some(TokenTree::Token(token::Token { kind, .. }, _)) if kind == tok
)
}
Expand Down Expand Up @@ -1157,9 +1154,8 @@ impl<'a> Parser<'a> {
// Typically around 98% of the `dist > 0` cases have `dist == 1`, so we
// have a fast special case for that.
if dist == 1 {
// The index is zero because the tree cursor's index always points
// to the next token to be gotten.
match self.token_cursor.curr.curr() {
// `look_ahead(0)` returns the *next* token.
match self.token_cursor.look_ahead(0) {
Some(tree) => {
// Indexing stayed within the current token tree.
match tree {
Expand All @@ -1174,8 +1170,7 @@ impl<'a> Parser<'a> {
None => {
// The tree cursor lookahead went (one) past the end of the
// current token tree. Try to return a close delimiter.
if let Some(last) = self.token_cursor.stack.last()
&& let Some(&TokenTree::Delimited(span, _, delim, _)) = last.curr()
if let Some((delim, span)) = self.token_cursor.parent_delim_and_span()
&& !delim.skip()
{
// We are not in the outermost token stream, so we have
Expand Down Expand Up @@ -1203,15 +1198,15 @@ impl<'a> Parser<'a> {
looker(&token)
}

/// Like `lookahead`, but skips over token trees rather than tokens. Useful
/// Like `look_ahead`, but skips over token trees rather than tokens. Useful
/// when looking past possible metavariable pasting sites.
pub fn tree_look_ahead<R>(
&self,
dist: usize,
looker: impl FnOnce(&TokenTree) -> R,
) -> Option<R> {
assert_ne!(dist, 0);
self.token_cursor.curr.look_ahead(dist - 1).map(looker)
self.token_cursor.look_ahead(dist - 1).map(looker)
}

/// Returns whether any of the given keywords are `dist` tokens ahead of the current one.
Expand Down Expand Up @@ -1408,30 +1403,30 @@ impl<'a> Parser<'a> {
if self.token.kind.open_delim().is_some() {
// Clone the `TokenTree::Delimited` that we are currently
// within. That's what we are going to return.
let tree = self.token_cursor.stack.last().unwrap().curr().unwrap().clone();
let tree = self.token_cursor.clone_enclosing_delim();
debug_assert_matches!(tree, TokenTree::Delimited(..));

// Advance the token cursor through the entire delimited
// sequence. After getting the `OpenDelim` we are *within* the
// delimited sequence, i.e. at depth `d`. After getting the
// matching `CloseDelim` we are *after* the delimited sequence,
// i.e. at depth `d - 1`.
let target_depth = self.token_cursor.stack.len() - 1;
let target_depth = self.token_cursor.depth() - 1;

if let Capturing::No = self.capture_state.capturing {
// We are not capturing tokens, so skip to the end of the
// delimited sequence. This is a perf win when dealing with
// declarative macros that pass large `tt` fragments through
// multiple rules, as seen in the uom-0.37.0 crate.
self.token_cursor.curr.bump_to_end();
self.token_cursor.bump_to_end();
self.bump();
debug_assert_eq!(self.token_cursor.stack.len(), target_depth);
debug_assert_eq!(self.token_cursor.depth(), target_depth);
} else {
loop {
// Advance one token at a time, so `TokenCursor::next()`
// can capture these tokens if necessary.
self.bump();
if self.token_cursor.stack.len() == target_depth {
if self.token_cursor.depth() == target_depth {
break;
}
}
Expand Down
Loading