blob: cf229966078dfe8338d93abf3d9aaa8b4a8a1e23 [file] [log] [blame]
Michael Layzell2a60e252017-05-31 21:36:47 -04001//! This module defines a cheaply-copyable cursor into a TokenStream's data.
2//!
3//! It does this by copying the data into a stably-addressed structured buffer,
4//! and holding raw pointers into that buffer to allow walking through delimited
David Tolnayc10676a2017-12-27 23:42:36 -05005//! groups cheaply.
Michael Layzell2a60e252017-05-31 21:36:47 -04006//!
7//! This module is heavily commented as it contains the only unsafe code in
8//! `syn`, and caution should be made when editing it. It provides a safe
9//! interface, but is fragile internally.
10
11use proc_macro2::*;
12
13use std::ptr;
Michael Layzell2a60e252017-05-31 21:36:47 -040014use std::marker::PhantomData;
15
David Tolnayf9e1de12017-12-31 00:47:01 -050016#[cfg(all(feature = "verbose-trace", not(feature = "all-features")))]
17use std::fmt::{self, Debug};
18
Michael Layzell2a60e252017-05-31 21:36:47 -040019/// Internal type which is used instead of `TokenTree` to represent a single
20/// `TokenTree` within a `SynomBuffer`.
Michael Layzell2a60e252017-05-31 21:36:47 -040021enum Entry {
22 /// Mimicing types from proc-macro.
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -070023 Group(Span, Delimiter, SynomBuffer),
24 Term(Span, Term),
25 Op(Span, char, Spacing),
Michael Layzell2a60e252017-05-31 21:36:47 -040026 Literal(Span, Literal),
27 /// End entries contain a raw pointer to the entry from the containing
28 /// TokenTree.
29 End(*const Entry),
30}
31
Michael Layzell2a60e252017-05-31 21:36:47 -040032/// A buffer of data which contains a structured representation of the input
33/// `TokenStream` object.
Michael Layzell2a60e252017-05-31 21:36:47 -040034pub struct SynomBuffer {
35 // NOTE: Do not derive clone on this - there are raw pointers inside which
36 // will be messed up. Moving the `SynomBuffer` itself is safe as the actual
37 // backing slices won't be moved.
38 data: Box<[Entry]>,
39}
40
41impl SynomBuffer {
42 // NOTE: DO NOT MUTATE THE `Vec` RETURNED FROM THIS FUNCTION ONCE IT
43 // RETURNS, THE ADDRESS OF ITS BACKING MEMORY MUST REMAIN STABLE.
44 fn inner_new(stream: TokenStream, up: *const Entry) -> SynomBuffer {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -070045 // Build up the entries list, recording the locations of any Groups
Michael Layzell2a60e252017-05-31 21:36:47 -040046 // in the list to be processed later.
47 let mut entries = Vec::new();
48 let mut seqs = Vec::new();
David Tolnay50fa4682017-12-26 23:17:22 -050049 for tt in stream {
Michael Layzell2a60e252017-05-31 21:36:47 -040050 match tt.kind {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -070051 TokenNode::Term(sym) => {
52 entries.push(Entry::Term(tt.span, sym));
Michael Layzell2a60e252017-05-31 21:36:47 -040053 }
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -070054 TokenNode::Op(chr, ok) => {
Michael Layzell2a60e252017-05-31 21:36:47 -040055 entries.push(Entry::Op(tt.span, chr, ok));
56 }
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -070057 TokenNode::Literal(lit) => {
Michael Layzell2a60e252017-05-31 21:36:47 -040058 entries.push(Entry::Literal(tt.span, lit));
59 }
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -070060 TokenNode::Group(delim, seq_stream) => {
Michael Layzell2a60e252017-05-31 21:36:47 -040061 // Record the index of the interesting entry, and store an
62 // `End(null)` there temporarially.
63 seqs.push((entries.len(), tt.span, delim, seq_stream));
64 entries.push(Entry::End(ptr::null()));
65 }
66 }
67 }
68 // Add an `End` entry to the end with a reference to the enclosing token
69 // stream which was passed in.
70 entries.push(Entry::End(up));
71
72 // NOTE: This is done to ensure that we don't accidentally modify the
73 // length of the backing buffer. The backing buffer must remain at a
74 // constant address after this point, as we are going to store a raw
75 // pointer into it.
76 let mut entries = entries.into_boxed_slice();
77 for (idx, span, delim, seq_stream) in seqs {
78 // We know that this index refers to one of the temporary
79 // `End(null)` entries, and we know that the last entry is
80 // `End(up)`, so the next index is also valid.
81 let seq_up = &entries[idx + 1] as *const Entry;
82
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -070083 // The end entry stored at the end of this Entry::Group should
84 // point to the Entry which follows the Group in the list.
Michael Layzell2a60e252017-05-31 21:36:47 -040085 let inner = Self::inner_new(seq_stream, seq_up);
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -070086 entries[idx] = Entry::Group(span, delim, inner);
Michael Layzell2a60e252017-05-31 21:36:47 -040087 }
88
David Tolnay51382052017-12-27 13:46:21 -050089 SynomBuffer { data: entries }
Michael Layzell2a60e252017-05-31 21:36:47 -040090 }
91
92 /// Create a new SynomBuffer, which contains the data from the given
93 /// TokenStream.
94 pub fn new(stream: TokenStream) -> SynomBuffer {
95 Self::inner_new(stream, ptr::null())
96 }
97
98 /// Create a cursor referencing the first token in the input.
99 pub fn begin(&self) -> Cursor {
David Tolnay51382052017-12-27 13:46:21 -0500100 unsafe { Cursor::create(&self.data[0], &self.data[self.data.len() - 1]) }
Michael Layzell2a60e252017-05-31 21:36:47 -0400101 }
102}
103
Michael Layzell2a60e252017-05-31 21:36:47 -0400104/// A cursor into an input `TokenStream`'s data. This cursor holds a reference
105/// into the immutable data which is used internally to represent a
106/// `TokenStream`, and can be efficiently manipulated and copied around.
107///
108/// An empty `Cursor` can be created directly, or one may create a `SynomBuffer`
109/// object and get a cursor to its first token with `begin()`.
110///
111/// Two cursors are equal if they have the same location in the same input
112/// stream, and have the same scope.
113#[derive(Copy, Clone, Eq, PartialEq)]
114pub 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 /// This uses the &'a reference which guarantees that these pointers are
121 /// still valid.
122 marker: PhantomData<&'a Entry>,
123}
124
Michael Layzell2a60e252017-05-31 21:36:47 -0400125impl<'a> Cursor<'a> {
126 /// Create a cursor referencing a static empty TokenStream.
127 pub fn empty() -> Self {
Michael Layzell69cf9082017-06-03 12:15:58 -0400128 // 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
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700130 // (`Term` is a reference into a thread-local table). This is because
131 // this entry never includes a `Term` object.
Michael Layzell69cf9082017-06-03 12:15:58 -0400132 //
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 {}
David Tolnay51382052017-12-27 13:46:21 -0500137 static EMPTY_ENTRY: UnsafeSyncEntry = UnsafeSyncEntry(Entry::End(0 as *const Entry));
Michael Layzell69cf9082017-06-03 12:15:58 -0400138
Michael Layzell2a60e252017-05-31 21:36:47 -0400139 Cursor {
Michael Layzell69cf9082017-06-03 12:15:58 -0400140 ptr: &EMPTY_ENTRY.0,
141 scope: &EMPTY_ENTRY.0,
Michael Layzell2a60e252017-05-31 21:36:47 -0400142 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
David Tolnayc10676a2017-12-27 23:42:36 -0500153 // from None-delimited groups entered with `ignore_none`.
Michael Layzell2a60e252017-05-31 21:36:47 -0400154 while let Entry::End(exit) = *ptr {
155 if ptr == scope {
156 break;
157 }
158 ptr = exit;
159 }
160
161 Cursor {
162 ptr: ptr,
163 scope: 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
David Tolnayc10676a2017-12-27 23:42:36 -0500180 /// If the cursor is looking at a `None`-delimited group, move it to look at
181 /// the first token inside instead. If the group is empty, this will move
182 /// the cursor past the `None`-delimited group.
Michael Layzell2a60e252017-05-31 21:36:47 -0400183 ///
184 /// WARNING: This mutates its argument.
185 fn ignore_none(&mut self) {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700186 if let Entry::Group(_, Delimiter::None, ref buf) = *self.entry() {
Michael Layzell2a60e252017-05-31 21:36:47 -0400187 // NOTE: We call `Cursor::create` here to make sure that situations
188 // where we should immediately exit the span after entering it are
189 // handled correctly.
190 unsafe {
191 *self = Cursor::create(&buf.data[0], self.scope);
192 }
193 }
194 }
195
196 /// Check if the cursor is currently pointing at the end of its valid scope.
197 #[inline]
198 pub fn eof(self) -> bool {
199 // We're at eof if we're at the end of our scope.
200 self.ptr == self.scope
201 }
202
David Tolnayc10676a2017-12-27 23:42:36 -0500203 /// If the cursor is pointing at a Group with the given `Delimiter`, return
204 /// a cursor into that group, and one pointing to the next `TokenTree`.
David Tolnay65729482017-12-31 16:14:50 -0500205 pub fn group(mut self, delim: Delimiter) -> Option<(Cursor<'a>, Span, Cursor<'a>)> {
David Tolnayc10676a2017-12-27 23:42:36 -0500206 // If we're not trying to enter a none-delimited group, we want to
Michael Layzell2a60e252017-05-31 21:36:47 -0400207 // ignore them. We have to make sure to _not_ ignore them when we want
208 // to enter them, of course. For obvious reasons.
David Tolnayc10676a2017-12-27 23:42:36 -0500209 if delim != Delimiter::None {
Michael Layzell2a60e252017-05-31 21:36:47 -0400210 self.ignore_none();
211 }
212
David Tolnayc10676a2017-12-27 23:42:36 -0500213 if let Entry::Group(span, group_delim, ref buf) = *self.entry() {
214 if group_delim == delim {
David Tolnay65729482017-12-31 16:14:50 -0500215 return Some((buf.begin(), span, unsafe { self.bump() }));
Michael Layzell2a60e252017-05-31 21:36:47 -0400216 }
Michael Layzell2a60e252017-05-31 21:36:47 -0400217 }
David Tolnayc10676a2017-12-27 23:42:36 -0500218
219 None
Michael Layzell2a60e252017-05-31 21:36:47 -0400220 }
221
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700222 /// If the cursor is pointing at a Term, return it and a cursor pointing at
Michael Layzell2a60e252017-05-31 21:36:47 -0400223 /// the next `TokenTree`.
David Tolnay65729482017-12-31 16:14:50 -0500224 pub fn term(mut self) -> Option<(Span, Term, Cursor<'a>)> {
Michael Layzell2a60e252017-05-31 21:36:47 -0400225 self.ignore_none();
226 match *self.entry() {
David Tolnay65729482017-12-31 16:14:50 -0500227 Entry::Term(span, term) => Some((span, term, unsafe { self.bump() })),
David Tolnay51382052017-12-27 13:46:21 -0500228 _ => None,
Michael Layzell2a60e252017-05-31 21:36:47 -0400229 }
230 }
231
232 /// If the cursor is pointing at an Op, return it and a cursor pointing
233 /// at the next `TokenTree`.
David Tolnay65729482017-12-31 16:14:50 -0500234 pub fn op(mut self) -> Option<(Span, char, Spacing, Cursor<'a>)> {
Michael Layzell2a60e252017-05-31 21:36:47 -0400235 self.ignore_none();
236 match *self.entry() {
David Tolnay65729482017-12-31 16:14:50 -0500237 Entry::Op(span, op, spacing) => Some((span, op, spacing, unsafe { self.bump() })),
David Tolnay51382052017-12-27 13:46:21 -0500238 _ => None,
Michael Layzell2a60e252017-05-31 21:36:47 -0400239 }
240 }
241
242 /// If the cursor is pointing at a Literal, return it and a cursor pointing
243 /// at the next `TokenTree`.
David Tolnay65729482017-12-31 16:14:50 -0500244 pub fn literal(mut self) -> Option<(Span, Literal, Cursor<'a>)> {
Michael Layzell2a60e252017-05-31 21:36:47 -0400245 self.ignore_none();
246 match *self.entry() {
David Tolnay65729482017-12-31 16:14:50 -0500247 Entry::Literal(span, ref lit) => Some((span, lit.clone(), unsafe { self.bump() })),
David Tolnay51382052017-12-27 13:46:21 -0500248 _ => None,
Michael Layzell2a60e252017-05-31 21:36:47 -0400249 }
250 }
251
252 /// Copy all remaining tokens visible from this cursor into a `TokenStream`.
253 pub fn token_stream(self) -> TokenStream {
254 let mut tts = Vec::new();
255 let mut cursor = self;
David Tolnay65729482017-12-31 16:14:50 -0500256 while let Some((tt, rest)) = cursor.token_tree() {
Michael Layzell2a60e252017-05-31 21:36:47 -0400257 tts.push(tt);
David Tolnay65729482017-12-31 16:14:50 -0500258 cursor = rest;
Michael Layzell2a60e252017-05-31 21:36:47 -0400259 }
260 tts.into_iter().collect()
261 }
262
263 /// If the cursor is looking at a `TokenTree`, returns it along with a
David Tolnayc10676a2017-12-27 23:42:36 -0500264 /// cursor pointing to the next token in the group, otherwise returns
Michael Layzell2a60e252017-05-31 21:36:47 -0400265 /// `None`.
266 ///
David Tolnayc10676a2017-12-27 23:42:36 -0500267 /// This method does not treat `None`-delimited groups as invisible, and
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700268 /// will return a `Group(None, ..)` if the cursor is looking at one.
David Tolnay65729482017-12-31 16:14:50 -0500269 pub fn token_tree(self) -> Option<(TokenTree, Cursor<'a>)> {
Michael Layzell2a60e252017-05-31 21:36:47 -0400270 let tree = match *self.entry() {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700271 Entry::Group(span, delim, ref buf) => {
Michael Layzell2a60e252017-05-31 21:36:47 -0400272 let stream = buf.begin().token_stream();
273 TokenTree {
274 span: span,
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700275 kind: TokenNode::Group(delim, stream),
Michael Layzell2a60e252017-05-31 21:36:47 -0400276 }
277 }
David Tolnay51382052017-12-27 13:46:21 -0500278 Entry::Literal(span, ref lit) => TokenTree {
279 span: span,
280 kind: TokenNode::Literal(lit.clone()),
281 },
282 Entry::Term(span, sym) => TokenTree {
283 span: span,
284 kind: TokenNode::Term(sym),
285 },
David Tolnay73c98de2017-12-31 15:56:56 -0500286 Entry::Op(span, chr, spacing) => TokenTree {
David Tolnay51382052017-12-27 13:46:21 -0500287 span: span,
David Tolnay73c98de2017-12-31 15:56:56 -0500288 kind: TokenNode::Op(chr, spacing),
David Tolnay51382052017-12-27 13:46:21 -0500289 },
Michael Layzell2a60e252017-05-31 21:36:47 -0400290 Entry::End(..) => {
291 return None;
292 }
293 };
294
David Tolnay65729482017-12-31 16:14:50 -0500295 Some((tree, unsafe { self.bump() }))
Michael Layzell2a60e252017-05-31 21:36:47 -0400296 }
David Tolnay225efa22017-12-31 16:51:29 -0500297
298 /// Returns the `Span` of the current token, or `Span::call_site()` if this
299 /// cursor points to eof.
300 pub fn span(self) -> Span {
301 match *self.entry() {
302 Entry::Group(span, ..) => span,
303 Entry::Literal(span, ..) => span,
304 Entry::Term(span, ..) => span,
305 Entry::Op(span, ..) => span,
306 Entry::End(..) => Span::call_site(),
307 }
308 }
Michael Layzell2a60e252017-05-31 21:36:47 -0400309}
310
311// We do a custom implementation for `Debug` as the default implementation is
312// pretty useless.
David Tolnayf9e1de12017-12-31 00:47:01 -0500313#[cfg(all(feature = "verbose-trace", not(feature = "all-features")))]
314impl<'a> Debug for Cursor<'a> {
Michael Layzell2a60e252017-05-31 21:36:47 -0400315 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Nika Layzellae81b372017-12-05 14:12:33 -0500316 // Print what the cursor is currently looking at.
317 // This will look like Cursor("some remaining tokens here")
318 f.debug_tuple("Cursor")
319 .field(&self.token_stream().to_string())
Michael Layzell2a60e252017-05-31 21:36:47 -0400320 .finish()
321 }
322}