|
1 | | -use super::{Capturing, FlatToken, ForceCollect, Parser, ReplaceRange, TokenCursor, TrailingToken}; |
2 | | -use rustc_ast::token::{self, Delimiter, Token, TokenKind}; |
3 | | -use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree, AttrsTarget, DelimSpacing}; |
4 | | -use rustc_ast::tokenstream::{DelimSpan, LazyAttrTokenStream, Spacing, ToAttrTokenStream}; |
| 1 | +use super::{Capturing, ForceCollect, Parser, TrailingToken}; |
| 2 | +use rustc_ast::token; |
| 3 | +use rustc_ast::tokenstream::{AttrsTarget, LazyAttrTokenStream, ReplaceRange}; |
5 | 4 | use rustc_ast::{self as ast}; |
6 | 5 | use rustc_ast::{AttrVec, Attribute, HasAttrs, HasTokens}; |
7 | 6 | use rustc_errors::PResult; |
8 | 7 | use rustc_session::parse::ParseSess; |
9 | | -use rustc_span::{sym, Span, DUMMY_SP}; |
| 8 | +use rustc_span::{sym, DUMMY_SP}; |
10 | 9 |
|
11 | | -use std::{iter, mem}; |
| 10 | +use std::mem; |
12 | 11 |
|
13 | 12 | /// A wrapper type to ensure that the parser handles outer attributes correctly. |
14 | 13 | /// When we parse outer attributes, we need to ensure that we capture tokens |
@@ -76,98 +75,6 @@ fn has_cfg_or_cfg_attr(attrs: &[Attribute]) -> bool { |
76 | 75 | }) |
77 | 76 | } |
78 | 77 |
|
79 | | -// Produces a `TokenStream` on-demand. Using `cursor_snapshot` |
80 | | -// and `num_calls`, we can reconstruct the `TokenStream` seen |
81 | | -// by the callback. This allows us to avoid producing a `TokenStream` |
82 | | -// if it is never needed - for example, a captured `macro_rules!` |
83 | | -// argument that is never passed to a proc macro. |
84 | | -// In practice token stream creation happens rarely compared to |
85 | | -// calls to `collect_tokens` (see some statistics in #78736), |
86 | | -// so we are doing as little up-front work as possible. |
87 | | -// |
88 | | -// This also makes `Parser` very cheap to clone, since |
89 | | -// there is no intermediate collection buffer to clone. |
90 | | -struct LazyAttrTokenStreamImpl { |
91 | | - start_token: (Token, Spacing), |
92 | | - cursor_snapshot: TokenCursor, |
93 | | - num_calls: u32, |
94 | | - break_last_token: bool, |
95 | | - replace_ranges: Box<[ReplaceRange]>, |
96 | | -} |
97 | | - |
98 | | -impl ToAttrTokenStream for LazyAttrTokenStreamImpl { |
99 | | - fn to_attr_token_stream(&self) -> AttrTokenStream { |
100 | | - // The token produced by the final call to `{,inlined_}next` was not |
101 | | - // actually consumed by the callback. The combination of chaining the |
102 | | - // initial token and using `take` produces the desired result - we |
103 | | - // produce an empty `TokenStream` if no calls were made, and omit the |
104 | | - // final token otherwise. |
105 | | - let mut cursor_snapshot = self.cursor_snapshot.clone(); |
106 | | - let tokens = iter::once((FlatToken::Token(self.start_token.0.clone()), self.start_token.1)) |
107 | | - .chain(iter::repeat_with(|| { |
108 | | - let token = cursor_snapshot.next(); |
109 | | - (FlatToken::Token(token.0), token.1) |
110 | | - })) |
111 | | - .take(self.num_calls as usize); |
112 | | - |
113 | | - if self.replace_ranges.is_empty() { |
114 | | - make_attr_token_stream(tokens, self.break_last_token) |
115 | | - } else { |
116 | | - let mut tokens: Vec<_> = tokens.collect(); |
117 | | - let mut replace_ranges = self.replace_ranges.to_vec(); |
118 | | - replace_ranges.sort_by_key(|(range, _)| range.start); |
119 | | - |
120 | | - #[cfg(debug_assertions)] |
121 | | - { |
122 | | - for [(range, tokens), (next_range, next_tokens)] in replace_ranges.array_windows() { |
123 | | - assert!( |
124 | | - range.end <= next_range.start || range.end >= next_range.end, |
125 | | - "Replace ranges should either be disjoint or nested: ({:?}, {:?}) ({:?}, {:?})", |
126 | | - range, |
127 | | - tokens, |
128 | | - next_range, |
129 | | - next_tokens, |
130 | | - ); |
131 | | - } |
132 | | - } |
133 | | - |
134 | | - // Process the replace ranges, starting from the highest start |
135 | | - // position and working our way back. If have tokens like: |
136 | | - // |
137 | | - // `#[cfg(FALSE)] struct Foo { #[cfg(FALSE)] field: bool }` |
138 | | - // |
139 | | - // Then we will generate replace ranges for both |
140 | | - // the `#[cfg(FALSE)] field: bool` and the entire |
141 | | - // `#[cfg(FALSE)] struct Foo { #[cfg(FALSE)] field: bool }` |
142 | | - // |
143 | | - // By starting processing from the replace range with the greatest |
144 | | - // start position, we ensure that any replace range which encloses |
145 | | - // another replace range will capture the *replaced* tokens for the inner |
146 | | - // range, not the original tokens. |
147 | | - for (range, target) in replace_ranges.into_iter().rev() { |
148 | | - assert!(!range.is_empty(), "Cannot replace an empty range: {range:?}"); |
149 | | - |
150 | | - // Replace the tokens in range with zero or one `FlatToken::AttrsTarget`s, plus |
151 | | - // enough `FlatToken::Empty`s to fill up the rest of the range. This keeps the |
152 | | - // total length of `tokens` constant throughout the replacement process, allowing |
153 | | - // us to use all of the `ReplaceRanges` entries without adjusting indices. |
154 | | - let target_len = target.is_some() as usize; |
155 | | - tokens.splice( |
156 | | - (range.start as usize)..(range.end as usize), |
157 | | - target |
158 | | - .into_iter() |
159 | | - .map(|target| (FlatToken::AttrsTarget(target), Spacing::Alone)) |
160 | | - .chain( |
161 | | - iter::repeat((FlatToken::Empty, Spacing::Alone)) |
162 | | - .take(range.len() - target_len), |
163 | | - ), |
164 | | - ); |
165 | | - } |
166 | | - make_attr_token_stream(tokens.into_iter(), self.break_last_token) |
167 | | - } |
168 | | - } |
169 | | -} |
170 | | - |
171 | 78 | impl<'a> Parser<'a> { |
172 | 79 | /// Records all tokens consumed by the provided callback, |
173 | 80 | /// including the current token. These tokens are collected |
@@ -317,20 +224,17 @@ impl<'a> Parser<'a> { |
317 | 224 | .collect() |
318 | 225 | }; |
319 | 226 |
|
320 | | - let tokens = LazyAttrTokenStream::new(LazyAttrTokenStreamImpl { |
| 227 | + let tokens = LazyAttrTokenStream::new_pending( |
321 | 228 | start_token, |
322 | | - num_calls, |
323 | 229 | cursor_snapshot, |
324 | | - break_last_token: self.break_last_token, |
| 230 | + num_calls, |
| 231 | + self.break_last_token, |
325 | 232 | replace_ranges, |
326 | | - }); |
| 233 | + ); |
327 | 234 |
|
328 | | - // If we support tokens at all |
329 | | - if let Some(target_tokens) = ret.tokens_mut() { |
330 | | - if target_tokens.is_none() { |
331 | | - // Store our newly captured tokens into the AST node. |
332 | | - *target_tokens = Some(tokens.clone()); |
333 | | - } |
| 235 | + // If we support tokens and don't already have them, store the newly captured tokens. |
| 236 | + if let Some(target_tokens @ None) = ret.tokens_mut() { |
| 237 | + *target_tokens = Some(tokens.clone()); |
334 | 238 | } |
335 | 239 |
|
336 | 240 | let final_attrs = ret.attrs(); |
@@ -366,88 +270,12 @@ impl<'a> Parser<'a> { |
366 | 270 | } |
367 | 271 | } |
368 | 272 |
|
369 | | -/// Converts a flattened iterator of tokens (including open and close delimiter tokens) into an |
370 | | -/// `AttrTokenStream`, creating an `AttrTokenTree::Delimited` for each matching pair of open and |
371 | | -/// close delims. |
372 | | -fn make_attr_token_stream( |
373 | | - mut iter: impl Iterator<Item = (FlatToken, Spacing)>, |
374 | | - break_last_token: bool, |
375 | | -) -> AttrTokenStream { |
376 | | - #[derive(Debug)] |
377 | | - struct FrameData { |
378 | | - // This is `None` for the first frame, `Some` for all others. |
379 | | - open_delim_sp: Option<(Delimiter, Span, Spacing)>, |
380 | | - inner: Vec<AttrTokenTree>, |
381 | | - } |
382 | | - let mut stack = vec![FrameData { open_delim_sp: None, inner: vec![] }]; |
383 | | - let mut token_and_spacing = iter.next(); |
384 | | - while let Some((token, spacing)) = token_and_spacing { |
385 | | - match token { |
386 | | - FlatToken::Token(Token { kind: TokenKind::OpenDelim(delim), span }) => { |
387 | | - stack |
388 | | - .push(FrameData { open_delim_sp: Some((delim, span, spacing)), inner: vec![] }); |
389 | | - } |
390 | | - FlatToken::Token(Token { kind: TokenKind::CloseDelim(delim), span }) => { |
391 | | - let frame_data = stack |
392 | | - .pop() |
393 | | - .unwrap_or_else(|| panic!("Token stack was empty for token: {token:?}")); |
394 | | - |
395 | | - let (open_delim, open_sp, open_spacing) = frame_data.open_delim_sp.unwrap(); |
396 | | - assert_eq!( |
397 | | - open_delim, delim, |
398 | | - "Mismatched open/close delims: open={open_delim:?} close={span:?}" |
399 | | - ); |
400 | | - let dspan = DelimSpan::from_pair(open_sp, span); |
401 | | - let dspacing = DelimSpacing::new(open_spacing, spacing); |
402 | | - let stream = AttrTokenStream::new(frame_data.inner); |
403 | | - let delimited = AttrTokenTree::Delimited(dspan, dspacing, delim, stream); |
404 | | - stack |
405 | | - .last_mut() |
406 | | - .unwrap_or_else(|| panic!("Bottom token frame is missing for token: {token:?}")) |
407 | | - .inner |
408 | | - .push(delimited); |
409 | | - } |
410 | | - FlatToken::Token(token) => stack |
411 | | - .last_mut() |
412 | | - .expect("Bottom token frame is missing!") |
413 | | - .inner |
414 | | - .push(AttrTokenTree::Token(token, spacing)), |
415 | | - FlatToken::AttrsTarget(target) => stack |
416 | | - .last_mut() |
417 | | - .expect("Bottom token frame is missing!") |
418 | | - .inner |
419 | | - .push(AttrTokenTree::AttrsTarget(target)), |
420 | | - FlatToken::Empty => {} |
421 | | - } |
422 | | - token_and_spacing = iter.next(); |
423 | | - } |
424 | | - let mut final_buf = stack.pop().expect("Missing final buf!"); |
425 | | - if break_last_token { |
426 | | - let last_token = final_buf.inner.pop().unwrap(); |
427 | | - if let AttrTokenTree::Token(last_token, spacing) = last_token { |
428 | | - let unglued_first = last_token.kind.break_two_token_op().unwrap().0; |
429 | | - |
430 | | - // An 'unglued' token is always two ASCII characters |
431 | | - let mut first_span = last_token.span.shrink_to_lo(); |
432 | | - first_span = first_span.with_hi(first_span.lo() + rustc_span::BytePos(1)); |
433 | | - |
434 | | - final_buf |
435 | | - .inner |
436 | | - .push(AttrTokenTree::Token(Token::new(unglued_first, first_span), spacing)); |
437 | | - } else { |
438 | | - panic!("Unexpected last token {last_token:?}") |
439 | | - } |
440 | | - } |
441 | | - AttrTokenStream::new(final_buf.inner) |
442 | | -} |
443 | | - |
444 | 273 | // Some types are used a lot. Make sure they don't unintentionally get bigger. |
445 | 274 | #[cfg(target_pointer_width = "64")] |
446 | 275 | mod size_asserts { |
447 | 276 | use super::*; |
448 | 277 | use rustc_data_structures::static_assert_size; |
449 | 278 | // tidy-alphabetical-start |
450 | 279 | static_assert_size!(AttrWrapper, 16); |
451 | | - static_assert_size!(LazyAttrTokenStreamImpl, 96); |
452 | 280 | // tidy-alphabetical-end |
453 | 281 | } |
0 commit comments