]> git.lizzy.rs Git - rust.git/blob - crates/tt/src/lib.rs
Merge #6586
[rust.git] / crates / tt / src / lib.rs
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 use std::{fmt, panic::RefUnwindSafe};
5
6 use stdx::impl_from;
7
8 pub use smol_str::SmolStr;
9
10 /// Represents identity of the token.
11 ///
12 /// For hygiene purposes, we need to track which expanded tokens originated from
13 /// which source tokens. We do it by assigning an distinct identity to each
14 /// source token and making sure that identities are preserved during macro
15 /// expansion.
16 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
17 pub struct TokenId(pub u32);
18
19 impl TokenId {
20     pub const fn unspecified() -> TokenId {
21         TokenId(!0)
22     }
23 }
24
25 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
26 pub enum TokenTree {
27     Leaf(Leaf),
28     Subtree(Subtree),
29 }
30 impl_from!(Leaf, Subtree for TokenTree);
31
32 impl TokenTree {
33     pub fn empty() -> Self {
34         TokenTree::Subtree(Subtree::default())
35     }
36 }
37
38 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
39 pub enum Leaf {
40     Literal(Literal),
41     Punct(Punct),
42     Ident(Ident),
43 }
44 impl_from!(Literal, Punct, Ident for Leaf);
45
46 #[derive(Clone, PartialEq, Eq, Hash, Default)]
47 pub struct Subtree {
48     pub delimiter: Option<Delimiter>,
49     pub token_trees: Vec<TokenTree>,
50 }
51
52 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
53 pub struct Delimiter {
54     pub id: TokenId,
55     pub kind: DelimiterKind,
56 }
57
58 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
59 pub enum DelimiterKind {
60     Parenthesis,
61     Brace,
62     Bracket,
63 }
64
65 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
66 pub struct Literal {
67     pub text: SmolStr,
68     pub id: TokenId,
69 }
70
71 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
72 pub struct Punct {
73     pub char: char,
74     pub spacing: Spacing,
75     pub id: TokenId,
76 }
77
78 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
79 pub enum Spacing {
80     Alone,
81     Joint,
82 }
83
84 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
85 pub struct Ident {
86     pub text: SmolStr,
87     pub id: TokenId,
88 }
89
90 fn print_debug_subtree(f: &mut fmt::Formatter<'_>, subtree: &Subtree, level: usize) -> fmt::Result {
91     let align = std::iter::repeat("  ").take(level).collect::<String>();
92
93     let aux = match subtree.delimiter.map(|it| (it.kind, it.id.0)) {
94         None => "$".to_string(),
95         Some((DelimiterKind::Parenthesis, id)) => format!("() {}", id),
96         Some((DelimiterKind::Brace, id)) => format!("{{}} {}", id),
97         Some((DelimiterKind::Bracket, id)) => format!("[] {}", id),
98     };
99
100     if subtree.token_trees.is_empty() {
101         write!(f, "{}SUBTREE {}", align, aux)?;
102     } else {
103         writeln!(f, "{}SUBTREE {}", align, aux)?;
104         for (idx, child) in subtree.token_trees.iter().enumerate() {
105             print_debug_token(f, child, level + 1)?;
106             if idx != subtree.token_trees.len() - 1 {
107                 writeln!(f)?;
108             }
109         }
110     }
111
112     Ok(())
113 }
114
115 fn print_debug_token(f: &mut fmt::Formatter<'_>, tkn: &TokenTree, level: usize) -> fmt::Result {
116     let align = std::iter::repeat("  ").take(level).collect::<String>();
117
118     match tkn {
119         TokenTree::Leaf(leaf) => match leaf {
120             Leaf::Literal(lit) => write!(f, "{}LITERAL {} {}", align, lit.text, lit.id.0)?,
121             Leaf::Punct(punct) => write!(
122                 f,
123                 "{}PUNCH   {} [{}] {}",
124                 align,
125                 punct.char,
126                 if punct.spacing == Spacing::Alone { "alone" } else { "joint" },
127                 punct.id.0
128             )?,
129             Leaf::Ident(ident) => write!(f, "{}IDENT   {} {}", align, ident.text, ident.id.0)?,
130         },
131         TokenTree::Subtree(subtree) => {
132             print_debug_subtree(f, subtree, level)?;
133         }
134     }
135
136     Ok(())
137 }
138
139 impl fmt::Debug for Subtree {
140     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141         print_debug_subtree(f, self, 0)
142     }
143 }
144
145 impl fmt::Display for TokenTree {
146     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
147         match self {
148             TokenTree::Leaf(it) => fmt::Display::fmt(it, f),
149             TokenTree::Subtree(it) => fmt::Display::fmt(it, f),
150         }
151     }
152 }
153
154 impl fmt::Display for Subtree {
155     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
156         let (l, r) = match self.delimiter_kind() {
157             Some(DelimiterKind::Parenthesis) => ("(", ")"),
158             Some(DelimiterKind::Brace) => ("{", "}"),
159             Some(DelimiterKind::Bracket) => ("[", "]"),
160             None => ("", ""),
161         };
162         f.write_str(l)?;
163         let mut needs_space = false;
164         for tt in self.token_trees.iter() {
165             if needs_space {
166                 f.write_str(" ")?;
167             }
168             needs_space = true;
169             match tt {
170                 TokenTree::Leaf(Leaf::Punct(p)) => {
171                     needs_space = p.spacing == Spacing::Alone;
172                     fmt::Display::fmt(p, f)?
173                 }
174                 tt => fmt::Display::fmt(tt, f)?,
175             }
176         }
177         f.write_str(r)?;
178         Ok(())
179     }
180 }
181
182 impl fmt::Display for Leaf {
183     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
184         match self {
185             Leaf::Ident(it) => fmt::Display::fmt(it, f),
186             Leaf::Literal(it) => fmt::Display::fmt(it, f),
187             Leaf::Punct(it) => fmt::Display::fmt(it, f),
188         }
189     }
190 }
191
192 impl fmt::Display for Ident {
193     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
194         fmt::Display::fmt(&self.text, f)
195     }
196 }
197
198 impl fmt::Display for Literal {
199     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
200         fmt::Display::fmt(&self.text, f)
201     }
202 }
203
204 impl fmt::Display for Punct {
205     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
206         fmt::Display::fmt(&self.char, f)
207     }
208 }
209
210 impl Subtree {
211     /// Count the number of tokens recursively
212     pub fn count(&self) -> usize {
213         let children_count = self
214             .token_trees
215             .iter()
216             .map(|c| match c {
217                 TokenTree::Subtree(c) => c.count(),
218                 _ => 0,
219             })
220             .sum::<usize>();
221
222         self.token_trees.len() + children_count
223     }
224
225     pub fn delimiter_kind(&self) -> Option<DelimiterKind> {
226         self.delimiter.map(|it| it.kind)
227     }
228 }
229
230 pub mod buffer;
231
232 #[derive(Debug, PartialEq, Eq, Clone)]
233 pub enum ExpansionError {
234     IOError(String),
235     JsonError(String),
236     Unknown(String),
237     ExpansionError(String),
238 }
239
240 impl fmt::Display for ExpansionError {
241     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242         match self {
243             ExpansionError::IOError(e) => write!(f, "I/O error: {}", e),
244             ExpansionError::JsonError(e) => write!(f, "JSON decoding error: {}", e),
245             ExpansionError::Unknown(e) => e.fmt(f),
246             ExpansionError::ExpansionError(e) => write!(f, "proc macro returned error: {}", e),
247         }
248     }
249 }
250
251 pub trait TokenExpander: fmt::Debug + Send + Sync + RefUnwindSafe {
252     fn expand(&self, subtree: &Subtree, attrs: Option<&Subtree>)
253         -> Result<Subtree, ExpansionError>;
254 }