blob: 856cf7bcd8cd11100f851cead4dcee01489494f7 [file] [log] [blame]
Alex Crichton9a4dca22018-03-28 06:32:19 -07001use proc_macro2::{Literal, Span};
David Tolnay360efd22018-01-04 23:35:26 -08002use std::str;
3
David Tolnay7d1d1282018-01-06 16:10:51 -08004#[cfg(feature = "printing")]
Alex Crichtona74a1c82018-05-16 10:20:44 -07005use proc_macro2::Ident;
David Tolnay7d1d1282018-01-06 16:10:51 -08006
David Tolnayd53ac2b2018-01-27 19:00:06 -08007#[cfg(feature = "parsing")]
8use proc_macro2::TokenStream;
9#[cfg(feature = "parsing")]
David Tolnaye82a2b12018-08-30 16:31:10 -070010use Error;
David Tolnayd53ac2b2018-01-27 19:00:06 -080011
David Tolnay60fafad2018-02-03 09:18:03 -080012use proc_macro2::TokenTree;
13
David Tolnay360efd22018-01-04 23:35:26 -080014#[cfg(feature = "extra-traits")]
Alex Crichtonccbb45d2017-05-23 10:58:24 -070015use std::hash::{Hash, Hasher};
16
David Tolnay4fb71232018-08-25 23:14:50 -040017#[cfg(feature = "parsing")]
18use lookahead;
David Tolnaye82a2b12018-08-30 16:31:10 -070019#[cfg(feature = "parsing")]
20use parse::Parse;
David Tolnay4fb71232018-08-25 23:14:50 -040021
David Tolnay360efd22018-01-04 23:35:26 -080022ast_enum_of_structs! {
David Tolnayabf5c2e2018-01-06 23:30:04 -080023 /// A Rust literal such as a string or integer or boolean.
David Tolnay614a0142018-01-07 10:25:43 -080024 ///
David Tolnay461d98e2018-01-07 11:07:19 -080025 /// *This type is available if Syn is built with the `"derive"` or `"full"`
26 /// feature.*
27 ///
David Tolnay614a0142018-01-07 10:25:43 -080028 /// # Syntax tree enum
29 ///
30 /// This type is a [syntax tree enum].
31 ///
32 /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
David Tolnay360efd22018-01-04 23:35:26 -080033 pub enum Lit {
David Tolnayabf5c2e2018-01-06 23:30:04 -080034 /// A UTF-8 string literal: `"foo"`.
David Tolnay461d98e2018-01-07 11:07:19 -080035 ///
36 /// *This type is available if Syn is built with the `"derive"` or
37 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080038 pub Str(LitStr #manual_extra_traits {
39 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080040 }),
Alex Crichtonccbb45d2017-05-23 10:58:24 -070041
David Tolnayabf5c2e2018-01-06 23:30:04 -080042 /// A byte string literal: `b"foo"`.
David Tolnay461d98e2018-01-07 11:07:19 -080043 ///
44 /// *This type is available if Syn is built with the `"derive"` or
45 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080046 pub ByteStr(LitByteStr #manual_extra_traits {
47 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080048 }),
49
David Tolnayabf5c2e2018-01-06 23:30:04 -080050 /// A byte literal: `b'f'`.
David Tolnay461d98e2018-01-07 11:07:19 -080051 ///
52 /// *This type is available if Syn is built with the `"derive"` or
53 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080054 pub Byte(LitByte #manual_extra_traits {
55 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080056 }),
57
David Tolnayabf5c2e2018-01-06 23:30:04 -080058 /// A character literal: `'a'`.
David Tolnay461d98e2018-01-07 11:07:19 -080059 ///
60 /// *This type is available if Syn is built with the `"derive"` or
61 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080062 pub Char(LitChar #manual_extra_traits {
63 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080064 }),
65
David Tolnayabf5c2e2018-01-06 23:30:04 -080066 /// An integer literal: `1` or `1u16`.
David Tolnay360efd22018-01-04 23:35:26 -080067 ///
68 /// Holds up to 64 bits of data. Use `LitVerbatim` for any larger
69 /// integer literal.
David Tolnay461d98e2018-01-07 11:07:19 -080070 ///
71 /// *This type is available if Syn is built with the `"derive"` or
72 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080073 pub Int(LitInt #manual_extra_traits {
74 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080075 }),
76
David Tolnayabf5c2e2018-01-06 23:30:04 -080077 /// A floating point literal: `1f64` or `1.0e10f64`.
David Tolnay360efd22018-01-04 23:35:26 -080078 ///
79 /// Must be finite. May not be infinte or NaN.
David Tolnay461d98e2018-01-07 11:07:19 -080080 ///
81 /// *This type is available if Syn is built with the `"derive"` or
82 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080083 pub Float(LitFloat #manual_extra_traits {
84 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080085 }),
86
David Tolnayabf5c2e2018-01-06 23:30:04 -080087 /// A boolean literal: `true` or `false`.
David Tolnay461d98e2018-01-07 11:07:19 -080088 ///
89 /// *This type is available if Syn is built with the `"derive"` or
90 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080091 pub Bool(LitBool #manual_extra_traits {
92 pub value: bool,
93 pub span: Span,
94 }),
95
David Tolnayabf5c2e2018-01-06 23:30:04 -080096 /// A raw token literal not interpreted by Syn, possibly because it
97 /// represents an integer larger than 64 bits.
David Tolnay461d98e2018-01-07 11:07:19 -080098 ///
99 /// *This type is available if Syn is built with the `"derive"` or
100 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800101 pub Verbatim(LitVerbatim #manual_extra_traits {
102 pub token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -0800103 }),
104 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700105}
106
David Tolnay360efd22018-01-04 23:35:26 -0800107impl LitStr {
108 pub fn new(value: &str, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700109 let mut lit = Literal::string(value);
110 lit.set_span(span);
David Tolnay94d2b792018-04-29 12:26:10 -0700111 LitStr { token: lit }
David Tolnay360efd22018-01-04 23:35:26 -0800112 }
113
114 pub fn value(&self) -> String {
115 value::parse_lit_str(&self.token.to_string())
116 }
David Tolnayd53ac2b2018-01-27 19:00:06 -0800117
118 /// Parse a syntax tree node from the content of this string literal.
119 ///
120 /// All spans in the syntax tree will point to the span of this `LitStr`.
David Tolnay3b0444a2018-09-01 17:17:19 -0700121 ///
122 /// # Example
123 ///
David Tolnay95989db2019-01-01 15:05:57 -0500124 /// ```edition2018
David Tolnay3b0444a2018-09-01 17:17:19 -0700125 /// use proc_macro2::Span;
David Tolnay67fea042018-11-24 14:50:20 -0800126 /// use syn::{Attribute, Error, Ident, Lit, Meta, MetaNameValue, Path, Result};
David Tolnay3b0444a2018-09-01 17:17:19 -0700127 ///
128 /// // Parses the path from an attribute that looks like:
129 /// //
130 /// // #[path = "a::b::c"]
131 /// //
David Tolnay4ac734f2018-11-10 14:19:00 -0800132 /// // or returns `None` if the input is some other attribute.
133 /// fn get_path(attr: &Attribute) -> Result<Option<Path>> {
134 /// if !attr.path.is_ident("path") {
135 /// return Ok(None);
David Tolnay3b0444a2018-09-01 17:17:19 -0700136 /// }
137 ///
David Tolnay4ac734f2018-11-10 14:19:00 -0800138 /// match attr.parse_meta()? {
David Tolnay3b0444a2018-09-01 17:17:19 -0700139 /// Meta::NameValue(MetaNameValue { lit: Lit::Str(lit_str), .. }) => {
David Tolnay4ac734f2018-11-10 14:19:00 -0800140 /// lit_str.parse().map(Some)
David Tolnay3b0444a2018-09-01 17:17:19 -0700141 /// }
142 /// _ => {
David Tolnay3b0444a2018-09-01 17:17:19 -0700143 /// let message = "expected #[path = \"...\"]";
David Tolnayff853572019-03-07 22:04:15 -0800144 /// Err(Error::new_spanned(attr, message))
David Tolnay3b0444a2018-09-01 17:17:19 -0700145 /// }
146 /// }
147 /// }
148 /// ```
David Tolnayd53ac2b2018-01-27 19:00:06 -0800149 #[cfg(feature = "parsing")]
David Tolnaye82a2b12018-08-30 16:31:10 -0700150 pub fn parse<T: Parse>(&self) -> Result<T, Error> {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700151 use proc_macro2::Group;
152
David Tolnayd53ac2b2018-01-27 19:00:06 -0800153 // Parse string literal into a token stream with every span equal to the
154 // original literal's span.
David Tolnayad4b2472018-08-25 08:25:24 -0400155 fn spanned_tokens(s: &LitStr) -> Result<TokenStream, Error> {
David Tolnayd53ac2b2018-01-27 19:00:06 -0800156 let stream = ::parse_str(&s.value())?;
Alex Crichton9a4dca22018-03-28 06:32:19 -0700157 Ok(respan_token_stream(stream, s.span()))
David Tolnayd53ac2b2018-01-27 19:00:06 -0800158 }
159
160 // Token stream with every span replaced by the given one.
161 fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
David Tolnay94d2b792018-04-29 12:26:10 -0700162 stream
163 .into_iter()
164 .map(|token| respan_token_tree(token, span))
165 .collect()
David Tolnayd53ac2b2018-01-27 19:00:06 -0800166 }
167
168 // Token tree with every span replaced by the given one.
Alex Crichton9a4dca22018-03-28 06:32:19 -0700169 fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
170 match token {
171 TokenTree::Group(ref mut g) => {
172 let stream = respan_token_stream(g.stream().clone(), span);
173 *g = Group::new(g.delimiter(), stream);
174 g.set_span(span);
175 }
176 ref mut other => other.set_span(span),
David Tolnayd53ac2b2018-01-27 19:00:06 -0800177 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700178 token
David Tolnayd53ac2b2018-01-27 19:00:06 -0800179 }
180
181 spanned_tokens(self).and_then(::parse2)
182 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700183
184 pub fn span(&self) -> Span {
185 self.token.span()
186 }
187
188 pub fn set_span(&mut self, span: Span) {
189 self.token.set_span(span)
190 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700191}
192
David Tolnay360efd22018-01-04 23:35:26 -0800193impl LitByteStr {
194 pub fn new(value: &[u8], span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700195 let mut token = Literal::byte_string(value);
196 token.set_span(span);
197 LitByteStr { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800198 }
199
200 pub fn value(&self) -> Vec<u8> {
201 value::parse_lit_byte_str(&self.token.to_string())
202 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700203
204 pub fn span(&self) -> Span {
205 self.token.span()
206 }
207
208 pub fn set_span(&mut self, span: Span) {
209 self.token.set_span(span)
210 }
David Tolnay360efd22018-01-04 23:35:26 -0800211}
212
213impl LitByte {
214 pub fn new(value: u8, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700215 let mut token = Literal::u8_suffixed(value);
216 token.set_span(span);
217 LitByte { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800218 }
219
220 pub fn value(&self) -> u8 {
221 value::parse_lit_byte(&self.token.to_string())
222 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700223
224 pub fn span(&self) -> Span {
225 self.token.span()
226 }
227
228 pub fn set_span(&mut self, span: Span) {
229 self.token.set_span(span)
230 }
David Tolnay360efd22018-01-04 23:35:26 -0800231}
232
233impl LitChar {
234 pub fn new(value: char, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700235 let mut token = Literal::character(value);
236 token.set_span(span);
237 LitChar { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800238 }
239
240 pub fn value(&self) -> char {
241 value::parse_lit_char(&self.token.to_string())
242 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700243
244 pub fn span(&self) -> Span {
245 self.token.span()
246 }
247
248 pub fn set_span(&mut self, span: Span) {
249 self.token.set_span(span)
250 }
David Tolnay360efd22018-01-04 23:35:26 -0800251}
252
253impl LitInt {
254 pub fn new(value: u64, suffix: IntSuffix, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700255 let mut token = match suffix {
256 IntSuffix::Isize => Literal::isize_suffixed(value as isize),
257 IntSuffix::I8 => Literal::i8_suffixed(value as i8),
258 IntSuffix::I16 => Literal::i16_suffixed(value as i16),
259 IntSuffix::I32 => Literal::i32_suffixed(value as i32),
260 IntSuffix::I64 => Literal::i64_suffixed(value as i64),
261 IntSuffix::I128 => value::to_literal(&format!("{}i128", value)),
262 IntSuffix::Usize => Literal::usize_suffixed(value as usize),
263 IntSuffix::U8 => Literal::u8_suffixed(value as u8),
264 IntSuffix::U16 => Literal::u16_suffixed(value as u16),
265 IntSuffix::U32 => Literal::u32_suffixed(value as u32),
266 IntSuffix::U64 => Literal::u64_suffixed(value),
267 IntSuffix::U128 => value::to_literal(&format!("{}u128", value)),
268 IntSuffix::None => Literal::u64_unsuffixed(value),
269 };
270 token.set_span(span);
271 LitInt { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800272 }
273
274 pub fn value(&self) -> u64 {
275 value::parse_lit_int(&self.token.to_string()).unwrap()
276 }
277
278 pub fn suffix(&self) -> IntSuffix {
279 let value = self.token.to_string();
280 for (s, suffix) in vec![
281 ("i8", IntSuffix::I8),
282 ("i16", IntSuffix::I16),
283 ("i32", IntSuffix::I32),
284 ("i64", IntSuffix::I64),
285 ("i128", IntSuffix::I128),
286 ("isize", IntSuffix::Isize),
287 ("u8", IntSuffix::U8),
288 ("u16", IntSuffix::U16),
289 ("u32", IntSuffix::U32),
290 ("u64", IntSuffix::U64),
291 ("u128", IntSuffix::U128),
292 ("usize", IntSuffix::Usize),
293 ] {
294 if value.ends_with(s) {
295 return suffix;
296 }
297 }
298 IntSuffix::None
299 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700300
301 pub fn span(&self) -> Span {
302 self.token.span()
303 }
304
305 pub fn set_span(&mut self, span: Span) {
306 self.token.set_span(span)
307 }
David Tolnay360efd22018-01-04 23:35:26 -0800308}
309
310impl LitFloat {
311 pub fn new(value: f64, suffix: FloatSuffix, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700312 let mut token = match suffix {
313 FloatSuffix::F32 => Literal::f32_suffixed(value as f32),
314 FloatSuffix::F64 => Literal::f64_suffixed(value),
315 FloatSuffix::None => Literal::f64_unsuffixed(value),
316 };
317 token.set_span(span);
318 LitFloat { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800319 }
320
321 pub fn value(&self) -> f64 {
322 value::parse_lit_float(&self.token.to_string())
323 }
324
325 pub fn suffix(&self) -> FloatSuffix {
326 let value = self.token.to_string();
David Tolnay61037c62018-01-05 16:21:03 -0800327 for (s, suffix) in vec![("f32", FloatSuffix::F32), ("f64", FloatSuffix::F64)] {
David Tolnay360efd22018-01-04 23:35:26 -0800328 if value.ends_with(s) {
329 return suffix;
330 }
331 }
332 FloatSuffix::None
333 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700334
335 pub fn span(&self) -> Span {
336 self.token.span()
337 }
338
339 pub fn set_span(&mut self, span: Span) {
340 self.token.set_span(span)
341 }
David Tolnay360efd22018-01-04 23:35:26 -0800342}
343
344macro_rules! lit_extra_traits {
345 ($ty:ident, $field:ident) => {
346 #[cfg(feature = "extra-traits")]
347 impl Eq for $ty {}
348
349 #[cfg(feature = "extra-traits")]
350 impl PartialEq for $ty {
351 fn eq(&self, other: &Self) -> bool {
352 self.$field.to_string() == other.$field.to_string()
353 }
354 }
355
356 #[cfg(feature = "extra-traits")]
357 impl Hash for $ty {
358 fn hash<H>(&self, state: &mut H)
359 where
360 H: Hasher,
361 {
362 self.$field.to_string().hash(state);
363 }
David Tolnay9c76bcb2017-12-26 23:14:59 -0500364 }
David Tolnay6a170ce2018-08-26 22:29:24 -0700365
366 #[cfg(feature = "parsing")]
367 #[doc(hidden)]
368 #[allow(non_snake_case)]
369 pub fn $ty(marker: lookahead::TokenMarker) -> $ty {
370 match marker {}
371 }
David Tolnay94d2b792018-04-29 12:26:10 -0700372 };
David Tolnayf4bbbd92016-09-23 14:41:55 -0700373}
374
Alex Crichton9a4dca22018-03-28 06:32:19 -0700375impl LitVerbatim {
376 pub fn span(&self) -> Span {
377 self.token.span()
378 }
379
380 pub fn set_span(&mut self, span: Span) {
381 self.token.set_span(span)
382 }
383}
384
David Tolnay360efd22018-01-04 23:35:26 -0800385lit_extra_traits!(LitStr, token);
386lit_extra_traits!(LitByteStr, token);
387lit_extra_traits!(LitByte, token);
388lit_extra_traits!(LitChar, token);
389lit_extra_traits!(LitInt, token);
390lit_extra_traits!(LitFloat, token);
391lit_extra_traits!(LitBool, value);
392lit_extra_traits!(LitVerbatim, token);
393
394ast_enum! {
David Tolnay05658502018-01-07 09:56:37 -0800395 /// The style of a string literal, either plain quoted or a raw string like
David Tolnayabf5c2e2018-01-06 23:30:04 -0800396 /// `r##"data"##`.
David Tolnay461d98e2018-01-07 11:07:19 -0800397 ///
398 /// *This type is available if Syn is built with the `"derive"` or `"full"`
399 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800400 pub enum StrStyle #no_visit {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800401 /// An ordinary string like `"data"`.
David Tolnay360efd22018-01-04 23:35:26 -0800402 Cooked,
David Tolnayabf5c2e2018-01-06 23:30:04 -0800403 /// A raw string like `r##"data"##`.
David Tolnay360efd22018-01-04 23:35:26 -0800404 ///
405 /// The unsigned integer is the number of `#` symbols used.
406 Raw(usize),
Alex Crichton62a0a592017-05-22 13:58:53 -0700407 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700408}
409
David Tolnay360efd22018-01-04 23:35:26 -0800410ast_enum! {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800411 /// The suffix on an integer literal if any, like the `u8` in `127u8`.
David Tolnay461d98e2018-01-07 11:07:19 -0800412 ///
413 /// *This type is available if Syn is built with the `"derive"` or `"full"`
414 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800415 pub enum IntSuffix #no_visit {
416 I8,
417 I16,
418 I32,
419 I64,
420 I128,
421 Isize,
422 U8,
423 U16,
424 U32,
425 U64,
426 U128,
427 Usize,
428 None,
Pascal Hertleif36342c52016-10-19 10:31:42 +0200429 }
430}
431
David Tolnay360efd22018-01-04 23:35:26 -0800432ast_enum! {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800433 /// The suffix on a floating point literal if any, like the `f32` in
434 /// `1.0f32`.
David Tolnay461d98e2018-01-07 11:07:19 -0800435 ///
436 /// *This type is available if Syn is built with the `"derive"` or `"full"`
437 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800438 pub enum FloatSuffix #no_visit {
439 F32,
440 F64,
441 None,
Alex Crichton2e0229c2017-05-23 09:34:50 -0700442 }
David Tolnay5fe14fc2017-01-27 16:22:08 -0800443}
444
445#[cfg(feature = "parsing")]
David Tolnay4fb71232018-08-25 23:14:50 -0400446#[doc(hidden)]
447#[allow(non_snake_case)]
448pub fn Lit(marker: lookahead::TokenMarker) -> Lit {
449 match marker {}
450}
451
452#[cfg(feature = "parsing")]
David Tolnayf4bbbd92016-09-23 14:41:55 -0700453pub mod parsing {
454 use super::*;
David Tolnay4fb71232018-08-25 23:14:50 -0400455 use parse::{Parse, ParseStream, Result};
David Tolnayf4bbbd92016-09-23 14:41:55 -0700456
David Tolnay4fb71232018-08-25 23:14:50 -0400457 impl Parse for Lit {
458 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay924e0af2018-09-01 13:07:34 -0700459 input.step(|cursor| {
460 if let Some((lit, rest)) = cursor.literal() {
461 return Ok((Lit::new(lit), rest));
462 }
463 while let Some((ident, rest)) = cursor.ident() {
464 let value = if ident == "true" {
465 true
466 } else if ident == "false" {
467 false
468 } else {
469 break;
470 };
471 let lit_bool = LitBool {
472 value: value,
473 span: ident.span(),
474 };
475 return Ok((Lit::Bool(lit_bool), rest));
476 }
477 Err(cursor.error("expected literal"))
David Tolnay4fb71232018-08-25 23:14:50 -0400478 })
Sergio Benitez5680d6a2017-12-29 11:20:29 -0800479 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700480 }
David Tolnay360efd22018-01-04 23:35:26 -0800481
David Tolnaya7d69fc2018-08-26 13:30:24 -0400482 impl Parse for LitStr {
483 fn parse(input: ParseStream) -> Result<Self> {
484 let head = input.fork();
485 match input.parse()? {
486 Lit::Str(lit) => Ok(lit),
487 _ => Err(head.error("expected string literal")),
488 }
489 }
490 }
David Tolnay360efd22018-01-04 23:35:26 -0800491
David Tolnaya7d69fc2018-08-26 13:30:24 -0400492 impl Parse for LitByteStr {
493 fn parse(input: ParseStream) -> Result<Self> {
494 let head = input.fork();
495 match input.parse()? {
496 Lit::ByteStr(lit) => Ok(lit),
497 _ => Err(head.error("expected byte string literal")),
498 }
499 }
500 }
David Tolnay360efd22018-01-04 23:35:26 -0800501
David Tolnaya7d69fc2018-08-26 13:30:24 -0400502 impl Parse for LitByte {
503 fn parse(input: ParseStream) -> Result<Self> {
504 let head = input.fork();
505 match input.parse()? {
506 Lit::Byte(lit) => Ok(lit),
507 _ => Err(head.error("expected byte literal")),
508 }
509 }
510 }
David Tolnay360efd22018-01-04 23:35:26 -0800511
David Tolnaya7d69fc2018-08-26 13:30:24 -0400512 impl Parse for LitChar {
513 fn parse(input: ParseStream) -> Result<Self> {
514 let head = input.fork();
515 match input.parse()? {
516 Lit::Char(lit) => Ok(lit),
517 _ => Err(head.error("expected character literal")),
518 }
519 }
520 }
David Tolnay360efd22018-01-04 23:35:26 -0800521
David Tolnaya7d69fc2018-08-26 13:30:24 -0400522 impl Parse for LitInt {
523 fn parse(input: ParseStream) -> Result<Self> {
524 let head = input.fork();
525 match input.parse()? {
526 Lit::Int(lit) => Ok(lit),
527 _ => Err(head.error("expected integer literal")),
528 }
529 }
530 }
David Tolnay360efd22018-01-04 23:35:26 -0800531
David Tolnaya7d69fc2018-08-26 13:30:24 -0400532 impl Parse for LitFloat {
533 fn parse(input: ParseStream) -> Result<Self> {
534 let head = input.fork();
535 match input.parse()? {
536 Lit::Float(lit) => Ok(lit),
537 _ => Err(head.error("expected floating point literal")),
538 }
539 }
540 }
David Tolnay360efd22018-01-04 23:35:26 -0800541
David Tolnaya7d69fc2018-08-26 13:30:24 -0400542 impl Parse for LitBool {
543 fn parse(input: ParseStream) -> Result<Self> {
544 let head = input.fork();
545 match input.parse()? {
546 Lit::Bool(lit) => Ok(lit),
547 _ => Err(head.error("expected boolean literal")),
548 }
549 }
550 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700551}
552
553#[cfg(feature = "printing")]
554mod printing {
555 use super::*;
Alex Crichtona74a1c82018-05-16 10:20:44 -0700556 use proc_macro2::TokenStream;
David Tolnay65fb5662018-05-20 20:02:28 -0700557 use quote::{ToTokens, TokenStreamExt};
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700558
David Tolnay360efd22018-01-04 23:35:26 -0800559 impl ToTokens for LitStr {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700560 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700561 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800562 }
563 }
564
565 impl ToTokens for LitByteStr {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700566 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700567 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800568 }
569 }
570
571 impl ToTokens for LitByte {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700572 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700573 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800574 }
575 }
576
577 impl ToTokens for LitChar {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700578 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700579 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800580 }
581 }
582
583 impl ToTokens for LitInt {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700584 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700585 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800586 }
587 }
588
589 impl ToTokens for LitFloat {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700590 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700591 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800592 }
593 }
594
595 impl ToTokens for LitBool {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700596 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700597 let s = if self.value { "true" } else { "false" };
Alex Crichtona74a1c82018-05-16 10:20:44 -0700598 tokens.append(Ident::new(s, self.span));
David Tolnay360efd22018-01-04 23:35:26 -0800599 }
600 }
601
602 impl ToTokens for LitVerbatim {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700603 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700604 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800605 }
606 }
607}
608
609mod value {
610 use super::*;
David Tolnay94d2b792018-04-29 12:26:10 -0700611 use proc_macro2::TokenStream;
David Tolnay360efd22018-01-04 23:35:26 -0800612 use std::char;
613 use std::ops::{Index, RangeFrom};
David Tolnay360efd22018-01-04 23:35:26 -0800614
David Tolnay7d1d1282018-01-06 16:10:51 -0800615 impl Lit {
David Tolnay780292d2018-01-22 23:26:44 -0800616 /// Interpret a Syn literal from a proc-macro2 literal.
617 ///
618 /// Not all proc-macro2 literals are valid Syn literals. In particular,
619 /// doc comments are considered by proc-macro2 to be literals but in Syn
620 /// they are [`Attribute`].
621 ///
622 /// [`Attribute`]: struct.Attribute.html
623 ///
624 /// # Panics
625 ///
626 /// Panics if the input is a doc comment literal.
Alex Crichton9a4dca22018-03-28 06:32:19 -0700627 pub fn new(token: Literal) -> Self {
David Tolnay7d1d1282018-01-06 16:10:51 -0800628 let value = token.to_string();
629
630 match value::byte(&value, 0) {
David Tolnay94d2b792018-04-29 12:26:10 -0700631 b'"' | b'r' => return Lit::Str(LitStr { token: token }),
David Tolnay7d1d1282018-01-06 16:10:51 -0800632 b'b' => match value::byte(&value, 1) {
David Tolnay94d2b792018-04-29 12:26:10 -0700633 b'"' | b'r' => return Lit::ByteStr(LitByteStr { token: token }),
634 b'\'' => return Lit::Byte(LitByte { token: token }),
David Tolnay7d1d1282018-01-06 16:10:51 -0800635 _ => {}
636 },
David Tolnay94d2b792018-04-29 12:26:10 -0700637 b'\'' => return Lit::Char(LitChar { token: token }),
David Tolnayfb84fc02018-10-02 21:01:30 -0700638 b'0'...b'9' => {
639 if number_is_int(&value) {
640 return Lit::Int(LitInt { token: token });
641 } else if number_is_float(&value) {
642 return Lit::Float(LitFloat { token: token });
643 } else {
644 // number overflow
645 return Lit::Verbatim(LitVerbatim { token: token });
646 }
647 }
648 _ => {
649 if value == "true" || value == "false" {
650 return Lit::Bool(LitBool {
651 value: value == "true",
652 span: token.span(),
653 });
654 }
655 }
David Tolnay7d1d1282018-01-06 16:10:51 -0800656 }
657
658 panic!("Unrecognized literal: {}", value);
659 }
660 }
661
662 fn number_is_int(value: &str) -> bool {
663 if number_is_float(value) {
664 false
665 } else {
666 value::parse_lit_int(value).is_some()
667 }
668 }
669
670 fn number_is_float(value: &str) -> bool {
671 if value.contains('.') {
672 true
673 } else if value.starts_with("0x") || value.ends_with("size") {
674 false
675 } else {
676 value.contains('e') || value.contains('E')
677 }
678 }
679
David Tolnay360efd22018-01-04 23:35:26 -0800680 /// Get the byte at offset idx, or a default of `b'\0'` if we're looking
681 /// past the end of the input buffer.
682 pub fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 {
683 let s = s.as_ref();
684 if idx < s.len() {
685 s[idx]
686 } else {
687 0
688 }
689 }
690
691 fn next_chr(s: &str) -> char {
692 s.chars().next().unwrap_or('\0')
693 }
694
695 pub fn parse_lit_str(s: &str) -> String {
696 match byte(s, 0) {
697 b'"' => parse_lit_str_cooked(s),
698 b'r' => parse_lit_str_raw(s),
699 _ => unreachable!(),
700 }
701 }
702
David Tolnay76ebcdd2018-01-05 17:07:26 -0800703 // Clippy false positive
704 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
705 #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))]
David Tolnay360efd22018-01-04 23:35:26 -0800706 fn parse_lit_str_cooked(mut s: &str) -> String {
707 assert_eq!(byte(s, 0), b'"');
708 s = &s[1..];
709
710 let mut out = String::new();
711 'outer: loop {
712 let ch = match byte(s, 0) {
713 b'"' => break,
714 b'\\' => {
715 let b = byte(s, 1);
716 s = &s[2..];
717 match b {
718 b'x' => {
719 let (byte, rest) = backslash_x(s);
720 s = rest;
721 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
David Tolnay76ebcdd2018-01-05 17:07:26 -0800722 char::from_u32(u32::from(byte)).unwrap()
David Tolnay360efd22018-01-04 23:35:26 -0800723 }
724 b'u' => {
David Tolnay76ebcdd2018-01-05 17:07:26 -0800725 let (chr, rest) = backslash_u(s);
David Tolnay360efd22018-01-04 23:35:26 -0800726 s = rest;
727 chr
728 }
729 b'n' => '\n',
730 b'r' => '\r',
731 b't' => '\t',
732 b'\\' => '\\',
733 b'0' => '\0',
734 b'\'' => '\'',
735 b'"' => '"',
David Tolnay61037c62018-01-05 16:21:03 -0800736 b'\r' | b'\n' => loop {
737 let ch = next_chr(s);
738 if ch.is_whitespace() {
739 s = &s[ch.len_utf8()..];
740 } else {
741 continue 'outer;
David Tolnay360efd22018-01-04 23:35:26 -0800742 }
David Tolnay61037c62018-01-05 16:21:03 -0800743 },
744 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800745 }
746 }
747 b'\r' => {
748 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
749 s = &s[2..];
750 '\n'
751 }
752 _ => {
753 let ch = next_chr(s);
754 s = &s[ch.len_utf8()..];
755 ch
756 }
757 };
758 out.push(ch);
759 }
760
761 assert_eq!(s, "\"");
762 out
763 }
764
765 fn parse_lit_str_raw(mut s: &str) -> String {
766 assert_eq!(byte(s, 0), b'r');
767 s = &s[1..];
768
769 let mut pounds = 0;
770 while byte(s, pounds) == b'#' {
771 pounds += 1;
772 }
773 assert_eq!(byte(s, pounds), b'"');
774 assert_eq!(byte(s, s.len() - pounds - 1), b'"');
775 for end in s[s.len() - pounds..].bytes() {
776 assert_eq!(end, b'#');
777 }
778
779 s[pounds + 1..s.len() - pounds - 1].to_owned()
780 }
781
782 pub fn parse_lit_byte_str(s: &str) -> Vec<u8> {
783 assert_eq!(byte(s, 0), b'b');
784 match byte(s, 1) {
785 b'"' => parse_lit_byte_str_cooked(s),
786 b'r' => parse_lit_byte_str_raw(s),
787 _ => unreachable!(),
788 }
789 }
790
David Tolnay76ebcdd2018-01-05 17:07:26 -0800791 // Clippy false positive
792 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
793 #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))]
David Tolnay360efd22018-01-04 23:35:26 -0800794 fn parse_lit_byte_str_cooked(mut s: &str) -> Vec<u8> {
795 assert_eq!(byte(s, 0), b'b');
796 assert_eq!(byte(s, 1), b'"');
797 s = &s[2..];
798
799 // We're going to want to have slices which don't respect codepoint boundaries.
800 let mut s = s.as_bytes();
801
802 let mut out = Vec::new();
803 'outer: loop {
804 let byte = match byte(s, 0) {
805 b'"' => break,
806 b'\\' => {
807 let b = byte(s, 1);
808 s = &s[2..];
809 match b {
810 b'x' => {
811 let (b, rest) = backslash_x(s);
812 s = rest;
813 b
814 }
815 b'n' => b'\n',
816 b'r' => b'\r',
817 b't' => b'\t',
818 b'\\' => b'\\',
819 b'0' => b'\0',
820 b'\'' => b'\'',
821 b'"' => b'"',
David Tolnay61037c62018-01-05 16:21:03 -0800822 b'\r' | b'\n' => loop {
823 let byte = byte(s, 0);
David Tolnay76ebcdd2018-01-05 17:07:26 -0800824 let ch = char::from_u32(u32::from(byte)).unwrap();
David Tolnay61037c62018-01-05 16:21:03 -0800825 if ch.is_whitespace() {
826 s = &s[1..];
827 } else {
828 continue 'outer;
David Tolnay360efd22018-01-04 23:35:26 -0800829 }
David Tolnay61037c62018-01-05 16:21:03 -0800830 },
831 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800832 }
833 }
834 b'\r' => {
835 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
836 s = &s[2..];
837 b'\n'
838 }
839 b => {
840 s = &s[1..];
841 b
842 }
843 };
844 out.push(byte);
845 }
846
847 assert_eq!(s, b"\"");
848 out
849 }
850
851 fn parse_lit_byte_str_raw(s: &str) -> Vec<u8> {
852 assert_eq!(byte(s, 0), b'b');
853 parse_lit_str_raw(&s[1..]).into_bytes()
854 }
855
856 pub fn parse_lit_byte(s: &str) -> u8 {
857 assert_eq!(byte(s, 0), b'b');
858 assert_eq!(byte(s, 1), b'\'');
859
860 // We're going to want to have slices which don't respect codepoint boundaries.
861 let mut s = s[2..].as_bytes();
862
863 let b = match byte(s, 0) {
864 b'\\' => {
865 let b = byte(s, 1);
866 s = &s[2..];
867 match b {
868 b'x' => {
869 let (b, rest) = backslash_x(s);
870 s = rest;
871 b
872 }
873 b'n' => b'\n',
874 b'r' => b'\r',
875 b't' => b'\t',
876 b'\\' => b'\\',
877 b'0' => b'\0',
878 b'\'' => b'\'',
879 b'"' => b'"',
David Tolnay61037c62018-01-05 16:21:03 -0800880 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800881 }
882 }
883 b => {
884 s = &s[1..];
885 b
886 }
887 };
888
889 assert_eq!(byte(s, 0), b'\'');
890 b
891 }
892
893 pub fn parse_lit_char(mut s: &str) -> char {
894 assert_eq!(byte(s, 0), b'\'');
895 s = &s[1..];
896
897 let ch = match byte(s, 0) {
898 b'\\' => {
899 let b = byte(s, 1);
900 s = &s[2..];
901 match b {
902 b'x' => {
903 let (byte, rest) = backslash_x(s);
904 s = rest;
905 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
David Tolnay76ebcdd2018-01-05 17:07:26 -0800906 char::from_u32(u32::from(byte)).unwrap()
David Tolnay360efd22018-01-04 23:35:26 -0800907 }
908 b'u' => {
909 let (chr, rest) = backslash_u(s);
910 s = rest;
911 chr
912 }
913 b'n' => '\n',
914 b'r' => '\r',
915 b't' => '\t',
916 b'\\' => '\\',
917 b'0' => '\0',
918 b'\'' => '\'',
919 b'"' => '"',
David Tolnay61037c62018-01-05 16:21:03 -0800920 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800921 }
922 }
923 _ => {
924 let ch = next_chr(s);
925 s = &s[ch.len_utf8()..];
926 ch
927 }
928 };
929 assert_eq!(s, "\'", "Expected end of char literal");
930 ch
931 }
932
933 fn backslash_x<S>(s: &S) -> (u8, &S)
David Tolnay61037c62018-01-05 16:21:03 -0800934 where
935 S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
David Tolnay360efd22018-01-04 23:35:26 -0800936 {
937 let mut ch = 0;
938 let b0 = byte(s, 0);
939 let b1 = byte(s, 1);
David Tolnaye614f282018-10-27 22:50:12 -0700940 ch += 0x10
941 * match b0 {
942 b'0'...b'9' => b0 - b'0',
943 b'a'...b'f' => 10 + (b0 - b'a'),
944 b'A'...b'F' => 10 + (b0 - b'A'),
945 _ => panic!("unexpected non-hex character after \\x"),
946 };
David Tolnay76ebcdd2018-01-05 17:07:26 -0800947 ch += match b1 {
David Tolnay360efd22018-01-04 23:35:26 -0800948 b'0'...b'9' => b1 - b'0',
949 b'a'...b'f' => 10 + (b1 - b'a'),
950 b'A'...b'F' => 10 + (b1 - b'A'),
951 _ => panic!("unexpected non-hex character after \\x"),
952 };
953 (ch, &s[2..])
954 }
955
956 fn backslash_u(mut s: &str) -> (char, &str) {
957 if byte(s, 0) != b'{' {
958 panic!("expected {{ after \\u");
959 }
960 s = &s[1..];
961
962 let mut ch = 0;
963 for _ in 0..6 {
964 let b = byte(s, 0);
965 match b {
966 b'0'...b'9' => {
967 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800968 ch += u32::from(b - b'0');
David Tolnay360efd22018-01-04 23:35:26 -0800969 s = &s[1..];
970 }
971 b'a'...b'f' => {
972 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800973 ch += u32::from(10 + b - b'a');
David Tolnay360efd22018-01-04 23:35:26 -0800974 s = &s[1..];
975 }
976 b'A'...b'F' => {
977 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800978 ch += u32::from(10 + b - b'A');
David Tolnay360efd22018-01-04 23:35:26 -0800979 s = &s[1..];
980 }
981 b'}' => break,
982 _ => panic!("unexpected non-hex character after \\u"),
983 }
984 }
985 assert!(byte(s, 0) == b'}');
986 s = &s[1..];
987
988 if let Some(ch) = char::from_u32(ch) {
989 (ch, s)
990 } else {
991 panic!("character code {:x} is not a valid unicode character", ch);
992 }
993 }
994
995 pub fn parse_lit_int(mut s: &str) -> Option<u64> {
996 let base = match (byte(s, 0), byte(s, 1)) {
997 (b'0', b'x') => {
998 s = &s[2..];
999 16
1000 }
1001 (b'0', b'o') => {
1002 s = &s[2..];
1003 8
1004 }
1005 (b'0', b'b') => {
1006 s = &s[2..];
1007 2
1008 }
1009 (b'0'...b'9', _) => 10,
1010 _ => unreachable!(),
1011 };
1012
1013 let mut value = 0u64;
1014 loop {
1015 let b = byte(s, 0);
1016 let digit = match b {
David Tolnay76ebcdd2018-01-05 17:07:26 -08001017 b'0'...b'9' => u64::from(b - b'0'),
1018 b'a'...b'f' if base > 10 => 10 + u64::from(b - b'a'),
1019 b'A'...b'F' if base > 10 => 10 + u64::from(b - b'A'),
David Tolnay360efd22018-01-04 23:35:26 -08001020 b'_' => {
1021 s = &s[1..];
1022 continue;
1023 }
1024 // NOTE: Looking at a floating point literal, we don't want to
1025 // consider these integers.
1026 b'.' if base == 10 => return None,
1027 b'e' | b'E' if base == 10 => return None,
1028 _ => break,
1029 };
1030
1031 if digit >= base {
1032 panic!("Unexpected digit {:x} out of base range", digit);
1033 }
1034
1035 value = match value.checked_mul(base) {
1036 Some(value) => value,
1037 None => return None,
1038 };
1039 value = match value.checked_add(digit) {
1040 Some(value) => value,
1041 None => return None,
1042 };
1043 s = &s[1..];
1044 }
1045
1046 Some(value)
1047 }
1048
1049 pub fn parse_lit_float(input: &str) -> f64 {
1050 // Rust's floating point literals are very similar to the ones parsed by
1051 // the standard library, except that rust's literals can contain
1052 // ignorable underscores. Let's remove those underscores.
1053 let mut bytes = input.to_owned().into_bytes();
1054 let mut write = 0;
1055 for read in 0..bytes.len() {
1056 if bytes[read] == b'_' {
1057 continue; // Don't increase write
David Tolnay76ebcdd2018-01-05 17:07:26 -08001058 }
1059 if write != read {
David Tolnay360efd22018-01-04 23:35:26 -08001060 let x = bytes[read];
1061 bytes[write] = x;
1062 }
1063 write += 1;
1064 }
1065 bytes.truncate(write);
1066 let input = String::from_utf8(bytes).unwrap();
David Tolnay76ebcdd2018-01-05 17:07:26 -08001067 let end = input.find('f').unwrap_or_else(|| input.len());
David Tolnay360efd22018-01-04 23:35:26 -08001068 input[..end].parse().unwrap()
1069 }
1070
1071 pub fn to_literal(s: &str) -> Literal {
1072 let stream = s.parse::<TokenStream>().unwrap();
Alex Crichton9a4dca22018-03-28 06:32:19 -07001073 match stream.into_iter().next().unwrap() {
1074 TokenTree::Literal(l) => l,
David Tolnay360efd22018-01-04 23:35:26 -08001075 _ => unreachable!(),
David Tolnayf17fd2f2016-10-07 23:38:08 -07001076 }
1077 }
David Tolnayf4bbbd92016-09-23 14:41:55 -07001078}