1 //! `tt` crate defines a `TokenTree` data structure: this is the interface (both
2 //! input and output) of macros. It closely mirrors `proc_macro` crate's
3 //! `TokenTree`.
4
5 #![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
6
7 use std::fmt;
8
9 use stdx::impl_from;
10
11 pub use smol_str::SmolStr;
12
13 /// Represents identity of the token.
14 ///
15 /// For hygiene purposes, we need to track which expanded tokens originated from
16 /// which source tokens. We do it by assigning an distinct identity to each
17 /// source token and making sure that identities are preserved during macro
18 /// expansion.
19 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
20 pub struct TokenId(pub u32);
21
22 impl fmt::Debug for TokenId {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 self.0.fmt(f)
25 }
26 }
27
28 impl TokenId {
29 pub const UNSPECIFIED: TokenId = TokenId(!0);
unspecified() -> TokenId30 pub const fn unspecified() -> TokenId {
31 Self::UNSPECIFIED
32 }
33 }
34
35 pub mod token_id {
36 pub use crate::{DelimiterKind, Spacing, TokenId};
37 pub type Span = crate::TokenId;
38 pub type Subtree = crate::Subtree<Span>;
39 pub type Punct = crate::Punct<Span>;
40 pub type Delimiter = crate::Delimiter<Span>;
41 pub type Leaf = crate::Leaf<Span>;
42 pub type Ident = crate::Ident<Span>;
43 pub type Literal = crate::Literal<Span>;
44 pub type TokenTree = crate::TokenTree<Span>;
45 pub mod buffer {
46 pub type TokenBuffer<'a> = crate::buffer::TokenBuffer<'a, super::Span>;
47 pub type Cursor<'a> = crate::buffer::Cursor<'a, super::Span>;
48 pub type TokenTreeRef<'a> = crate::buffer::TokenTreeRef<'a, super::Span>;
49 }
50
51 impl Delimiter {
52 pub const UNSPECIFIED: Self = Self {
53 open: TokenId::UNSPECIFIED,
54 close: TokenId::UNSPECIFIED,
55 kind: DelimiterKind::Invisible,
56 };
unspecified() -> Self57 pub const fn unspecified() -> Self {
58 Self::UNSPECIFIED
59 }
60 }
61 impl Subtree {
empty() -> Self62 pub const fn empty() -> Self {
63 Subtree { delimiter: Delimiter::unspecified(), token_trees: vec![] }
64 }
65 }
66 impl TokenTree {
empty() -> Self67 pub const fn empty() -> Self {
68 Self::Subtree(Subtree { delimiter: Delimiter::unspecified(), token_trees: vec![] })
69 }
70 }
71 }
72
73 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
74 pub struct SyntaxContext(pub u32);
75
76 // #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
77 // pub struct Span {
78 // pub id: TokenId,
79 // pub ctx: SyntaxContext,
80 // }
81 // pub type Span = (TokenId, SyntaxContext);
82
83 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
84 pub enum TokenTree<Span> {
85 Leaf(Leaf<Span>),
86 Subtree(Subtree<Span>),
87 }
88 impl_from!(Leaf<Span>, Subtree<Span> for TokenTree);
89
90 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
91 pub enum Leaf<Span> {
92 Literal(Literal<Span>),
93 Punct(Punct<Span>),
94 Ident(Ident<Span>),
95 }
96
97 impl<Span> Leaf<Span> {
span(&self) -> &Span98 pub fn span(&self) -> &Span {
99 match self {
100 Leaf::Literal(it) => &it.span,
101 Leaf::Punct(it) => &it.span,
102 Leaf::Ident(it) => &it.span,
103 }
104 }
105 }
106 impl_from!(Literal<Span>, Punct<Span>, Ident<Span> for Leaf);
107
108 #[derive(Clone, PartialEq, Eq, Hash)]
109 pub struct Subtree<Span> {
110 // FIXME, this should not be Option
111 pub delimiter: Delimiter<Span>,
112 pub token_trees: Vec<TokenTree<Span>>,
113 }
114
115 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
116 pub struct Delimiter<Span> {
117 pub open: Span,
118 pub close: Span,
119 pub kind: DelimiterKind,
120 }
121
122 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
123 pub enum DelimiterKind {
124 Parenthesis,
125 Brace,
126 Bracket,
127 Invisible,
128 }
129
130 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
131 pub struct Literal<Span> {
132 pub text: SmolStr,
133 pub span: Span,
134 }
135
136 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
137 pub struct Punct<Span> {
138 pub char: char,
139 pub spacing: Spacing,
140 pub span: Span,
141 }
142
143 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
144 pub enum Spacing {
145 Alone,
146 Joint,
147 }
148
149 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
150 /// Identifier or keyword. Unlike rustc, we keep "r#" prefix when it represents a raw identifier.
151 pub struct Ident<Span> {
152 pub text: SmolStr,
153 pub span: Span,
154 }
155
156 impl<S> Ident<S> {
new(text: impl Into<SmolStr>, span: S) -> Self157 pub fn new(text: impl Into<SmolStr>, span: S) -> Self {
158 Ident { text: text.into(), span }
159 }
160 }
161
print_debug_subtree<Span: fmt::Debug>( f: &mut fmt::Formatter<'_>, subtree: &Subtree<Span>, level: usize, ) -> fmt::Result162 fn print_debug_subtree<Span: fmt::Debug>(
163 f: &mut fmt::Formatter<'_>,
164 subtree: &Subtree<Span>,
165 level: usize,
166 ) -> fmt::Result {
167 let align = " ".repeat(level);
168
169 let Delimiter { kind, open, close } = &subtree.delimiter;
170 let aux = match kind {
171 DelimiterKind::Invisible => format!("$$ {:?} {:?}", open, close),
172 DelimiterKind::Parenthesis => format!("() {:?} {:?}", open, close),
173 DelimiterKind::Brace => format!("{{}} {:?} {:?}", open, close),
174 DelimiterKind::Bracket => format!("[] {:?} {:?}", open, close),
175 };
176
177 if subtree.token_trees.is_empty() {
178 write!(f, "{align}SUBTREE {aux}")?;
179 } else {
180 writeln!(f, "{align}SUBTREE {aux}")?;
181 for (idx, child) in subtree.token_trees.iter().enumerate() {
182 print_debug_token(f, child, level + 1)?;
183 if idx != subtree.token_trees.len() - 1 {
184 writeln!(f)?;
185 }
186 }
187 }
188
189 Ok(())
190 }
191
print_debug_token<Span: fmt::Debug>( f: &mut fmt::Formatter<'_>, tkn: &TokenTree<Span>, level: usize, ) -> fmt::Result192 fn print_debug_token<Span: fmt::Debug>(
193 f: &mut fmt::Formatter<'_>,
194 tkn: &TokenTree<Span>,
195 level: usize,
196 ) -> fmt::Result {
197 let align = " ".repeat(level);
198
199 match tkn {
200 TokenTree::Leaf(leaf) => match leaf {
201 Leaf::Literal(lit) => write!(f, "{}LITERAL {} {:?}", align, lit.text, lit.span)?,
202 Leaf::Punct(punct) => write!(
203 f,
204 "{}PUNCH {} [{}] {:?}",
205 align,
206 punct.char,
207 if punct.spacing == Spacing::Alone { "alone" } else { "joint" },
208 punct.span
209 )?,
210 Leaf::Ident(ident) => write!(f, "{}IDENT {} {:?}", align, ident.text, ident.span)?,
211 },
212 TokenTree::Subtree(subtree) => {
213 print_debug_subtree(f, subtree, level)?;
214 }
215 }
216
217 Ok(())
218 }
219
220 impl<Span: fmt::Debug> fmt::Debug for Subtree<Span> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result221 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222 print_debug_subtree(f, self, 0)
223 }
224 }
225
226 impl<Span> fmt::Display for TokenTree<Span> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result227 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228 match self {
229 TokenTree::Leaf(it) => fmt::Display::fmt(it, f),
230 TokenTree::Subtree(it) => fmt::Display::fmt(it, f),
231 }
232 }
233 }
234
235 impl<Span> fmt::Display for Subtree<Span> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result236 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237 let (l, r) = match self.delimiter.kind {
238 DelimiterKind::Parenthesis => ("(", ")"),
239 DelimiterKind::Brace => ("{", "}"),
240 DelimiterKind::Bracket => ("[", "]"),
241 DelimiterKind::Invisible => ("", ""),
242 };
243 f.write_str(l)?;
244 let mut needs_space = false;
245 for tt in &self.token_trees {
246 if needs_space {
247 f.write_str(" ")?;
248 }
249 needs_space = true;
250 match tt {
251 TokenTree::Leaf(Leaf::Punct(p)) => {
252 needs_space = p.spacing == Spacing::Alone;
253 fmt::Display::fmt(p, f)?;
254 }
255 tt => fmt::Display::fmt(tt, f)?,
256 }
257 }
258 f.write_str(r)?;
259 Ok(())
260 }
261 }
262
263 impl<Span> fmt::Display for Leaf<Span> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result264 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
265 match self {
266 Leaf::Ident(it) => fmt::Display::fmt(it, f),
267 Leaf::Literal(it) => fmt::Display::fmt(it, f),
268 Leaf::Punct(it) => fmt::Display::fmt(it, f),
269 }
270 }
271 }
272
273 impl<Span> fmt::Display for Ident<Span> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result274 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
275 fmt::Display::fmt(&self.text, f)
276 }
277 }
278
279 impl<Span> fmt::Display for Literal<Span> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result280 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
281 fmt::Display::fmt(&self.text, f)
282 }
283 }
284
285 impl<Span> fmt::Display for Punct<Span> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result286 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
287 fmt::Display::fmt(&self.char, f)
288 }
289 }
290
291 impl<Span> Subtree<Span> {
292 /// Count the number of tokens recursively
count(&self) -> usize293 pub fn count(&self) -> usize {
294 let children_count = self
295 .token_trees
296 .iter()
297 .map(|c| match c {
298 TokenTree::Subtree(c) => c.count(),
299 TokenTree::Leaf(_) => 0,
300 })
301 .sum::<usize>();
302
303 self.token_trees.len() + children_count
304 }
305 }
306
307 impl<Span> Subtree<Span> {
308 /// A simple line string used for debugging
as_debug_string(&self) -> String309 pub fn as_debug_string(&self) -> String {
310 let delim = match self.delimiter.kind {
311 DelimiterKind::Brace => ("{", "}"),
312 DelimiterKind::Bracket => ("[", "]"),
313 DelimiterKind::Parenthesis => ("(", ")"),
314 DelimiterKind::Invisible => ("$", "$"),
315 };
316
317 let mut res = String::new();
318 res.push_str(delim.0);
319 let mut last = None;
320 for child in &self.token_trees {
321 let s = match child {
322 TokenTree::Leaf(it) => {
323 let s = match it {
324 Leaf::Literal(it) => it.text.to_string(),
325 Leaf::Punct(it) => it.char.to_string(),
326 Leaf::Ident(it) => it.text.to_string(),
327 };
328 match (it, last) {
329 (Leaf::Ident(_), Some(&TokenTree::Leaf(Leaf::Ident(_)))) => {
330 " ".to_string() + &s
331 }
332 (Leaf::Punct(_), Some(TokenTree::Leaf(Leaf::Punct(punct)))) => {
333 if punct.spacing == Spacing::Alone {
334 " ".to_string() + &s
335 } else {
336 s
337 }
338 }
339 _ => s,
340 }
341 }
342 TokenTree::Subtree(it) => it.as_debug_string(),
343 };
344 res.push_str(&s);
345 last = Some(child);
346 }
347
348 res.push_str(delim.1);
349 res
350 }
351 }
352
353 pub mod buffer;
354
pretty<Span>(tkns: &[TokenTree<Span>]) -> String355 pub fn pretty<Span>(tkns: &[TokenTree<Span>]) -> String {
356 fn tokentree_to_text<Span>(tkn: &TokenTree<Span>) -> String {
357 match tkn {
358 TokenTree::Leaf(Leaf::Ident(ident)) => ident.text.clone().into(),
359 TokenTree::Leaf(Leaf::Literal(literal)) => literal.text.clone().into(),
360 TokenTree::Leaf(Leaf::Punct(punct)) => format!("{}", punct.char),
361 TokenTree::Subtree(subtree) => {
362 let content = pretty(&subtree.token_trees);
363 let (open, close) = match subtree.delimiter.kind {
364 DelimiterKind::Brace => ("{", "}"),
365 DelimiterKind::Bracket => ("[", "]"),
366 DelimiterKind::Parenthesis => ("(", ")"),
367 DelimiterKind::Invisible => ("", ""),
368 };
369 format!("{open}{content}{close}")
370 }
371 }
372 }
373
374 tkns.iter()
375 .fold((String::new(), true), |(last, last_to_joint), tkn| {
376 let s = [last, tokentree_to_text(tkn)].join(if last_to_joint { "" } else { " " });
377 let mut is_joint = false;
378 if let TokenTree::Leaf(Leaf::Punct(punct)) = tkn {
379 if punct.spacing == Spacing::Joint {
380 is_joint = true;
381 }
382 }
383 (s, is_joint)
384 })
385 .0
386 }
387