blob: 9fd87e87d129770e9b592d05db51e392ff0d13b2 [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 ///
124 /// ```
125 /// # extern crate proc_macro2;
David Tolnay3b0444a2018-09-01 17:17:19 -0700126 /// #
127 /// use proc_macro2::Span;
David Tolnay67fea042018-11-24 14:50:20 -0800128 /// use syn::{Attribute, Error, Ident, Lit, Meta, MetaNameValue, Path, Result};
David Tolnay3b0444a2018-09-01 17:17:19 -0700129 ///
130 /// // Parses the path from an attribute that looks like:
131 /// //
132 /// // #[path = "a::b::c"]
133 /// //
David Tolnay4ac734f2018-11-10 14:19:00 -0800134 /// // or returns `None` if the input is some other attribute.
135 /// fn get_path(attr: &Attribute) -> Result<Option<Path>> {
136 /// if !attr.path.is_ident("path") {
137 /// return Ok(None);
David Tolnay3b0444a2018-09-01 17:17:19 -0700138 /// }
139 ///
David Tolnay4ac734f2018-11-10 14:19:00 -0800140 /// match attr.parse_meta()? {
David Tolnay3b0444a2018-09-01 17:17:19 -0700141 /// Meta::NameValue(MetaNameValue { lit: Lit::Str(lit_str), .. }) => {
David Tolnay4ac734f2018-11-10 14:19:00 -0800142 /// lit_str.parse().map(Some)
David Tolnay3b0444a2018-09-01 17:17:19 -0700143 /// }
144 /// _ => {
145 /// let error_span = attr.bracket_token.span;
146 /// let message = "expected #[path = \"...\"]";
147 /// Err(Error::new(error_span, message))
148 /// }
149 /// }
150 /// }
151 /// ```
David Tolnayd53ac2b2018-01-27 19:00:06 -0800152 #[cfg(feature = "parsing")]
David Tolnaye82a2b12018-08-30 16:31:10 -0700153 pub fn parse<T: Parse>(&self) -> Result<T, Error> {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700154 use proc_macro2::Group;
155
David Tolnayd53ac2b2018-01-27 19:00:06 -0800156 // Parse string literal into a token stream with every span equal to the
157 // original literal's span.
David Tolnayad4b2472018-08-25 08:25:24 -0400158 fn spanned_tokens(s: &LitStr) -> Result<TokenStream, Error> {
David Tolnayd53ac2b2018-01-27 19:00:06 -0800159 let stream = ::parse_str(&s.value())?;
Alex Crichton9a4dca22018-03-28 06:32:19 -0700160 Ok(respan_token_stream(stream, s.span()))
David Tolnayd53ac2b2018-01-27 19:00:06 -0800161 }
162
163 // Token stream with every span replaced by the given one.
164 fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
David Tolnay94d2b792018-04-29 12:26:10 -0700165 stream
166 .into_iter()
167 .map(|token| respan_token_tree(token, span))
168 .collect()
David Tolnayd53ac2b2018-01-27 19:00:06 -0800169 }
170
171 // Token tree with every span replaced by the given one.
Alex Crichton9a4dca22018-03-28 06:32:19 -0700172 fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
173 match token {
174 TokenTree::Group(ref mut g) => {
175 let stream = respan_token_stream(g.stream().clone(), span);
176 *g = Group::new(g.delimiter(), stream);
177 g.set_span(span);
178 }
179 ref mut other => other.set_span(span),
David Tolnayd53ac2b2018-01-27 19:00:06 -0800180 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700181 token
David Tolnayd53ac2b2018-01-27 19:00:06 -0800182 }
183
184 spanned_tokens(self).and_then(::parse2)
185 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700186
187 pub fn span(&self) -> Span {
188 self.token.span()
189 }
190
191 pub fn set_span(&mut self, span: Span) {
192 self.token.set_span(span)
193 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700194}
195
David Tolnay360efd22018-01-04 23:35:26 -0800196impl LitByteStr {
197 pub fn new(value: &[u8], span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700198 let mut token = Literal::byte_string(value);
199 token.set_span(span);
200 LitByteStr { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800201 }
202
203 pub fn value(&self) -> Vec<u8> {
204 value::parse_lit_byte_str(&self.token.to_string())
205 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700206
207 pub fn span(&self) -> Span {
208 self.token.span()
209 }
210
211 pub fn set_span(&mut self, span: Span) {
212 self.token.set_span(span)
213 }
David Tolnay360efd22018-01-04 23:35:26 -0800214}
215
216impl LitByte {
217 pub fn new(value: u8, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700218 let mut token = Literal::u8_suffixed(value);
219 token.set_span(span);
220 LitByte { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800221 }
222
223 pub fn value(&self) -> u8 {
224 value::parse_lit_byte(&self.token.to_string())
225 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700226
227 pub fn span(&self) -> Span {
228 self.token.span()
229 }
230
231 pub fn set_span(&mut self, span: Span) {
232 self.token.set_span(span)
233 }
David Tolnay360efd22018-01-04 23:35:26 -0800234}
235
236impl LitChar {
237 pub fn new(value: char, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700238 let mut token = Literal::character(value);
239 token.set_span(span);
240 LitChar { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800241 }
242
243 pub fn value(&self) -> char {
244 value::parse_lit_char(&self.token.to_string())
245 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700246
247 pub fn span(&self) -> Span {
248 self.token.span()
249 }
250
251 pub fn set_span(&mut self, span: Span) {
252 self.token.set_span(span)
253 }
David Tolnay360efd22018-01-04 23:35:26 -0800254}
255
256impl LitInt {
257 pub fn new(value: u64, suffix: IntSuffix, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700258 let mut token = match suffix {
259 IntSuffix::Isize => Literal::isize_suffixed(value as isize),
260 IntSuffix::I8 => Literal::i8_suffixed(value as i8),
261 IntSuffix::I16 => Literal::i16_suffixed(value as i16),
262 IntSuffix::I32 => Literal::i32_suffixed(value as i32),
263 IntSuffix::I64 => Literal::i64_suffixed(value as i64),
264 IntSuffix::I128 => value::to_literal(&format!("{}i128", value)),
265 IntSuffix::Usize => Literal::usize_suffixed(value as usize),
266 IntSuffix::U8 => Literal::u8_suffixed(value as u8),
267 IntSuffix::U16 => Literal::u16_suffixed(value as u16),
268 IntSuffix::U32 => Literal::u32_suffixed(value as u32),
269 IntSuffix::U64 => Literal::u64_suffixed(value),
270 IntSuffix::U128 => value::to_literal(&format!("{}u128", value)),
271 IntSuffix::None => Literal::u64_unsuffixed(value),
272 };
273 token.set_span(span);
274 LitInt { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800275 }
276
277 pub fn value(&self) -> u64 {
278 value::parse_lit_int(&self.token.to_string()).unwrap()
279 }
280
281 pub fn suffix(&self) -> IntSuffix {
282 let value = self.token.to_string();
283 for (s, suffix) in vec![
284 ("i8", IntSuffix::I8),
285 ("i16", IntSuffix::I16),
286 ("i32", IntSuffix::I32),
287 ("i64", IntSuffix::I64),
288 ("i128", IntSuffix::I128),
289 ("isize", IntSuffix::Isize),
290 ("u8", IntSuffix::U8),
291 ("u16", IntSuffix::U16),
292 ("u32", IntSuffix::U32),
293 ("u64", IntSuffix::U64),
294 ("u128", IntSuffix::U128),
295 ("usize", IntSuffix::Usize),
296 ] {
297 if value.ends_with(s) {
298 return suffix;
299 }
300 }
301 IntSuffix::None
302 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700303
304 pub fn span(&self) -> Span {
305 self.token.span()
306 }
307
308 pub fn set_span(&mut self, span: Span) {
309 self.token.set_span(span)
310 }
David Tolnay360efd22018-01-04 23:35:26 -0800311}
312
313impl LitFloat {
314 pub fn new(value: f64, suffix: FloatSuffix, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700315 let mut token = match suffix {
316 FloatSuffix::F32 => Literal::f32_suffixed(value as f32),
317 FloatSuffix::F64 => Literal::f64_suffixed(value),
318 FloatSuffix::None => Literal::f64_unsuffixed(value),
319 };
320 token.set_span(span);
321 LitFloat { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800322 }
323
324 pub fn value(&self) -> f64 {
325 value::parse_lit_float(&self.token.to_string())
326 }
327
328 pub fn suffix(&self) -> FloatSuffix {
329 let value = self.token.to_string();
David Tolnay61037c62018-01-05 16:21:03 -0800330 for (s, suffix) in vec![("f32", FloatSuffix::F32), ("f64", FloatSuffix::F64)] {
David Tolnay360efd22018-01-04 23:35:26 -0800331 if value.ends_with(s) {
332 return suffix;
333 }
334 }
335 FloatSuffix::None
336 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700337
338 pub fn span(&self) -> Span {
339 self.token.span()
340 }
341
342 pub fn set_span(&mut self, span: Span) {
343 self.token.set_span(span)
344 }
David Tolnay360efd22018-01-04 23:35:26 -0800345}
346
347macro_rules! lit_extra_traits {
348 ($ty:ident, $field:ident) => {
349 #[cfg(feature = "extra-traits")]
350 impl Eq for $ty {}
351
352 #[cfg(feature = "extra-traits")]
353 impl PartialEq for $ty {
354 fn eq(&self, other: &Self) -> bool {
355 self.$field.to_string() == other.$field.to_string()
356 }
357 }
358
359 #[cfg(feature = "extra-traits")]
360 impl Hash for $ty {
361 fn hash<H>(&self, state: &mut H)
362 where
363 H: Hasher,
364 {
365 self.$field.to_string().hash(state);
366 }
David Tolnay9c76bcb2017-12-26 23:14:59 -0500367 }
David Tolnay6a170ce2018-08-26 22:29:24 -0700368
369 #[cfg(feature = "parsing")]
370 #[doc(hidden)]
371 #[allow(non_snake_case)]
372 pub fn $ty(marker: lookahead::TokenMarker) -> $ty {
373 match marker {}
374 }
David Tolnay94d2b792018-04-29 12:26:10 -0700375 };
David Tolnayf4bbbd92016-09-23 14:41:55 -0700376}
377
Alex Crichton9a4dca22018-03-28 06:32:19 -0700378impl LitVerbatim {
379 pub fn span(&self) -> Span {
380 self.token.span()
381 }
382
383 pub fn set_span(&mut self, span: Span) {
384 self.token.set_span(span)
385 }
386}
387
David Tolnay360efd22018-01-04 23:35:26 -0800388lit_extra_traits!(LitStr, token);
389lit_extra_traits!(LitByteStr, token);
390lit_extra_traits!(LitByte, token);
391lit_extra_traits!(LitChar, token);
392lit_extra_traits!(LitInt, token);
393lit_extra_traits!(LitFloat, token);
394lit_extra_traits!(LitBool, value);
395lit_extra_traits!(LitVerbatim, token);
396
397ast_enum! {
David Tolnay05658502018-01-07 09:56:37 -0800398 /// The style of a string literal, either plain quoted or a raw string like
David Tolnayabf5c2e2018-01-06 23:30:04 -0800399 /// `r##"data"##`.
David Tolnay461d98e2018-01-07 11:07:19 -0800400 ///
401 /// *This type is available if Syn is built with the `"derive"` or `"full"`
402 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800403 pub enum StrStyle #no_visit {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800404 /// An ordinary string like `"data"`.
David Tolnay360efd22018-01-04 23:35:26 -0800405 Cooked,
David Tolnayabf5c2e2018-01-06 23:30:04 -0800406 /// A raw string like `r##"data"##`.
David Tolnay360efd22018-01-04 23:35:26 -0800407 ///
408 /// The unsigned integer is the number of `#` symbols used.
409 Raw(usize),
Alex Crichton62a0a592017-05-22 13:58:53 -0700410 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700411}
412
David Tolnay360efd22018-01-04 23:35:26 -0800413ast_enum! {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800414 /// The suffix on an integer literal if any, like the `u8` in `127u8`.
David Tolnay461d98e2018-01-07 11:07:19 -0800415 ///
416 /// *This type is available if Syn is built with the `"derive"` or `"full"`
417 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800418 pub enum IntSuffix #no_visit {
419 I8,
420 I16,
421 I32,
422 I64,
423 I128,
424 Isize,
425 U8,
426 U16,
427 U32,
428 U64,
429 U128,
430 Usize,
431 None,
Pascal Hertleif36342c52016-10-19 10:31:42 +0200432 }
433}
434
David Tolnay360efd22018-01-04 23:35:26 -0800435ast_enum! {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800436 /// The suffix on a floating point literal if any, like the `f32` in
437 /// `1.0f32`.
David Tolnay461d98e2018-01-07 11:07:19 -0800438 ///
439 /// *This type is available if Syn is built with the `"derive"` or `"full"`
440 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800441 pub enum FloatSuffix #no_visit {
442 F32,
443 F64,
444 None,
Alex Crichton2e0229c2017-05-23 09:34:50 -0700445 }
David Tolnay5fe14fc2017-01-27 16:22:08 -0800446}
447
448#[cfg(feature = "parsing")]
David Tolnay4fb71232018-08-25 23:14:50 -0400449#[doc(hidden)]
450#[allow(non_snake_case)]
451pub fn Lit(marker: lookahead::TokenMarker) -> Lit {
452 match marker {}
453}
454
455#[cfg(feature = "parsing")]
David Tolnayf4bbbd92016-09-23 14:41:55 -0700456pub mod parsing {
457 use super::*;
David Tolnay4fb71232018-08-25 23:14:50 -0400458 use parse::{Parse, ParseStream, Result};
David Tolnayf4bbbd92016-09-23 14:41:55 -0700459
David Tolnay4fb71232018-08-25 23:14:50 -0400460 impl Parse for Lit {
461 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay924e0af2018-09-01 13:07:34 -0700462 input.step(|cursor| {
463 if let Some((lit, rest)) = cursor.literal() {
464 return Ok((Lit::new(lit), rest));
465 }
466 while let Some((ident, rest)) = cursor.ident() {
467 let value = if ident == "true" {
468 true
469 } else if ident == "false" {
470 false
471 } else {
472 break;
473 };
474 let lit_bool = LitBool {
475 value: value,
476 span: ident.span(),
477 };
478 return Ok((Lit::Bool(lit_bool), rest));
479 }
480 Err(cursor.error("expected literal"))
David Tolnay4fb71232018-08-25 23:14:50 -0400481 })
Sergio Benitez5680d6a2017-12-29 11:20:29 -0800482 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700483 }
David Tolnay360efd22018-01-04 23:35:26 -0800484
David Tolnaya7d69fc2018-08-26 13:30:24 -0400485 impl Parse for LitStr {
486 fn parse(input: ParseStream) -> Result<Self> {
487 let head = input.fork();
488 match input.parse()? {
489 Lit::Str(lit) => Ok(lit),
490 _ => Err(head.error("expected string literal")),
491 }
492 }
493 }
David Tolnay360efd22018-01-04 23:35:26 -0800494
David Tolnaya7d69fc2018-08-26 13:30:24 -0400495 impl Parse for LitByteStr {
496 fn parse(input: ParseStream) -> Result<Self> {
497 let head = input.fork();
498 match input.parse()? {
499 Lit::ByteStr(lit) => Ok(lit),
500 _ => Err(head.error("expected byte string literal")),
501 }
502 }
503 }
David Tolnay360efd22018-01-04 23:35:26 -0800504
David Tolnaya7d69fc2018-08-26 13:30:24 -0400505 impl Parse for LitByte {
506 fn parse(input: ParseStream) -> Result<Self> {
507 let head = input.fork();
508 match input.parse()? {
509 Lit::Byte(lit) => Ok(lit),
510 _ => Err(head.error("expected byte literal")),
511 }
512 }
513 }
David Tolnay360efd22018-01-04 23:35:26 -0800514
David Tolnaya7d69fc2018-08-26 13:30:24 -0400515 impl Parse for LitChar {
516 fn parse(input: ParseStream) -> Result<Self> {
517 let head = input.fork();
518 match input.parse()? {
519 Lit::Char(lit) => Ok(lit),
520 _ => Err(head.error("expected character literal")),
521 }
522 }
523 }
David Tolnay360efd22018-01-04 23:35:26 -0800524
David Tolnaya7d69fc2018-08-26 13:30:24 -0400525 impl Parse for LitInt {
526 fn parse(input: ParseStream) -> Result<Self> {
527 let head = input.fork();
528 match input.parse()? {
529 Lit::Int(lit) => Ok(lit),
530 _ => Err(head.error("expected integer literal")),
531 }
532 }
533 }
David Tolnay360efd22018-01-04 23:35:26 -0800534
David Tolnaya7d69fc2018-08-26 13:30:24 -0400535 impl Parse for LitFloat {
536 fn parse(input: ParseStream) -> Result<Self> {
537 let head = input.fork();
538 match input.parse()? {
539 Lit::Float(lit) => Ok(lit),
540 _ => Err(head.error("expected floating point literal")),
541 }
542 }
543 }
David Tolnay360efd22018-01-04 23:35:26 -0800544
David Tolnaya7d69fc2018-08-26 13:30:24 -0400545 impl Parse for LitBool {
546 fn parse(input: ParseStream) -> Result<Self> {
547 let head = input.fork();
548 match input.parse()? {
549 Lit::Bool(lit) => Ok(lit),
550 _ => Err(head.error("expected boolean literal")),
551 }
552 }
553 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700554}
555
556#[cfg(feature = "printing")]
557mod printing {
558 use super::*;
Alex Crichtona74a1c82018-05-16 10:20:44 -0700559 use proc_macro2::TokenStream;
David Tolnay65fb5662018-05-20 20:02:28 -0700560 use quote::{ToTokens, TokenStreamExt};
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700561
David Tolnay360efd22018-01-04 23:35:26 -0800562 impl ToTokens for LitStr {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700563 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700564 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800565 }
566 }
567
568 impl ToTokens for LitByteStr {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700569 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700570 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800571 }
572 }
573
574 impl ToTokens for LitByte {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700575 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700576 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800577 }
578 }
579
580 impl ToTokens for LitChar {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700581 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700582 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800583 }
584 }
585
586 impl ToTokens for LitInt {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700587 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700588 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800589 }
590 }
591
592 impl ToTokens for LitFloat {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700593 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700594 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800595 }
596 }
597
598 impl ToTokens for LitBool {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700599 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700600 let s = if self.value { "true" } else { "false" };
Alex Crichtona74a1c82018-05-16 10:20:44 -0700601 tokens.append(Ident::new(s, self.span));
David Tolnay360efd22018-01-04 23:35:26 -0800602 }
603 }
604
605 impl ToTokens for LitVerbatim {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700606 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700607 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800608 }
609 }
610}
611
612mod value {
613 use super::*;
David Tolnay94d2b792018-04-29 12:26:10 -0700614 use proc_macro2::TokenStream;
David Tolnay360efd22018-01-04 23:35:26 -0800615 use std::char;
616 use std::ops::{Index, RangeFrom};
David Tolnay360efd22018-01-04 23:35:26 -0800617
David Tolnay7d1d1282018-01-06 16:10:51 -0800618 impl Lit {
David Tolnay780292d2018-01-22 23:26:44 -0800619 /// Interpret a Syn literal from a proc-macro2 literal.
620 ///
621 /// Not all proc-macro2 literals are valid Syn literals. In particular,
622 /// doc comments are considered by proc-macro2 to be literals but in Syn
623 /// they are [`Attribute`].
624 ///
625 /// [`Attribute`]: struct.Attribute.html
626 ///
627 /// # Panics
628 ///
629 /// Panics if the input is a doc comment literal.
Alex Crichton9a4dca22018-03-28 06:32:19 -0700630 pub fn new(token: Literal) -> Self {
David Tolnay7d1d1282018-01-06 16:10:51 -0800631 let value = token.to_string();
632
633 match value::byte(&value, 0) {
David Tolnay94d2b792018-04-29 12:26:10 -0700634 b'"' | b'r' => return Lit::Str(LitStr { token: token }),
David Tolnay7d1d1282018-01-06 16:10:51 -0800635 b'b' => match value::byte(&value, 1) {
David Tolnay94d2b792018-04-29 12:26:10 -0700636 b'"' | b'r' => return Lit::ByteStr(LitByteStr { token: token }),
637 b'\'' => return Lit::Byte(LitByte { token: token }),
David Tolnay7d1d1282018-01-06 16:10:51 -0800638 _ => {}
639 },
David Tolnay94d2b792018-04-29 12:26:10 -0700640 b'\'' => return Lit::Char(LitChar { token: token }),
David Tolnayfb84fc02018-10-02 21:01:30 -0700641 b'0'...b'9' => {
642 if number_is_int(&value) {
643 return Lit::Int(LitInt { token: token });
644 } else if number_is_float(&value) {
645 return Lit::Float(LitFloat { token: token });
646 } else {
647 // number overflow
648 return Lit::Verbatim(LitVerbatim { token: token });
649 }
650 }
651 _ => {
652 if value == "true" || value == "false" {
653 return Lit::Bool(LitBool {
654 value: value == "true",
655 span: token.span(),
656 });
657 }
658 }
David Tolnay7d1d1282018-01-06 16:10:51 -0800659 }
660
661 panic!("Unrecognized literal: {}", value);
662 }
663 }
664
665 fn number_is_int(value: &str) -> bool {
666 if number_is_float(value) {
667 false
668 } else {
669 value::parse_lit_int(value).is_some()
670 }
671 }
672
673 fn number_is_float(value: &str) -> bool {
674 if value.contains('.') {
675 true
676 } else if value.starts_with("0x") || value.ends_with("size") {
677 false
678 } else {
679 value.contains('e') || value.contains('E')
680 }
681 }
682
David Tolnay360efd22018-01-04 23:35:26 -0800683 /// Get the byte at offset idx, or a default of `b'\0'` if we're looking
684 /// past the end of the input buffer.
685 pub fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 {
686 let s = s.as_ref();
687 if idx < s.len() {
688 s[idx]
689 } else {
690 0
691 }
692 }
693
694 fn next_chr(s: &str) -> char {
695 s.chars().next().unwrap_or('\0')
696 }
697
698 pub fn parse_lit_str(s: &str) -> String {
699 match byte(s, 0) {
700 b'"' => parse_lit_str_cooked(s),
701 b'r' => parse_lit_str_raw(s),
702 _ => unreachable!(),
703 }
704 }
705
David Tolnay76ebcdd2018-01-05 17:07:26 -0800706 // Clippy false positive
707 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
708 #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))]
David Tolnay360efd22018-01-04 23:35:26 -0800709 fn parse_lit_str_cooked(mut s: &str) -> String {
710 assert_eq!(byte(s, 0), b'"');
711 s = &s[1..];
712
713 let mut out = String::new();
714 'outer: loop {
715 let ch = match byte(s, 0) {
716 b'"' => break,
717 b'\\' => {
718 let b = byte(s, 1);
719 s = &s[2..];
720 match b {
721 b'x' => {
722 let (byte, rest) = backslash_x(s);
723 s = rest;
724 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
David Tolnay76ebcdd2018-01-05 17:07:26 -0800725 char::from_u32(u32::from(byte)).unwrap()
David Tolnay360efd22018-01-04 23:35:26 -0800726 }
727 b'u' => {
David Tolnay76ebcdd2018-01-05 17:07:26 -0800728 let (chr, rest) = backslash_u(s);
David Tolnay360efd22018-01-04 23:35:26 -0800729 s = rest;
730 chr
731 }
732 b'n' => '\n',
733 b'r' => '\r',
734 b't' => '\t',
735 b'\\' => '\\',
736 b'0' => '\0',
737 b'\'' => '\'',
738 b'"' => '"',
David Tolnay61037c62018-01-05 16:21:03 -0800739 b'\r' | b'\n' => loop {
740 let ch = next_chr(s);
741 if ch.is_whitespace() {
742 s = &s[ch.len_utf8()..];
743 } else {
744 continue 'outer;
David Tolnay360efd22018-01-04 23:35:26 -0800745 }
David Tolnay61037c62018-01-05 16:21:03 -0800746 },
747 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800748 }
749 }
750 b'\r' => {
751 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
752 s = &s[2..];
753 '\n'
754 }
755 _ => {
756 let ch = next_chr(s);
757 s = &s[ch.len_utf8()..];
758 ch
759 }
760 };
761 out.push(ch);
762 }
763
764 assert_eq!(s, "\"");
765 out
766 }
767
768 fn parse_lit_str_raw(mut s: &str) -> String {
769 assert_eq!(byte(s, 0), b'r');
770 s = &s[1..];
771
772 let mut pounds = 0;
773 while byte(s, pounds) == b'#' {
774 pounds += 1;
775 }
776 assert_eq!(byte(s, pounds), b'"');
777 assert_eq!(byte(s, s.len() - pounds - 1), b'"');
778 for end in s[s.len() - pounds..].bytes() {
779 assert_eq!(end, b'#');
780 }
781
782 s[pounds + 1..s.len() - pounds - 1].to_owned()
783 }
784
785 pub fn parse_lit_byte_str(s: &str) -> Vec<u8> {
786 assert_eq!(byte(s, 0), b'b');
787 match byte(s, 1) {
788 b'"' => parse_lit_byte_str_cooked(s),
789 b'r' => parse_lit_byte_str_raw(s),
790 _ => unreachable!(),
791 }
792 }
793
David Tolnay76ebcdd2018-01-05 17:07:26 -0800794 // Clippy false positive
795 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
796 #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))]
David Tolnay360efd22018-01-04 23:35:26 -0800797 fn parse_lit_byte_str_cooked(mut s: &str) -> Vec<u8> {
798 assert_eq!(byte(s, 0), b'b');
799 assert_eq!(byte(s, 1), b'"');
800 s = &s[2..];
801
802 // We're going to want to have slices which don't respect codepoint boundaries.
803 let mut s = s.as_bytes();
804
805 let mut out = Vec::new();
806 'outer: loop {
807 let byte = match byte(s, 0) {
808 b'"' => break,
809 b'\\' => {
810 let b = byte(s, 1);
811 s = &s[2..];
812 match b {
813 b'x' => {
814 let (b, rest) = backslash_x(s);
815 s = rest;
816 b
817 }
818 b'n' => b'\n',
819 b'r' => b'\r',
820 b't' => b'\t',
821 b'\\' => b'\\',
822 b'0' => b'\0',
823 b'\'' => b'\'',
824 b'"' => b'"',
David Tolnay61037c62018-01-05 16:21:03 -0800825 b'\r' | b'\n' => loop {
826 let byte = byte(s, 0);
David Tolnay76ebcdd2018-01-05 17:07:26 -0800827 let ch = char::from_u32(u32::from(byte)).unwrap();
David Tolnay61037c62018-01-05 16:21:03 -0800828 if ch.is_whitespace() {
829 s = &s[1..];
830 } else {
831 continue 'outer;
David Tolnay360efd22018-01-04 23:35:26 -0800832 }
David Tolnay61037c62018-01-05 16:21:03 -0800833 },
834 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800835 }
836 }
837 b'\r' => {
838 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
839 s = &s[2..];
840 b'\n'
841 }
842 b => {
843 s = &s[1..];
844 b
845 }
846 };
847 out.push(byte);
848 }
849
850 assert_eq!(s, b"\"");
851 out
852 }
853
854 fn parse_lit_byte_str_raw(s: &str) -> Vec<u8> {
855 assert_eq!(byte(s, 0), b'b');
856 parse_lit_str_raw(&s[1..]).into_bytes()
857 }
858
859 pub fn parse_lit_byte(s: &str) -> u8 {
860 assert_eq!(byte(s, 0), b'b');
861 assert_eq!(byte(s, 1), b'\'');
862
863 // We're going to want to have slices which don't respect codepoint boundaries.
864 let mut s = s[2..].as_bytes();
865
866 let b = match byte(s, 0) {
867 b'\\' => {
868 let b = byte(s, 1);
869 s = &s[2..];
870 match b {
871 b'x' => {
872 let (b, rest) = backslash_x(s);
873 s = rest;
874 b
875 }
876 b'n' => b'\n',
877 b'r' => b'\r',
878 b't' => b'\t',
879 b'\\' => b'\\',
880 b'0' => b'\0',
881 b'\'' => b'\'',
882 b'"' => b'"',
David Tolnay61037c62018-01-05 16:21:03 -0800883 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800884 }
885 }
886 b => {
887 s = &s[1..];
888 b
889 }
890 };
891
892 assert_eq!(byte(s, 0), b'\'');
893 b
894 }
895
896 pub fn parse_lit_char(mut s: &str) -> char {
897 assert_eq!(byte(s, 0), b'\'');
898 s = &s[1..];
899
900 let ch = match byte(s, 0) {
901 b'\\' => {
902 let b = byte(s, 1);
903 s = &s[2..];
904 match b {
905 b'x' => {
906 let (byte, rest) = backslash_x(s);
907 s = rest;
908 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
David Tolnay76ebcdd2018-01-05 17:07:26 -0800909 char::from_u32(u32::from(byte)).unwrap()
David Tolnay360efd22018-01-04 23:35:26 -0800910 }
911 b'u' => {
912 let (chr, rest) = backslash_u(s);
913 s = rest;
914 chr
915 }
916 b'n' => '\n',
917 b'r' => '\r',
918 b't' => '\t',
919 b'\\' => '\\',
920 b'0' => '\0',
921 b'\'' => '\'',
922 b'"' => '"',
David Tolnay61037c62018-01-05 16:21:03 -0800923 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800924 }
925 }
926 _ => {
927 let ch = next_chr(s);
928 s = &s[ch.len_utf8()..];
929 ch
930 }
931 };
932 assert_eq!(s, "\'", "Expected end of char literal");
933 ch
934 }
935
936 fn backslash_x<S>(s: &S) -> (u8, &S)
David Tolnay61037c62018-01-05 16:21:03 -0800937 where
938 S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
David Tolnay360efd22018-01-04 23:35:26 -0800939 {
940 let mut ch = 0;
941 let b0 = byte(s, 0);
942 let b1 = byte(s, 1);
David Tolnaye614f282018-10-27 22:50:12 -0700943 ch += 0x10
944 * match b0 {
945 b'0'...b'9' => b0 - b'0',
946 b'a'...b'f' => 10 + (b0 - b'a'),
947 b'A'...b'F' => 10 + (b0 - b'A'),
948 _ => panic!("unexpected non-hex character after \\x"),
949 };
David Tolnay76ebcdd2018-01-05 17:07:26 -0800950 ch += match b1 {
David Tolnay360efd22018-01-04 23:35:26 -0800951 b'0'...b'9' => b1 - b'0',
952 b'a'...b'f' => 10 + (b1 - b'a'),
953 b'A'...b'F' => 10 + (b1 - b'A'),
954 _ => panic!("unexpected non-hex character after \\x"),
955 };
956 (ch, &s[2..])
957 }
958
959 fn backslash_u(mut s: &str) -> (char, &str) {
960 if byte(s, 0) != b'{' {
961 panic!("expected {{ after \\u");
962 }
963 s = &s[1..];
964
965 let mut ch = 0;
966 for _ in 0..6 {
967 let b = byte(s, 0);
968 match b {
969 b'0'...b'9' => {
970 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800971 ch += u32::from(b - b'0');
David Tolnay360efd22018-01-04 23:35:26 -0800972 s = &s[1..];
973 }
974 b'a'...b'f' => {
975 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800976 ch += u32::from(10 + b - b'a');
David Tolnay360efd22018-01-04 23:35:26 -0800977 s = &s[1..];
978 }
979 b'A'...b'F' => {
980 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800981 ch += u32::from(10 + b - b'A');
David Tolnay360efd22018-01-04 23:35:26 -0800982 s = &s[1..];
983 }
984 b'}' => break,
985 _ => panic!("unexpected non-hex character after \\u"),
986 }
987 }
988 assert!(byte(s, 0) == b'}');
989 s = &s[1..];
990
991 if let Some(ch) = char::from_u32(ch) {
992 (ch, s)
993 } else {
994 panic!("character code {:x} is not a valid unicode character", ch);
995 }
996 }
997
998 pub fn parse_lit_int(mut s: &str) -> Option<u64> {
999 let base = match (byte(s, 0), byte(s, 1)) {
1000 (b'0', b'x') => {
1001 s = &s[2..];
1002 16
1003 }
1004 (b'0', b'o') => {
1005 s = &s[2..];
1006 8
1007 }
1008 (b'0', b'b') => {
1009 s = &s[2..];
1010 2
1011 }
1012 (b'0'...b'9', _) => 10,
1013 _ => unreachable!(),
1014 };
1015
1016 let mut value = 0u64;
1017 loop {
1018 let b = byte(s, 0);
1019 let digit = match b {
David Tolnay76ebcdd2018-01-05 17:07:26 -08001020 b'0'...b'9' => u64::from(b - b'0'),
1021 b'a'...b'f' if base > 10 => 10 + u64::from(b - b'a'),
1022 b'A'...b'F' if base > 10 => 10 + u64::from(b - b'A'),
David Tolnay360efd22018-01-04 23:35:26 -08001023 b'_' => {
1024 s = &s[1..];
1025 continue;
1026 }
1027 // NOTE: Looking at a floating point literal, we don't want to
1028 // consider these integers.
1029 b'.' if base == 10 => return None,
1030 b'e' | b'E' if base == 10 => return None,
1031 _ => break,
1032 };
1033
1034 if digit >= base {
1035 panic!("Unexpected digit {:x} out of base range", digit);
1036 }
1037
1038 value = match value.checked_mul(base) {
1039 Some(value) => value,
1040 None => return None,
1041 };
1042 value = match value.checked_add(digit) {
1043 Some(value) => value,
1044 None => return None,
1045 };
1046 s = &s[1..];
1047 }
1048
1049 Some(value)
1050 }
1051
1052 pub fn parse_lit_float(input: &str) -> f64 {
1053 // Rust's floating point literals are very similar to the ones parsed by
1054 // the standard library, except that rust's literals can contain
1055 // ignorable underscores. Let's remove those underscores.
1056 let mut bytes = input.to_owned().into_bytes();
1057 let mut write = 0;
1058 for read in 0..bytes.len() {
1059 if bytes[read] == b'_' {
1060 continue; // Don't increase write
David Tolnay76ebcdd2018-01-05 17:07:26 -08001061 }
1062 if write != read {
David Tolnay360efd22018-01-04 23:35:26 -08001063 let x = bytes[read];
1064 bytes[write] = x;
1065 }
1066 write += 1;
1067 }
1068 bytes.truncate(write);
1069 let input = String::from_utf8(bytes).unwrap();
David Tolnay76ebcdd2018-01-05 17:07:26 -08001070 let end = input.find('f').unwrap_or_else(|| input.len());
David Tolnay360efd22018-01-04 23:35:26 -08001071 input[..end].parse().unwrap()
1072 }
1073
1074 pub fn to_literal(s: &str) -> Literal {
1075 let stream = s.parse::<TokenStream>().unwrap();
Alex Crichton9a4dca22018-03-28 06:32:19 -07001076 match stream.into_iter().next().unwrap() {
1077 TokenTree::Literal(l) => l,
David Tolnay360efd22018-01-04 23:35:26 -08001078 _ => unreachable!(),
David Tolnayf17fd2f2016-10-07 23:38:08 -07001079 }
1080 }
David Tolnayf4bbbd92016-09-23 14:41:55 -07001081}