1use super::{ToTokens, TokenStream};
2use crate::lex::{Cursor, LexError, Scan};
3use crate::{Span, TokenTree};
4
5#[macro_export]
44macro_rules! ident {
45 ($x:ident) => { $crate::Ident::lex(stringify!($x).to_string()).expect("invalid syntax") };
46 ($x:expr) => { $crate::Ident::lex($x).expect("invalid syntax") };
47 ($head:ident, $($tail:tt)+) => {{
48 let mut __ident = stringify!($head).to_string();
49 ident!(@accum __ident, $($tail)+)
50 }};
51 ($head:expr, $($tail:tt)+) => {{
52 let mut __ident = $head.to_string();
53 ident!(@accum __ident, $($tail)+)
54 }};
55 (@accum $acc:ident, $next:ident, $($tail:tt)+) => {{
56 $acc += stringify!($next);
57 ident!(@accum $acc, $($tail)+)
58 }};
59 (@accum $acc:ident, $next:expr, $($tail:tt)+) => {{
60 $acc += &$next.to_string();
61 ident!(@accum $acc, $($tail)+)
62 }};
63 (@accum $acc:ident, $last:ident) => {{
64 $acc += stringify!($last);
65 $crate::Ident::lex($acc).expect("invalid syntax")
66 }};
67 (@accum $acc:ident, $last:expr) => {{
68 $acc += &$last.to_string();
69 $crate::Ident::lex($acc).expect("invalid syntax")
70 }};
71}
72
73#[derive(Debug, Clone, PartialEq, Eq)]
75pub struct Ident {
76 text: Box<str>,
77 span: Span,
78}
79
80impl Ident {
81 pub fn new(text: impl std::fmt::Display) -> Self {
82 Self {
83 text: text.to_string().into_boxed_str(),
84 span: Span::default(),
85 }
86 }
87
88 pub fn lex(input: impl std::fmt::Display) -> Result<Self, LexError> {
89 std::str::FromStr::from_str(&input.to_string())
90 }
91
92 #[inline]
93 pub fn with_span(mut self, span: Span) -> Self {
94 self.span = span;
95 self
96 }
97
98 #[inline]
99 pub fn text(&self) -> &str {
100 match self.text.strip_prefix("r#") {
101 Some(rest) => rest,
102 None => &self.text,
103 }
104 }
105
106 #[inline]
107 pub fn is_raw(&self) -> bool {
108 self.text.starts_with("r#")
109 }
110
111 #[inline]
112 pub fn span(&self) -> Span {
113 self.span
114 }
115
116 #[inline]
117 pub fn set_span(&mut self, span: Span) {
118 self.span = span;
119 }
120
121 pub fn to_lowercase(mut self) -> Self {
122 self.text = self.text.to_lowercase().into_boxed_str();
123 self
124 }
125
126 pub fn to_uppercase(mut self) -> Self {
127 self.text = self.text.to_uppercase().into_boxed_str();
128 self
129 }
130
131 #[inline]
132 pub fn to_token_tree(&self) -> TokenTree {
133 TokenTree::Ident(self.clone())
134 }
135
136 #[inline]
137 pub fn into_token_tree(self) -> TokenTree {
138 TokenTree::Ident(self)
139 }
140}
141
142impl Scan for Ident {
143 fn scan(cursor: Cursor<'_>) -> Result<(Cursor<'_>, Self), LexError> {
144 if cursor.starts_with("r#") {
146 let after = cursor.advance_by(2);
147 let end = after.skip_while(unicode_ident::is_xid_continue);
148
149 if end.offset() == after.offset() {
150 return cursor.error().into();
151 }
152
153 let span = cursor.span_to(&end);
154 let name = &cursor.rest()[..end.offset() as usize - cursor.offset() as usize];
155 return Ok((end, Self::new(name).with_span(span)));
156 }
157
158 let first = cursor.first().ok_or(cursor.error())?;
159
160 if first != '_' && !unicode_ident::is_xid_start(first) {
161 return cursor.error().into();
162 }
163
164 let end = cursor.advance_by(first.len_utf8()).skip_while(unicode_ident::is_xid_continue);
165 let span = cursor.span_to(&end);
166 let text = &cursor.rest()[..end.offset() as usize - cursor.offset() as usize];
167 Ok((end, Self::new(text).with_span(span)))
168 }
169}
170
171impl std::fmt::Display for Ident {
172 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
173 write!(f, "{}", self.text)
174 }
175}
176
177impl ToTokens for Ident {
178 fn to_tokens(&self, tokens: &mut TokenStream) {
179 tokens.extend_one(TokenTree::Ident(self.clone()));
180 }
181}
182
183impl crate::Spanner for Ident {
184 fn span(&self) -> Span {
185 self.span
186 }
187}
188
189impl std::str::FromStr for Ident {
190 type Err = LexError;
191
192 fn from_str(s: &str) -> Result<Self, Self::Err> {
193 let cursor = Cursor::new(s, 0);
194 let (_, ident) = Self::scan(cursor)?;
195 Ok(ident)
196 }
197}
198
199#[cfg(feature = "serde")]
200impl serde::Serialize for Ident {
201 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
202 where
203 S: serde::Serializer,
204 {
205 self.text.serialize(s)
206 }
207}
208
209impl PartialEq<str> for Ident {
210 fn eq(&self, other: &str) -> bool {
211 self.text.as_ref() == other
212 }
213}
214
215impl PartialEq<&str> for Ident {
216 fn eq(&self, other: &&str) -> bool {
217 self.text.as_ref() == *other
218 }
219}
220
221impl std::hash::Hash for Ident {
222 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
223 self.text.hash(state);
224 }
225}