|
| 1 | +// SPDX-License-Identifier: MIT or Apache-2.0 |
| 2 | + |
| 3 | +// Adapted from https://github.com/dtolnay/syn/blob/1.0.72/src/buffer.rs |
| 4 | +// Changes made compared to upstream: |
| 5 | +// * Removed code that depends on proc_macro2 |
| 6 | +// * Removed lifetime parsing which depends on types defined elsewhere in syn. |
| 7 | + |
| 8 | +use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Span, TokenStream, TokenTree}; |
| 9 | +use std::marker::PhantomData; |
| 10 | +use std::ptr; |
| 11 | + |
| 12 | +/// Internal type which is used instead of `TokenTree` to represent a token tree |
| 13 | +/// within a `TokenBuffer`. |
| 14 | +enum Entry { |
| 15 | + // Mimicking types from proc-macro. |
| 16 | + Group(Group, TokenBuffer), |
| 17 | + Ident(Ident), |
| 18 | + Punct(Punct), |
| 19 | + Literal(Literal), |
| 20 | + // End entries contain a raw pointer to the entry from the containing |
| 21 | + // token tree, or null if this is the outermost level. |
| 22 | + End(*const Entry), |
| 23 | +} |
| 24 | + |
| 25 | +/// A buffer that can be efficiently traversed multiple times, unlike |
| 26 | +/// `TokenStream` which requires a deep copy in order to traverse more than |
| 27 | +/// once. |
| 28 | +/// |
| 29 | +/// *This type is available only if Syn is built with the `"parsing"` feature.* |
| 30 | +pub struct TokenBuffer { |
| 31 | + // NOTE: Do not derive clone on this - there are raw pointers inside which |
| 32 | + // will be messed up. Moving the `TokenBuffer` itself is safe as the actual |
| 33 | + // backing slices won't be moved. |
| 34 | + data: Box<[Entry]>, |
| 35 | +} |
| 36 | + |
| 37 | +impl TokenBuffer { |
| 38 | + // NOTE: DO NOT MUTATE THE `Vec` RETURNED FROM THIS FUNCTION ONCE IT |
| 39 | + // RETURNS, THE ADDRESS OF ITS BACKING MEMORY MUST REMAIN STABLE. |
| 40 | + fn inner_new(stream: TokenStream, up: *const Entry) -> TokenBuffer { |
| 41 | + // Build up the entries list, recording the locations of any Groups |
| 42 | + // in the list to be processed later. |
| 43 | + let mut entries = Vec::new(); |
| 44 | + let mut seqs = Vec::new(); |
| 45 | + for tt in stream { |
| 46 | + match tt { |
| 47 | + TokenTree::Ident(sym) => { |
| 48 | + entries.push(Entry::Ident(sym)); |
| 49 | + } |
| 50 | + TokenTree::Punct(op) => { |
| 51 | + entries.push(Entry::Punct(op)); |
| 52 | + } |
| 53 | + TokenTree::Literal(l) => { |
| 54 | + entries.push(Entry::Literal(l)); |
| 55 | + } |
| 56 | + TokenTree::Group(g) => { |
| 57 | + // Record the index of the interesting entry, and store an |
| 58 | + // `End(null)` there temporarially. |
| 59 | + seqs.push((entries.len(), g)); |
| 60 | + entries.push(Entry::End(ptr::null())); |
| 61 | + } |
| 62 | + } |
| 63 | + } |
| 64 | + // Add an `End` entry to the end with a reference to the enclosing token |
| 65 | + // stream which was passed in. |
| 66 | + entries.push(Entry::End(up)); |
| 67 | + |
| 68 | + // NOTE: This is done to ensure that we don't accidentally modify the |
| 69 | + // length of the backing buffer. The backing buffer must remain at a |
| 70 | + // constant address after this point, as we are going to store a raw |
| 71 | + // pointer into it. |
| 72 | + let mut entries = entries.into_boxed_slice(); |
| 73 | + for (idx, group) in seqs { |
| 74 | + // We know that this index refers to one of the temporary |
| 75 | + // `End(null)` entries, and we know that the last entry is |
| 76 | + // `End(up)`, so the next index is also valid. |
| 77 | + let seq_up = &entries[idx + 1] as *const Entry; |
| 78 | + |
| 79 | + // The end entry stored at the end of this Entry::Group should |
| 80 | + // point to the Entry which follows the Group in the list. |
| 81 | + let inner = Self::inner_new(group.stream(), seq_up); |
| 82 | + entries[idx] = Entry::Group(group, inner); |
| 83 | + } |
| 84 | + |
| 85 | + TokenBuffer { data: entries } |
| 86 | + } |
| 87 | + |
| 88 | + /// Creates a `TokenBuffer` containing all the tokens from the input |
| 89 | + /// `TokenStream`. |
| 90 | + pub fn new(stream: TokenStream) -> TokenBuffer { |
| 91 | + Self::inner_new(stream, ptr::null()) |
| 92 | + } |
| 93 | + |
| 94 | + /// Creates a cursor referencing the first token in the buffer and able to |
| 95 | + /// traverse until the end of the buffer. |
| 96 | + pub fn begin(&self) -> Cursor { |
| 97 | + unsafe { Cursor::create(&self.data[0], &self.data[self.data.len() - 1]) } |
| 98 | + } |
| 99 | +} |
| 100 | + |
| 101 | +/// A cheaply copyable cursor into a `TokenBuffer`. |
| 102 | +/// |
| 103 | +/// This cursor holds a shared reference into the immutable data which is used |
| 104 | +/// internally to represent a `TokenStream`, and can be efficiently manipulated |
| 105 | +/// and copied around. |
| 106 | +/// |
| 107 | +/// An empty `Cursor` can be created directly, or one may create a `TokenBuffer` |
| 108 | +/// object and get a cursor to its first token with `begin()`. |
| 109 | +/// |
| 110 | +/// Two cursors are equal if they have the same location in the same input |
| 111 | +/// stream, and have the same scope. |
| 112 | +/// |
| 113 | +/// *This type is available only if Syn is built with the `"parsing"` feature.* |
| 114 | +pub struct Cursor<'a> { |
| 115 | + // The current entry which the `Cursor` is pointing at. |
| 116 | + ptr: *const Entry, |
| 117 | + // This is the only `Entry::End(..)` object which this cursor is allowed to |
| 118 | + // point at. All other `End` objects are skipped over in `Cursor::create`. |
| 119 | + scope: *const Entry, |
| 120 | + // Cursor is covariant in 'a. This field ensures that our pointers are still |
| 121 | + // valid. |
| 122 | + marker: PhantomData<&'a Entry>, |
| 123 | +} |
| 124 | + |
| 125 | +impl<'a> Cursor<'a> { |
| 126 | + /// Creates a cursor referencing a static empty TokenStream. |
| 127 | + pub fn empty() -> Self { |
| 128 | + // It's safe in this situation for us to put an `Entry` object in global |
| 129 | + // storage, despite it not actually being safe to send across threads |
| 130 | + // (`Ident` is a reference into a thread-local table). This is because |
| 131 | + // this entry never includes a `Ident` object. |
| 132 | + // |
| 133 | + // This wrapper struct allows us to break the rules and put a `Sync` |
| 134 | + // object in global storage. |
| 135 | + struct UnsafeSyncEntry(Entry); |
| 136 | + unsafe impl Sync for UnsafeSyncEntry {} |
| 137 | + static EMPTY_ENTRY: UnsafeSyncEntry = UnsafeSyncEntry(Entry::End(0 as *const Entry)); |
| 138 | + |
| 139 | + Cursor { |
| 140 | + ptr: &EMPTY_ENTRY.0, |
| 141 | + scope: &EMPTY_ENTRY.0, |
| 142 | + marker: PhantomData, |
| 143 | + } |
| 144 | + } |
| 145 | + |
| 146 | + /// This create method intelligently exits non-explicitly-entered |
| 147 | + /// `None`-delimited scopes when the cursor reaches the end of them, |
| 148 | + /// allowing for them to be treated transparently. |
| 149 | + unsafe fn create(mut ptr: *const Entry, scope: *const Entry) -> Self { |
| 150 | + // NOTE: If we're looking at a `End(..)`, we want to advance the cursor |
| 151 | + // past it, unless `ptr == scope`, which means that we're at the edge of |
| 152 | + // our cursor's scope. We should only have `ptr != scope` at the exit |
| 153 | + // from None-delimited groups entered with `ignore_none`. |
| 154 | + while let Entry::End(exit) = *ptr { |
| 155 | + if ptr == scope { |
| 156 | + break; |
| 157 | + } |
| 158 | + ptr = exit; |
| 159 | + } |
| 160 | + |
| 161 | + Cursor { |
| 162 | + ptr, |
| 163 | + scope, |
| 164 | + marker: PhantomData, |
| 165 | + } |
| 166 | + } |
| 167 | + |
| 168 | + /// Get the current entry. |
| 169 | + fn entry(self) -> &'a Entry { |
| 170 | + unsafe { &*self.ptr } |
| 171 | + } |
| 172 | + |
| 173 | + /// Bump the cursor to point at the next token after the current one. This |
| 174 | + /// is undefined behavior if the cursor is currently looking at an |
| 175 | + /// `Entry::End`. |
| 176 | + unsafe fn bump(self) -> Cursor<'a> { |
| 177 | + Cursor::create(self.ptr.offset(1), self.scope) |
| 178 | + } |
| 179 | + |
| 180 | + /// While the cursor is looking at a `None`-delimited group, move it to look |
| 181 | + /// at the first token inside instead. If the group is empty, this will move |
| 182 | + /// the cursor past the `None`-delimited group. |
| 183 | + /// |
| 184 | + /// WARNING: This mutates its argument. |
| 185 | + fn ignore_none(&mut self) { |
| 186 | + while let Entry::Group(group, buf) = self.entry() { |
| 187 | + if group.delimiter() == Delimiter::None { |
| 188 | + // NOTE: We call `Cursor::create` here to make sure that |
| 189 | + // situations where we should immediately exit the span after |
| 190 | + // entering it are handled correctly. |
| 191 | + unsafe { |
| 192 | + *self = Cursor::create(&buf.data[0], self.scope); |
| 193 | + } |
| 194 | + } else { |
| 195 | + break; |
| 196 | + } |
| 197 | + } |
| 198 | + } |
| 199 | + |
| 200 | + /// Checks whether the cursor is currently pointing at the end of its valid |
| 201 | + /// scope. |
| 202 | + pub fn eof(self) -> bool { |
| 203 | + // We're at eof if we're at the end of our scope. |
| 204 | + self.ptr == self.scope |
| 205 | + } |
| 206 | + |
| 207 | + /// If the cursor is pointing at a `Group` with the given delimiter, returns |
| 208 | + /// a cursor into that group and one pointing to the next `TokenTree`. |
| 209 | + pub fn group(mut self, delim: Delimiter) -> Option<(Cursor<'a>, Span, Cursor<'a>)> { |
| 210 | + // If we're not trying to enter a none-delimited group, we want to |
| 211 | + // ignore them. We have to make sure to _not_ ignore them when we want |
| 212 | + // to enter them, of course. For obvious reasons. |
| 213 | + if delim != Delimiter::None { |
| 214 | + self.ignore_none(); |
| 215 | + } |
| 216 | + |
| 217 | + if let Entry::Group(group, buf) = self.entry() { |
| 218 | + if group.delimiter() == delim { |
| 219 | + return Some((buf.begin(), group.span(), unsafe { self.bump() })); |
| 220 | + } |
| 221 | + } |
| 222 | + |
| 223 | + None |
| 224 | + } |
| 225 | + |
| 226 | + /// If the cursor is pointing at a `Ident`, returns it along with a cursor |
| 227 | + /// pointing at the next `TokenTree`. |
| 228 | + pub fn ident(mut self) -> Option<(Ident, Cursor<'a>)> { |
| 229 | + self.ignore_none(); |
| 230 | + match self.entry() { |
| 231 | + Entry::Ident(ident) => Some((ident.clone(), unsafe { self.bump() })), |
| 232 | + _ => None, |
| 233 | + } |
| 234 | + } |
| 235 | + |
| 236 | + /// If the cursor is pointing at an `Punct`, returns it along with a cursor |
| 237 | + /// pointing at the next `TokenTree`. |
| 238 | + pub fn punct(mut self) -> Option<(Punct, Cursor<'a>)> { |
| 239 | + self.ignore_none(); |
| 240 | + match self.entry() { |
| 241 | + Entry::Punct(op) if op.as_char() != '\'' => Some((op.clone(), unsafe { self.bump() })), |
| 242 | + _ => None, |
| 243 | + } |
| 244 | + } |
| 245 | + |
| 246 | + /// If the cursor is pointing at a `Literal`, return it along with a cursor |
| 247 | + /// pointing at the next `TokenTree`. |
| 248 | + pub fn literal(mut self) -> Option<(Literal, Cursor<'a>)> { |
| 249 | + self.ignore_none(); |
| 250 | + match self.entry() { |
| 251 | + Entry::Literal(lit) => Some((lit.clone(), unsafe { self.bump() })), |
| 252 | + _ => None, |
| 253 | + } |
| 254 | + } |
| 255 | + |
| 256 | + /// Copies all remaining tokens visible from this cursor into a |
| 257 | + /// `TokenStream`. |
| 258 | + pub fn token_stream(self) -> TokenStream { |
| 259 | + let mut tts = Vec::new(); |
| 260 | + let mut cursor = self; |
| 261 | + while let Some((tt, rest)) = cursor.token_tree() { |
| 262 | + tts.push(tt); |
| 263 | + cursor = rest; |
| 264 | + } |
| 265 | + tts.into_iter().collect() |
| 266 | + } |
| 267 | + |
| 268 | + /// If the cursor is pointing at a `TokenTree`, returns it along with a |
| 269 | + /// cursor pointing at the next `TokenTree`. |
| 270 | + /// |
| 271 | + /// Returns `None` if the cursor has reached the end of its stream. |
| 272 | + /// |
| 273 | + /// This method does not treat `None`-delimited groups as transparent, and |
| 274 | + /// will return a `Group(None, ..)` if the cursor is looking at one. |
| 275 | + pub fn token_tree(self) -> Option<(TokenTree, Cursor<'a>)> { |
| 276 | + let tree = match self.entry() { |
| 277 | + Entry::Group(group, _) => group.clone().into(), |
| 278 | + Entry::Literal(lit) => lit.clone().into(), |
| 279 | + Entry::Ident(ident) => ident.clone().into(), |
| 280 | + Entry::Punct(op) => op.clone().into(), |
| 281 | + Entry::End(..) => { |
| 282 | + return None; |
| 283 | + } |
| 284 | + }; |
| 285 | + |
| 286 | + Some((tree, unsafe { self.bump() })) |
| 287 | + } |
| 288 | + |
| 289 | + /// Returns the `Span` of the current token, or `Span::call_site()` if this |
| 290 | + /// cursor points to eof. |
| 291 | + pub fn span(self) -> Span { |
| 292 | + match self.entry() { |
| 293 | + Entry::Group(group, _) => group.span(), |
| 294 | + Entry::Literal(l) => l.span(), |
| 295 | + Entry::Ident(t) => t.span(), |
| 296 | + Entry::Punct(o) => o.span(), |
| 297 | + Entry::End(..) => Span::call_site(), |
| 298 | + } |
| 299 | + } |
| 300 | +} |
| 301 | + |
| 302 | +impl<'a> Copy for Cursor<'a> {} |
| 303 | + |
| 304 | +impl<'a> Clone for Cursor<'a> { |
| 305 | + fn clone(&self) -> Self { |
| 306 | + *self |
| 307 | + } |
| 308 | +} |
| 309 | + |
| 310 | +impl<'a> Eq for Cursor<'a> {} |
| 311 | + |
| 312 | +impl<'a> PartialEq for Cursor<'a> { |
| 313 | + fn eq(&self, other: &Self) -> bool { |
| 314 | + let Cursor { ptr, scope, marker } = self; |
| 315 | + let _ = marker; |
| 316 | + *ptr == other.ptr && *scope == other.scope |
| 317 | + } |
| 318 | +} |
0 commit comments