diff options
Diffstat (limited to 'crates/tt/src/buffer.rs')
-rw-r--r-- | crates/tt/src/buffer.rs | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/crates/tt/src/buffer.rs b/crates/tt/src/buffer.rs new file mode 100644 index 000000000..02c771f70 --- /dev/null +++ b/crates/tt/src/buffer.rs | |||
@@ -0,0 +1,185 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use crate::{Subtree, TokenTree}; | ||
4 | |||
5 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] | ||
6 | struct EntryId(usize); | ||
7 | |||
8 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] | ||
9 | struct EntryPtr(EntryId, usize); | ||
10 | |||
11 | /// Internal type which is used instead of `TokenTree` to represent a token tree | ||
12 | /// within a `TokenBuffer`. | ||
13 | #[derive(Debug)] | ||
14 | enum Entry<'t> { | ||
15 | // Mimicking types from proc-macro. | ||
16 | Subtree(&'t TokenTree, EntryId), | ||
17 | Leaf(&'t TokenTree), | ||
18 | // End entries contain a pointer to the entry from the containing | ||
19 | // token tree, or None if this is the outermost level. | ||
20 | End(Option<EntryPtr>), | ||
21 | } | ||
22 | |||
23 | /// A token tree buffer | ||
24 | /// The safe version of `syn` [`TokenBuffer`](https://github.com/dtolnay/syn/blob/6533607f91686545cb034d2838beea338d9d0742/src/buffer.rs#L41) | ||
25 | #[derive(Debug)] | ||
26 | pub struct TokenBuffer<'t> { | ||
27 | buffers: Vec<Box<[Entry<'t>]>>, | ||
28 | } | ||
29 | |||
30 | impl<'t> TokenBuffer<'t> { | ||
31 | pub fn new(tokens: &'t [TokenTree]) -> TokenBuffer<'t> { | ||
32 | let mut buffers = vec![]; | ||
33 | |||
34 | let idx = TokenBuffer::new_inner(tokens, &mut buffers, None); | ||
35 | assert_eq!(idx, 0); | ||
36 | |||
37 | TokenBuffer { buffers } | ||
38 | } | ||
39 | |||
40 | fn new_inner( | ||
41 | tokens: &'t [TokenTree], | ||
42 | buffers: &mut Vec<Box<[Entry<'t>]>>, | ||
43 | next: Option<EntryPtr>, | ||
44 | ) -> usize { | ||
45 | // Must contain everything in tokens and then the Entry::End | ||
46 | let start_capacity = tokens.len() + 1; | ||
47 | let mut entries = Vec::with_capacity(start_capacity); | ||
48 | let mut children = vec![]; | ||
49 | |||
50 | for (idx, tt) in tokens.iter().enumerate() { | ||
51 | match tt { | ||
52 | TokenTree::Leaf(_) => { | ||
53 | entries.push(Entry::Leaf(tt)); | ||
54 | } | ||
55 | TokenTree::Subtree(subtree) => { | ||
56 | entries.push(Entry::End(None)); | ||
57 | children.push((idx, (subtree, tt))); | ||
58 | } | ||
59 | } | ||
60 | } | ||
61 | |||
62 | entries.push(Entry::End(next)); | ||
63 | let res = buffers.len(); | ||
64 | buffers.push(entries.into_boxed_slice()); | ||
65 | |||
66 | for (child_idx, (subtree, tt)) in children { | ||
67 | let idx = TokenBuffer::new_inner( | ||
68 | &subtree.token_trees, | ||
69 | buffers, | ||
70 | Some(EntryPtr(EntryId(res), child_idx + 1)), | ||
71 | ); | ||
72 | buffers[res].as_mut()[child_idx] = Entry::Subtree(tt, EntryId(idx)); | ||
73 | } | ||
74 | |||
75 | res | ||
76 | } | ||
77 | |||
78 | /// Creates a cursor referencing the first token in the buffer and able to | ||
79 | /// traverse until the end of the buffer. | ||
80 | pub fn begin(&self) -> Cursor { | ||
81 | Cursor::create(self, EntryPtr(EntryId(0), 0)) | ||
82 | } | ||
83 | |||
84 | fn entry(&self, ptr: &EntryPtr) -> Option<&Entry> { | ||
85 | let id = ptr.0; | ||
86 | self.buffers[id.0].get(ptr.1) | ||
87 | } | ||
88 | } | ||
89 | |||
90 | /// A safe version of `Cursor` from `syn` crate https://github.com/dtolnay/syn/blob/6533607f91686545cb034d2838beea338d9d0742/src/buffer.rs#L125 | ||
91 | #[derive(Copy, Clone, Debug)] | ||
92 | pub struct Cursor<'a> { | ||
93 | buffer: &'a TokenBuffer<'a>, | ||
94 | ptr: EntryPtr, | ||
95 | } | ||
96 | |||
97 | impl<'a> PartialEq for Cursor<'a> { | ||
98 | fn eq(&self, other: &Cursor) -> bool { | ||
99 | self.ptr == other.ptr && std::ptr::eq(self.buffer, other.buffer) | ||
100 | } | ||
101 | } | ||
102 | |||
103 | impl<'a> Eq for Cursor<'a> {} | ||
104 | |||
105 | impl<'a> Cursor<'a> { | ||
106 | /// Check whether it is eof | ||
107 | pub fn eof(self) -> bool { | ||
108 | matches!(self.buffer.entry(&self.ptr), None | Some(Entry::End(None))) | ||
109 | } | ||
110 | |||
111 | /// If the cursor is pointing at the end of a subtree, returns | ||
112 | /// the parent subtree | ||
113 | pub fn end(self) -> Option<&'a Subtree> { | ||
114 | match self.entry() { | ||
115 | Some(Entry::End(Some(ptr))) => { | ||
116 | let idx = ptr.1; | ||
117 | if let Some(Entry::Subtree(TokenTree::Subtree(subtree), _)) = | ||
118 | self.buffer.entry(&EntryPtr(ptr.0, idx - 1)) | ||
119 | { | ||
120 | return Some(subtree); | ||
121 | } | ||
122 | |||
123 | None | ||
124 | } | ||
125 | _ => None, | ||
126 | } | ||
127 | } | ||
128 | |||
129 | fn entry(self) -> Option<&'a Entry<'a>> { | ||
130 | self.buffer.entry(&self.ptr) | ||
131 | } | ||
132 | |||
133 | /// If the cursor is pointing at a `Subtree`, returns | ||
134 | /// a cursor into that subtree | ||
135 | pub fn subtree(self) -> Option<Cursor<'a>> { | ||
136 | match self.entry() { | ||
137 | Some(Entry::Subtree(_, entry_id)) => { | ||
138 | Some(Cursor::create(self.buffer, EntryPtr(*entry_id, 0))) | ||
139 | } | ||
140 | _ => None, | ||
141 | } | ||
142 | } | ||
143 | |||
144 | /// If the cursor is pointing at a `TokenTree`, returns it | ||
145 | pub fn token_tree(self) -> Option<&'a TokenTree> { | ||
146 | match self.entry() { | ||
147 | Some(Entry::Leaf(tt)) => Some(tt), | ||
148 | Some(Entry::Subtree(tt, _)) => Some(tt), | ||
149 | Some(Entry::End(_)) => None, | ||
150 | None => None, | ||
151 | } | ||
152 | } | ||
153 | |||
154 | fn create(buffer: &'a TokenBuffer, ptr: EntryPtr) -> Cursor<'a> { | ||
155 | Cursor { buffer, ptr } | ||
156 | } | ||
157 | |||
158 | /// Bump the cursor | ||
159 | pub fn bump(self) -> Cursor<'a> { | ||
160 | if let Some(Entry::End(exit)) = self.buffer.entry(&self.ptr) { | ||
161 | if let Some(exit) = exit { | ||
162 | Cursor::create(self.buffer, *exit) | ||
163 | } else { | ||
164 | self | ||
165 | } | ||
166 | } else { | ||
167 | Cursor::create(self.buffer, EntryPtr(self.ptr.0, self.ptr.1 + 1)) | ||
168 | } | ||
169 | } | ||
170 | |||
171 | /// Bump the cursor, if it is a subtree, returns | ||
172 | /// a cursor into that subtree | ||
173 | pub fn bump_subtree(self) -> Cursor<'a> { | ||
174 | match self.entry() { | ||
175 | Some(Entry::Subtree(_, _)) => self.subtree().unwrap(), | ||
176 | _ => self.bump(), | ||
177 | } | ||
178 | } | ||
179 | |||
180 | /// Check whether it is a top level | ||
181 | pub fn is_root(&self) -> bool { | ||
182 | let entry_id = self.ptr.0; | ||
183 | entry_id.0 == 0 | ||
184 | } | ||
185 | } | ||