1use crate::lex::{Cursor, Scan};
2use crate::{Delim, Group, Ident, Keyword, Lit, Punct, Span, Spanner, ToTokens, TokenStream};
3
4#[derive(Debug, Clone, PartialEq, Eq)]
5#[cfg_attr(feature = "serde", derive(serde::Serialize), serde(untagged))]
6pub enum TokenTree {
7 Ident(Ident),
8 Keyword(Keyword),
9 Punct(Punct),
10 Literal(Lit),
11 Group(Group),
12}
13
14impl TokenTree {
15 pub fn span(&self) -> Span {
16 match self {
17 Self::Ident(v) => v.span(),
18 Self::Keyword(v) => v.span(),
19 Self::Punct(v) => v.span(),
20 Self::Literal(v) => v.span(),
21 Self::Group(v) => v.span().into(),
22 }
23 }
24
25 pub fn text(&self) -> Option<&str> {
26 match self {
27 Self::Ident(v) => Some(v.text()),
28 Self::Keyword(v) => Some(v.as_str()),
29 _ => None,
30 }
31 }
32
33 pub fn delim(&self) -> Option<Delim> {
34 match self {
35 Self::Group(g) => Some(g.delim()),
36 _ => None,
37 }
38 }
39
40 #[inline]
41 pub fn is_token(&self) -> bool {
42 !matches!(self, Self::Group(_))
43 }
44
45 #[inline]
46 pub fn is_group(&self) -> bool {
47 matches!(self, Self::Group(_))
48 }
49
50 #[inline]
51 pub fn as_group(&self) -> Option<&Group> {
52 match self {
53 Self::Group(v) => Some(v),
54 _ => None,
55 }
56 }
57
58 #[inline]
59 pub fn is_ident(&self) -> bool {
60 matches!(self, Self::Ident(_))
61 }
62
63 #[inline]
64 pub fn as_ident(&self) -> Option<&Ident> {
65 match self {
66 Self::Ident(v) => Some(v),
67 _ => None,
68 }
69 }
70
71 #[inline]
72 pub fn is_literal(&self) -> bool {
73 matches!(self, Self::Literal(_))
74 }
75
76 #[inline]
77 pub fn as_literal(&self) -> Option<&Lit> {
78 match self {
79 Self::Literal(v) => Some(v),
80 _ => None,
81 }
82 }
83}
84
85impl From<Ident> for TokenTree {
86 #[inline]
87 fn from(value: Ident) -> Self {
88 Self::Ident(value)
89 }
90}
91
92impl From<Keyword> for TokenTree {
93 #[inline]
94 fn from(value: Keyword) -> Self {
95 Self::Keyword(value)
96 }
97}
98
99impl From<Punct> for TokenTree {
100 #[inline]
101 fn from(value: Punct) -> Self {
102 Self::Punct(value)
103 }
104}
105
106impl From<Lit> for TokenTree {
107 #[inline]
108 fn from(value: Lit) -> Self {
109 Self::Literal(value)
110 }
111}
112
113impl From<Group> for TokenTree {
114 #[inline]
115 fn from(value: Group) -> Self {
116 Self::Group(value)
117 }
118}
119
120impl IntoIterator for TokenTree {
121 type Item = Self;
122 type IntoIter = std::iter::Once<Self>;
123
124 fn into_iter(self) -> Self::IntoIter {
125 std::iter::once(self)
126 }
127}
128
129impl std::fmt::Display for TokenTree {
130 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
131 match self {
132 Self::Ident(v) => write!(f, "{}", v),
133 Self::Keyword(v) => write!(f, "{}", v),
134 Self::Punct(v) => write!(f, "{}", v),
135 Self::Literal(v) => write!(f, "{}", v),
136 Self::Group(v) => write!(f, "{}", v),
137 }
138 }
139}
140
141impl ToTokens for TokenTree {
142 fn to_tokens(&self, tokens: &mut TokenStream) {
143 tokens.extend_one(self.clone());
144 }
145}
146
147impl Spanner for TokenTree {
148 fn span(&self) -> Span {
149 self.span()
150 }
151}
152
153impl ToTokens for &str {
154 fn to_tokens(&self, tokens: &mut TokenStream) {
155 use std::str::FromStr;
156
157 if let Ok(ts) = TokenStream::from_str(self) {
158 ts.to_tokens(tokens);
159 }
160 }
161}
162
163impl ToTokens for String {
164 fn to_tokens(&self, tokens: &mut TokenStream) {
165 crate::Lit::string(self).to_tokens(tokens);
166 }
167}
168
169impl ToTokens for &mut String {
170 fn to_tokens(&self, tokens: &mut TokenStream) {
171 crate::Lit::string(self).to_tokens(tokens);
172 }
173}
174
175pub(crate) fn scan_puncts_spanned(run: &[(char, Span, crate::Spacing)], tokens: &mut TokenStream) {
178 let text: String = run.iter().map(|(c, _, _)| *c).collect();
179 let mut cursor = Cursor::new(&text, 0);
180 let mut idx = 0usize;
181
182 while !cursor.is_empty() {
183 match <Punct as Scan>::scan(cursor) {
184 Ok((next, mut op)) => {
185 let consumed = op.as_str().chars().count();
186 let span = run[idx].1.join(run[idx + consumed - 1].1);
187 op.set_span(span);
188 op.set_spacing(run[idx + consumed - 1].2);
189 tokens.extend_one(TokenTree::Punct(op));
190 idx += consumed;
191 cursor = next;
192 }
193 Err(_) => break,
194 }
195 }
196}