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