Skip to content

Commit af1d16e

Browse files
committed
Improve doc comment desugaring.
Sometimes the parser needs to desugar a doc comment into `#[doc = r"foo"]`. Currently it does this in a hacky way: by pushing a "fake" new frame (one without a delimiter) onto the `TokenCursor` stack. This commit changes things so that the token stream itself is modified in place. The nice thing about this is that it means `TokenCursorFrame::delim_sp` is now only `None` for the outermost frame.
1 parent 97872b7 commit af1d16e

File tree

2 files changed

+30
-27
lines changed

2 files changed

+30
-27
lines changed

compiler/rustc_ast/src/tokenstream.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,15 @@ impl Cursor {
614614
pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> {
615615
self.stream.0.get(self.index + n)
616616
}
617+
618+
// Replace the previously obtained token tree with `tts`, and rewind to
619+
// just before them.
620+
pub fn replace_prev_and_rewind(&mut self, tts: Vec<TokenTree>) {
621+
assert!(self.index > 0);
622+
self.index -= 1;
623+
let stream = Lrc::make_mut(&mut self.stream.0);
624+
stream.splice(self.index..self.index + 1, tts);
625+
}
617626
}
618627

619628
#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]

compiler/rustc_parse/src/parser/mod.rs

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ impl<'a> Drop for Parser<'a> {
224224
#[derive(Clone)]
225225
struct TokenCursor {
226226
// The current (innermost) frame. `frame` and `stack` could be combined,
227-
// but it's faster to have them separately to access `frame` directly
227+
// but it's faster to keep them separate and access `frame` directly
228228
// rather than via something like `stack.last().unwrap()` or
229229
// `stack[stack.len() - 1]`.
230230
frame: TokenCursorFrame,
@@ -259,6 +259,7 @@ struct TokenCursor {
259259

260260
#[derive(Clone)]
261261
struct TokenCursorFrame {
262+
// This is `None` only for the outermost frame.
262263
delim_sp: Option<(Delimiter, DelimSpan)>,
263264
tree_cursor: tokenstream::Cursor,
264265
}
@@ -285,7 +286,9 @@ impl TokenCursor {
285286
match tree {
286287
&TokenTree::Token(ref token, spacing) => match (desugar_doc_comments, token) {
287288
(true, &Token { kind: token::DocComment(_, attr_style, data), span }) => {
288-
return self.desugar(attr_style, data, span);
289+
let desugared = self.desugar(attr_style, data, span);
290+
self.frame.tree_cursor.replace_prev_and_rewind(desugared);
291+
// Continue to get the first token of the desugared doc comment.
289292
}
290293
_ => return (token.clone(), spacing),
291294
},
@@ -300,19 +303,22 @@ impl TokenCursor {
300303
}
301304
};
302305
} else if let Some(frame) = self.stack.pop() {
303-
if let Some((delim, span)) = self.frame.delim_sp && delim != Delimiter::Invisible {
304-
self.frame = frame;
306+
// We have exhausted this frame. Move back to its parent frame.
307+
let (delim, span) = self.frame.delim_sp.unwrap();
308+
self.frame = frame;
309+
if delim != Delimiter::Invisible {
305310
return (Token::new(token::CloseDelim(delim), span.close), Spacing::Alone);
306311
}
307-
self.frame = frame;
308312
// No close delimiter to return; continue on to the next iteration.
309313
} else {
314+
// We have exhausted the outermost frame.
310315
return (Token::new(token::Eof, DUMMY_SP), Spacing::Alone);
311316
}
312317
}
313318
}
314319

315-
fn desugar(&mut self, attr_style: AttrStyle, data: Symbol, span: Span) -> (Token, Spacing) {
320+
// Desugar a doc comment into something like `#[doc = r"foo"]`.
321+
fn desugar(&mut self, attr_style: AttrStyle, data: Symbol, span: Span) -> Vec<TokenTree> {
316322
// Searches for the occurrences of `"#*` and returns the minimum number of `#`s
317323
// required to wrap the text. E.g.
318324
// - `abc d` is wrapped as `r"abc d"` (num_of_hashes = 0)
@@ -346,27 +352,15 @@ impl TokenCursor {
346352
.collect::<TokenStream>(),
347353
);
348354

349-
self.stack.push(mem::replace(
350-
&mut self.frame,
351-
TokenCursorFrame::new(
352-
None,
353-
if attr_style == AttrStyle::Inner {
354-
[
355-
TokenTree::token_alone(token::Pound, span),
356-
TokenTree::token_alone(token::Not, span),
357-
body,
358-
]
359-
.into_iter()
360-
.collect::<TokenStream>()
361-
} else {
362-
[TokenTree::token_alone(token::Pound, span), body]
363-
.into_iter()
364-
.collect::<TokenStream>()
365-
},
366-
),
367-
));
368-
369-
self.next(/* desugar_doc_comments */ false)
355+
if attr_style == AttrStyle::Inner {
356+
vec![
357+
TokenTree::token_alone(token::Pound, span),
358+
TokenTree::token_alone(token::Not, span),
359+
body,
360+
]
361+
} else {
362+
vec![TokenTree::token_alone(token::Pound, span), body]
363+
}
370364
}
371365
}
372366

0 commit comments

Comments
 (0)