blob: d58730a79c4eed7afc13c7bac8fafd82c355a58d [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 /// _ => {
143 /// let error_span = attr.bracket_token.span;
144 /// let message = "expected #[path = \"...\"]";
145 /// Err(Error::new(error_span, message))
146 /// }
147 /// }
148 /// }
149 /// ```
David Tolnayd53ac2b2018-01-27 19:00:06 -0800150 #[cfg(feature = "parsing")]
David Tolnaye82a2b12018-08-30 16:31:10 -0700151 pub fn parse<T: Parse>(&self) -> Result<T, Error> {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700152 use proc_macro2::Group;
153
David Tolnayd53ac2b2018-01-27 19:00:06 -0800154 // Parse string literal into a token stream with every span equal to the
155 // original literal's span.
David Tolnayad4b2472018-08-25 08:25:24 -0400156 fn spanned_tokens(s: &LitStr) -> Result<TokenStream, Error> {
David Tolnayd53ac2b2018-01-27 19:00:06 -0800157 let stream = ::parse_str(&s.value())?;
Alex Crichton9a4dca22018-03-28 06:32:19 -0700158 Ok(respan_token_stream(stream, s.span()))
David Tolnayd53ac2b2018-01-27 19:00:06 -0800159 }
160
161 // Token stream with every span replaced by the given one.
162 fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
David Tolnay94d2b792018-04-29 12:26:10 -0700163 stream
164 .into_iter()
165 .map(|token| respan_token_tree(token, span))
166 .collect()
David Tolnayd53ac2b2018-01-27 19:00:06 -0800167 }
168
169 // Token tree with every span replaced by the given one.
Alex Crichton9a4dca22018-03-28 06:32:19 -0700170 fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
171 match token {
172 TokenTree::Group(ref mut g) => {
173 let stream = respan_token_stream(g.stream().clone(), span);
174 *g = Group::new(g.delimiter(), stream);
175 g.set_span(span);
176 }
177 ref mut other => other.set_span(span),
David Tolnayd53ac2b2018-01-27 19:00:06 -0800178 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700179 token
David Tolnayd53ac2b2018-01-27 19:00:06 -0800180 }
181
182 spanned_tokens(self).and_then(::parse2)
183 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700184
185 pub fn span(&self) -> Span {
186 self.token.span()
187 }
188
189 pub fn set_span(&mut self, span: Span) {
190 self.token.set_span(span)
191 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700192}
193
David Tolnay360efd22018-01-04 23:35:26 -0800194impl LitByteStr {
195 pub fn new(value: &[u8], span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700196 let mut token = Literal::byte_string(value);
197 token.set_span(span);
198 LitByteStr { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800199 }
200
201 pub fn value(&self) -> Vec<u8> {
202 value::parse_lit_byte_str(&self.token.to_string())
203 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700204
205 pub fn span(&self) -> Span {
206 self.token.span()
207 }
208
209 pub fn set_span(&mut self, span: Span) {
210 self.token.set_span(span)
211 }
David Tolnay360efd22018-01-04 23:35:26 -0800212}
213
214impl LitByte {
215 pub fn new(value: u8, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700216 let mut token = Literal::u8_suffixed(value);
217 token.set_span(span);
218 LitByte { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800219 }
220
221 pub fn value(&self) -> u8 {
222 value::parse_lit_byte(&self.token.to_string())
223 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700224
225 pub fn span(&self) -> Span {
226 self.token.span()
227 }
228
229 pub fn set_span(&mut self, span: Span) {
230 self.token.set_span(span)
231 }
David Tolnay360efd22018-01-04 23:35:26 -0800232}
233
234impl LitChar {
235 pub fn new(value: char, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700236 let mut token = Literal::character(value);
237 token.set_span(span);
238 LitChar { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800239 }
240
241 pub fn value(&self) -> char {
242 value::parse_lit_char(&self.token.to_string())
243 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700244
245 pub fn span(&self) -> Span {
246 self.token.span()
247 }
248
249 pub fn set_span(&mut self, span: Span) {
250 self.token.set_span(span)
251 }
David Tolnay360efd22018-01-04 23:35:26 -0800252}
253
254impl LitInt {
255 pub fn new(value: u64, suffix: IntSuffix, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700256 let mut token = match suffix {
257 IntSuffix::Isize => Literal::isize_suffixed(value as isize),
258 IntSuffix::I8 => Literal::i8_suffixed(value as i8),
259 IntSuffix::I16 => Literal::i16_suffixed(value as i16),
260 IntSuffix::I32 => Literal::i32_suffixed(value as i32),
261 IntSuffix::I64 => Literal::i64_suffixed(value as i64),
262 IntSuffix::I128 => value::to_literal(&format!("{}i128", value)),
263 IntSuffix::Usize => Literal::usize_suffixed(value as usize),
264 IntSuffix::U8 => Literal::u8_suffixed(value as u8),
265 IntSuffix::U16 => Literal::u16_suffixed(value as u16),
266 IntSuffix::U32 => Literal::u32_suffixed(value as u32),
267 IntSuffix::U64 => Literal::u64_suffixed(value),
268 IntSuffix::U128 => value::to_literal(&format!("{}u128", value)),
269 IntSuffix::None => Literal::u64_unsuffixed(value),
270 };
271 token.set_span(span);
272 LitInt { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800273 }
274
275 pub fn value(&self) -> u64 {
276 value::parse_lit_int(&self.token.to_string()).unwrap()
277 }
278
279 pub fn suffix(&self) -> IntSuffix {
280 let value = self.token.to_string();
281 for (s, suffix) in vec![
282 ("i8", IntSuffix::I8),
283 ("i16", IntSuffix::I16),
284 ("i32", IntSuffix::I32),
285 ("i64", IntSuffix::I64),
286 ("i128", IntSuffix::I128),
287 ("isize", IntSuffix::Isize),
288 ("u8", IntSuffix::U8),
289 ("u16", IntSuffix::U16),
290 ("u32", IntSuffix::U32),
291 ("u64", IntSuffix::U64),
292 ("u128", IntSuffix::U128),
293 ("usize", IntSuffix::Usize),
294 ] {
295 if value.ends_with(s) {
296 return suffix;
297 }
298 }
299 IntSuffix::None
300 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700301
302 pub fn span(&self) -> Span {
303 self.token.span()
304 }
305
306 pub fn set_span(&mut self, span: Span) {
307 self.token.set_span(span)
308 }
David Tolnay360efd22018-01-04 23:35:26 -0800309}
310
311impl LitFloat {
312 pub fn new(value: f64, suffix: FloatSuffix, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700313 let mut token = match suffix {
314 FloatSuffix::F32 => Literal::f32_suffixed(value as f32),
315 FloatSuffix::F64 => Literal::f64_suffixed(value),
316 FloatSuffix::None => Literal::f64_unsuffixed(value),
317 };
318 token.set_span(span);
319 LitFloat { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800320 }
321
322 pub fn value(&self) -> f64 {
323 value::parse_lit_float(&self.token.to_string())
324 }
325
326 pub fn suffix(&self) -> FloatSuffix {
327 let value = self.token.to_string();
David Tolnay61037c62018-01-05 16:21:03 -0800328 for (s, suffix) in vec![("f32", FloatSuffix::F32), ("f64", FloatSuffix::F64)] {
David Tolnay360efd22018-01-04 23:35:26 -0800329 if value.ends_with(s) {
330 return suffix;
331 }
332 }
333 FloatSuffix::None
334 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700335
336 pub fn span(&self) -> Span {
337 self.token.span()
338 }
339
340 pub fn set_span(&mut self, span: Span) {
341 self.token.set_span(span)
342 }
David Tolnay360efd22018-01-04 23:35:26 -0800343}
344
345macro_rules! lit_extra_traits {
346 ($ty:ident, $field:ident) => {
347 #[cfg(feature = "extra-traits")]
348 impl Eq for $ty {}
349
350 #[cfg(feature = "extra-traits")]
351 impl PartialEq for $ty {
352 fn eq(&self, other: &Self) -> bool {
353 self.$field.to_string() == other.$field.to_string()
354 }
355 }
356
357 #[cfg(feature = "extra-traits")]
358 impl Hash for $ty {
359 fn hash<H>(&self, state: &mut H)
360 where
361 H: Hasher,
362 {
363 self.$field.to_string().hash(state);
364 }
David Tolnay9c76bcb2017-12-26 23:14:59 -0500365 }
David Tolnay6a170ce2018-08-26 22:29:24 -0700366
367 #[cfg(feature = "parsing")]
368 #[doc(hidden)]
369 #[allow(non_snake_case)]
370 pub fn $ty(marker: lookahead::TokenMarker) -> $ty {
371 match marker {}
372 }
David Tolnay94d2b792018-04-29 12:26:10 -0700373 };
David Tolnayf4bbbd92016-09-23 14:41:55 -0700374}
375
Alex Crichton9a4dca22018-03-28 06:32:19 -0700376impl LitVerbatim {
377 pub fn span(&self) -> Span {
378 self.token.span()
379 }
380
381 pub fn set_span(&mut self, span: Span) {
382 self.token.set_span(span)
383 }
384}
385
David Tolnay360efd22018-01-04 23:35:26 -0800386lit_extra_traits!(LitStr, token);
387lit_extra_traits!(LitByteStr, token);
388lit_extra_traits!(LitByte, token);
389lit_extra_traits!(LitChar, token);
390lit_extra_traits!(LitInt, token);
391lit_extra_traits!(LitFloat, token);
392lit_extra_traits!(LitBool, value);
393lit_extra_traits!(LitVerbatim, token);
394
395ast_enum! {
David Tolnay05658502018-01-07 09:56:37 -0800396 /// The style of a string literal, either plain quoted or a raw string like
David Tolnayabf5c2e2018-01-06 23:30:04 -0800397 /// `r##"data"##`.
David Tolnay461d98e2018-01-07 11:07:19 -0800398 ///
399 /// *This type is available if Syn is built with the `"derive"` or `"full"`
400 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800401 pub enum StrStyle #no_visit {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800402 /// An ordinary string like `"data"`.
David Tolnay360efd22018-01-04 23:35:26 -0800403 Cooked,
David Tolnayabf5c2e2018-01-06 23:30:04 -0800404 /// A raw string like `r##"data"##`.
David Tolnay360efd22018-01-04 23:35:26 -0800405 ///
406 /// The unsigned integer is the number of `#` symbols used.
407 Raw(usize),
Alex Crichton62a0a592017-05-22 13:58:53 -0700408 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700409}
410
David Tolnay360efd22018-01-04 23:35:26 -0800411ast_enum! {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800412 /// The suffix on an integer literal if any, like the `u8` in `127u8`.
David Tolnay461d98e2018-01-07 11:07:19 -0800413 ///
414 /// *This type is available if Syn is built with the `"derive"` or `"full"`
415 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800416 pub enum IntSuffix #no_visit {
417 I8,
418 I16,
419 I32,
420 I64,
421 I128,
422 Isize,
423 U8,
424 U16,
425 U32,
426 U64,
427 U128,
428 Usize,
429 None,
Pascal Hertleif36342c52016-10-19 10:31:42 +0200430 }
431}
432
David Tolnay360efd22018-01-04 23:35:26 -0800433ast_enum! {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800434 /// The suffix on a floating point literal if any, like the `f32` in
435 /// `1.0f32`.
David Tolnay461d98e2018-01-07 11:07:19 -0800436 ///
437 /// *This type is available if Syn is built with the `"derive"` or `"full"`
438 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800439 pub enum FloatSuffix #no_visit {
440 F32,
441 F64,
442 None,
Alex Crichton2e0229c2017-05-23 09:34:50 -0700443 }
David Tolnay5fe14fc2017-01-27 16:22:08 -0800444}
445
446#[cfg(feature = "parsing")]
David Tolnay4fb71232018-08-25 23:14:50 -0400447#[doc(hidden)]
448#[allow(non_snake_case)]
449pub fn Lit(marker: lookahead::TokenMarker) -> Lit {
450 match marker {}
451}
452
453#[cfg(feature = "parsing")]
David Tolnayf4bbbd92016-09-23 14:41:55 -0700454pub mod parsing {
455 use super::*;
David Tolnay4fb71232018-08-25 23:14:50 -0400456 use parse::{Parse, ParseStream, Result};
David Tolnayf4bbbd92016-09-23 14:41:55 -0700457
David Tolnay4fb71232018-08-25 23:14:50 -0400458 impl Parse for Lit {
459 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay924e0af2018-09-01 13:07:34 -0700460 input.step(|cursor| {
461 if let Some((lit, rest)) = cursor.literal() {
462 return Ok((Lit::new(lit), rest));
463 }
464 while let Some((ident, rest)) = cursor.ident() {
465 let value = if ident == "true" {
466 true
467 } else if ident == "false" {
468 false
469 } else {
470 break;
471 };
472 let lit_bool = LitBool {
473 value: value,
474 span: ident.span(),
475 };
476 return Ok((Lit::Bool(lit_bool), rest));
477 }
478 Err(cursor.error("expected literal"))
David Tolnay4fb71232018-08-25 23:14:50 -0400479 })
Sergio Benitez5680d6a2017-12-29 11:20:29 -0800480 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700481 }
David Tolnay360efd22018-01-04 23:35:26 -0800482
David Tolnaya7d69fc2018-08-26 13:30:24 -0400483 impl Parse for LitStr {
484 fn parse(input: ParseStream) -> Result<Self> {
485 let head = input.fork();
486 match input.parse()? {
487 Lit::Str(lit) => Ok(lit),
488 _ => Err(head.error("expected string literal")),
489 }
490 }
491 }
David Tolnay360efd22018-01-04 23:35:26 -0800492
David Tolnaya7d69fc2018-08-26 13:30:24 -0400493 impl Parse for LitByteStr {
494 fn parse(input: ParseStream) -> Result<Self> {
495 let head = input.fork();
496 match input.parse()? {
497 Lit::ByteStr(lit) => Ok(lit),
498 _ => Err(head.error("expected byte string literal")),
499 }
500 }
501 }
David Tolnay360efd22018-01-04 23:35:26 -0800502
David Tolnaya7d69fc2018-08-26 13:30:24 -0400503 impl Parse for LitByte {
504 fn parse(input: ParseStream) -> Result<Self> {
505 let head = input.fork();
506 match input.parse()? {
507 Lit::Byte(lit) => Ok(lit),
508 _ => Err(head.error("expected byte literal")),
509 }
510 }
511 }
David Tolnay360efd22018-01-04 23:35:26 -0800512
David Tolnaya7d69fc2018-08-26 13:30:24 -0400513 impl Parse for LitChar {
514 fn parse(input: ParseStream) -> Result<Self> {
515 let head = input.fork();
516 match input.parse()? {
517 Lit::Char(lit) => Ok(lit),
518 _ => Err(head.error("expected character literal")),
519 }
520 }
521 }
David Tolnay360efd22018-01-04 23:35:26 -0800522
David Tolnaya7d69fc2018-08-26 13:30:24 -0400523 impl Parse for LitInt {
524 fn parse(input: ParseStream) -> Result<Self> {
525 let head = input.fork();
526 match input.parse()? {
527 Lit::Int(lit) => Ok(lit),
528 _ => Err(head.error("expected integer literal")),
529 }
530 }
531 }
David Tolnay360efd22018-01-04 23:35:26 -0800532
David Tolnaya7d69fc2018-08-26 13:30:24 -0400533 impl Parse for LitFloat {
534 fn parse(input: ParseStream) -> Result<Self> {
535 let head = input.fork();
536 match input.parse()? {
537 Lit::Float(lit) => Ok(lit),
538 _ => Err(head.error("expected floating point literal")),
539 }
540 }
541 }
David Tolnay360efd22018-01-04 23:35:26 -0800542
David Tolnaya7d69fc2018-08-26 13:30:24 -0400543 impl Parse for LitBool {
544 fn parse(input: ParseStream) -> Result<Self> {
545 let head = input.fork();
546 match input.parse()? {
547 Lit::Bool(lit) => Ok(lit),
548 _ => Err(head.error("expected boolean literal")),
549 }
550 }
551 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700552}
553
554#[cfg(feature = "printing")]
555mod printing {
556 use super::*;
Alex Crichtona74a1c82018-05-16 10:20:44 -0700557 use proc_macro2::TokenStream;
David Tolnay65fb5662018-05-20 20:02:28 -0700558 use quote::{ToTokens, TokenStreamExt};
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700559
David Tolnay360efd22018-01-04 23:35:26 -0800560 impl ToTokens for LitStr {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700561 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700562 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800563 }
564 }
565
566 impl ToTokens for LitByteStr {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700567 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700568 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800569 }
570 }
571
572 impl ToTokens for LitByte {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700573 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700574 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800575 }
576 }
577
578 impl ToTokens for LitChar {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700579 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700580 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800581 }
582 }
583
584 impl ToTokens for LitInt {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700585 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700586 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800587 }
588 }
589
590 impl ToTokens for LitFloat {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700591 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700592 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800593 }
594 }
595
596 impl ToTokens for LitBool {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700597 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700598 let s = if self.value { "true" } else { "false" };
Alex Crichtona74a1c82018-05-16 10:20:44 -0700599 tokens.append(Ident::new(s, self.span));
David Tolnay360efd22018-01-04 23:35:26 -0800600 }
601 }
602
603 impl ToTokens for LitVerbatim {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700604 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700605 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800606 }
607 }
608}
609
610mod value {
611 use super::*;
David Tolnay94d2b792018-04-29 12:26:10 -0700612 use proc_macro2::TokenStream;
David Tolnay360efd22018-01-04 23:35:26 -0800613 use std::char;
614 use std::ops::{Index, RangeFrom};
David Tolnay360efd22018-01-04 23:35:26 -0800615
David Tolnay7d1d1282018-01-06 16:10:51 -0800616 impl Lit {
David Tolnay780292d2018-01-22 23:26:44 -0800617 /// Interpret a Syn literal from a proc-macro2 literal.
618 ///
619 /// Not all proc-macro2 literals are valid Syn literals. In particular,
620 /// doc comments are considered by proc-macro2 to be literals but in Syn
621 /// they are [`Attribute`].
622 ///
623 /// [`Attribute`]: struct.Attribute.html
624 ///
625 /// # Panics
626 ///
627 /// Panics if the input is a doc comment literal.
Alex Crichton9a4dca22018-03-28 06:32:19 -0700628 pub fn new(token: Literal) -> Self {
David Tolnay7d1d1282018-01-06 16:10:51 -0800629 let value = token.to_string();
630
631 match value::byte(&value, 0) {
David Tolnay94d2b792018-04-29 12:26:10 -0700632 b'"' | b'r' => return Lit::Str(LitStr { token: token }),
David Tolnay7d1d1282018-01-06 16:10:51 -0800633 b'b' => match value::byte(&value, 1) {
David Tolnay94d2b792018-04-29 12:26:10 -0700634 b'"' | b'r' => return Lit::ByteStr(LitByteStr { token: token }),
635 b'\'' => return Lit::Byte(LitByte { token: token }),
David Tolnay7d1d1282018-01-06 16:10:51 -0800636 _ => {}
637 },
David Tolnay94d2b792018-04-29 12:26:10 -0700638 b'\'' => return Lit::Char(LitChar { token: token }),
David Tolnayfb84fc02018-10-02 21:01:30 -0700639 b'0'...b'9' => {
640 if number_is_int(&value) {
641 return Lit::Int(LitInt { token: token });
642 } else if number_is_float(&value) {
643 return Lit::Float(LitFloat { token: token });
644 } else {
645 // number overflow
646 return Lit::Verbatim(LitVerbatim { token: token });
647 }
648 }
649 _ => {
650 if value == "true" || value == "false" {
651 return Lit::Bool(LitBool {
652 value: value == "true",
653 span: token.span(),
654 });
655 }
656 }
David Tolnay7d1d1282018-01-06 16:10:51 -0800657 }
658
659 panic!("Unrecognized literal: {}", value);
660 }
661 }
662
663 fn number_is_int(value: &str) -> bool {
664 if number_is_float(value) {
665 false
666 } else {
667 value::parse_lit_int(value).is_some()
668 }
669 }
670
671 fn number_is_float(value: &str) -> bool {
672 if value.contains('.') {
673 true
674 } else if value.starts_with("0x") || value.ends_with("size") {
675 false
676 } else {
677 value.contains('e') || value.contains('E')
678 }
679 }
680
David Tolnay360efd22018-01-04 23:35:26 -0800681 /// Get the byte at offset idx, or a default of `b'\0'` if we're looking
682 /// past the end of the input buffer.
683 pub fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 {
684 let s = s.as_ref();
685 if idx < s.len() {
686 s[idx]
687 } else {
688 0
689 }
690 }
691
692 fn next_chr(s: &str) -> char {
693 s.chars().next().unwrap_or('\0')
694 }
695
696 pub fn parse_lit_str(s: &str) -> String {
697 match byte(s, 0) {
698 b'"' => parse_lit_str_cooked(s),
699 b'r' => parse_lit_str_raw(s),
700 _ => unreachable!(),
701 }
702 }
703
David Tolnay76ebcdd2018-01-05 17:07:26 -0800704 // Clippy false positive
705 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
706 #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))]
David Tolnay360efd22018-01-04 23:35:26 -0800707 fn parse_lit_str_cooked(mut s: &str) -> String {
708 assert_eq!(byte(s, 0), b'"');
709 s = &s[1..];
710
711 let mut out = String::new();
712 'outer: loop {
713 let ch = match byte(s, 0) {
714 b'"' => break,
715 b'\\' => {
716 let b = byte(s, 1);
717 s = &s[2..];
718 match b {
719 b'x' => {
720 let (byte, rest) = backslash_x(s);
721 s = rest;
722 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
David Tolnay76ebcdd2018-01-05 17:07:26 -0800723 char::from_u32(u32::from(byte)).unwrap()
David Tolnay360efd22018-01-04 23:35:26 -0800724 }
725 b'u' => {
David Tolnay76ebcdd2018-01-05 17:07:26 -0800726 let (chr, rest) = backslash_u(s);
David Tolnay360efd22018-01-04 23:35:26 -0800727 s = rest;
728 chr
729 }
730 b'n' => '\n',
731 b'r' => '\r',
732 b't' => '\t',
733 b'\\' => '\\',
734 b'0' => '\0',
735 b'\'' => '\'',
736 b'"' => '"',
David Tolnay61037c62018-01-05 16:21:03 -0800737 b'\r' | b'\n' => loop {
738 let ch = next_chr(s);
739 if ch.is_whitespace() {
740 s = &s[ch.len_utf8()..];
741 } else {
742 continue 'outer;
David Tolnay360efd22018-01-04 23:35:26 -0800743 }
David Tolnay61037c62018-01-05 16:21:03 -0800744 },
745 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800746 }
747 }
748 b'\r' => {
749 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
750 s = &s[2..];
751 '\n'
752 }
753 _ => {
754 let ch = next_chr(s);
755 s = &s[ch.len_utf8()..];
756 ch
757 }
758 };
759 out.push(ch);
760 }
761
762 assert_eq!(s, "\"");
763 out
764 }
765
766 fn parse_lit_str_raw(mut s: &str) -> String {
767 assert_eq!(byte(s, 0), b'r');
768 s = &s[1..];
769
770 let mut pounds = 0;
771 while byte(s, pounds) == b'#' {
772 pounds += 1;
773 }
774 assert_eq!(byte(s, pounds), b'"');
775 assert_eq!(byte(s, s.len() - pounds - 1), b'"');
776 for end in s[s.len() - pounds..].bytes() {
777 assert_eq!(end, b'#');
778 }
779
780 s[pounds + 1..s.len() - pounds - 1].to_owned()
781 }
782
783 pub fn parse_lit_byte_str(s: &str) -> Vec<u8> {
784 assert_eq!(byte(s, 0), b'b');
785 match byte(s, 1) {
786 b'"' => parse_lit_byte_str_cooked(s),
787 b'r' => parse_lit_byte_str_raw(s),
788 _ => unreachable!(),
789 }
790 }
791
David Tolnay76ebcdd2018-01-05 17:07:26 -0800792 // Clippy false positive
793 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
794 #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))]
David Tolnay360efd22018-01-04 23:35:26 -0800795 fn parse_lit_byte_str_cooked(mut s: &str) -> Vec<u8> {
796 assert_eq!(byte(s, 0), b'b');
797 assert_eq!(byte(s, 1), b'"');
798 s = &s[2..];
799
800 // We're going to want to have slices which don't respect codepoint boundaries.
801 let mut s = s.as_bytes();
802
803 let mut out = Vec::new();
804 'outer: loop {
805 let byte = match byte(s, 0) {
806 b'"' => break,
807 b'\\' => {
808 let b = byte(s, 1);
809 s = &s[2..];
810 match b {
811 b'x' => {
812 let (b, rest) = backslash_x(s);
813 s = rest;
814 b
815 }
816 b'n' => b'\n',
817 b'r' => b'\r',
818 b't' => b'\t',
819 b'\\' => b'\\',
820 b'0' => b'\0',
821 b'\'' => b'\'',
822 b'"' => b'"',
David Tolnay61037c62018-01-05 16:21:03 -0800823 b'\r' | b'\n' => loop {
824 let byte = byte(s, 0);
David Tolnay76ebcdd2018-01-05 17:07:26 -0800825 let ch = char::from_u32(u32::from(byte)).unwrap();
David Tolnay61037c62018-01-05 16:21:03 -0800826 if ch.is_whitespace() {
827 s = &s[1..];
828 } else {
829 continue 'outer;
David Tolnay360efd22018-01-04 23:35:26 -0800830 }
David Tolnay61037c62018-01-05 16:21:03 -0800831 },
832 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800833 }
834 }
835 b'\r' => {
836 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
837 s = &s[2..];
838 b'\n'
839 }
840 b => {
841 s = &s[1..];
842 b
843 }
844 };
845 out.push(byte);
846 }
847
848 assert_eq!(s, b"\"");
849 out
850 }
851
852 fn parse_lit_byte_str_raw(s: &str) -> Vec<u8> {
853 assert_eq!(byte(s, 0), b'b');
854 parse_lit_str_raw(&s[1..]).into_bytes()
855 }
856
857 pub fn parse_lit_byte(s: &str) -> u8 {
858 assert_eq!(byte(s, 0), b'b');
859 assert_eq!(byte(s, 1), b'\'');
860
861 // We're going to want to have slices which don't respect codepoint boundaries.
862 let mut s = s[2..].as_bytes();
863
864 let b = match byte(s, 0) {
865 b'\\' => {
866 let b = byte(s, 1);
867 s = &s[2..];
868 match b {
869 b'x' => {
870 let (b, rest) = backslash_x(s);
871 s = rest;
872 b
873 }
874 b'n' => b'\n',
875 b'r' => b'\r',
876 b't' => b'\t',
877 b'\\' => b'\\',
878 b'0' => b'\0',
879 b'\'' => b'\'',
880 b'"' => b'"',
David Tolnay61037c62018-01-05 16:21:03 -0800881 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800882 }
883 }
884 b => {
885 s = &s[1..];
886 b
887 }
888 };
889
890 assert_eq!(byte(s, 0), b'\'');
891 b
892 }
893
894 pub fn parse_lit_char(mut s: &str) -> char {
895 assert_eq!(byte(s, 0), b'\'');
896 s = &s[1..];
897
898 let ch = match byte(s, 0) {
899 b'\\' => {
900 let b = byte(s, 1);
901 s = &s[2..];
902 match b {
903 b'x' => {
904 let (byte, rest) = backslash_x(s);
905 s = rest;
906 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
David Tolnay76ebcdd2018-01-05 17:07:26 -0800907 char::from_u32(u32::from(byte)).unwrap()
David Tolnay360efd22018-01-04 23:35:26 -0800908 }
909 b'u' => {
910 let (chr, rest) = backslash_u(s);
911 s = rest;
912 chr
913 }
914 b'n' => '\n',
915 b'r' => '\r',
916 b't' => '\t',
917 b'\\' => '\\',
918 b'0' => '\0',
919 b'\'' => '\'',
920 b'"' => '"',
David Tolnay61037c62018-01-05 16:21:03 -0800921 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800922 }
923 }
924 _ => {
925 let ch = next_chr(s);
926 s = &s[ch.len_utf8()..];
927 ch
928 }
929 };
930 assert_eq!(s, "\'", "Expected end of char literal");
931 ch
932 }
933
934 fn backslash_x<S>(s: &S) -> (u8, &S)
David Tolnay61037c62018-01-05 16:21:03 -0800935 where
936 S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
David Tolnay360efd22018-01-04 23:35:26 -0800937 {
938 let mut ch = 0;
939 let b0 = byte(s, 0);
940 let b1 = byte(s, 1);
David Tolnaye614f282018-10-27 22:50:12 -0700941 ch += 0x10
942 * match b0 {
943 b'0'...b'9' => b0 - b'0',
944 b'a'...b'f' => 10 + (b0 - b'a'),
945 b'A'...b'F' => 10 + (b0 - b'A'),
946 _ => panic!("unexpected non-hex character after \\x"),
947 };
David Tolnay76ebcdd2018-01-05 17:07:26 -0800948 ch += match b1 {
David Tolnay360efd22018-01-04 23:35:26 -0800949 b'0'...b'9' => b1 - b'0',
950 b'a'...b'f' => 10 + (b1 - b'a'),
951 b'A'...b'F' => 10 + (b1 - b'A'),
952 _ => panic!("unexpected non-hex character after \\x"),
953 };
954 (ch, &s[2..])
955 }
956
957 fn backslash_u(mut s: &str) -> (char, &str) {
958 if byte(s, 0) != b'{' {
959 panic!("expected {{ after \\u");
960 }
961 s = &s[1..];
962
963 let mut ch = 0;
964 for _ in 0..6 {
965 let b = byte(s, 0);
966 match b {
967 b'0'...b'9' => {
968 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800969 ch += u32::from(b - b'0');
David Tolnay360efd22018-01-04 23:35:26 -0800970 s = &s[1..];
971 }
972 b'a'...b'f' => {
973 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800974 ch += u32::from(10 + b - b'a');
David Tolnay360efd22018-01-04 23:35:26 -0800975 s = &s[1..];
976 }
977 b'A'...b'F' => {
978 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800979 ch += u32::from(10 + b - b'A');
David Tolnay360efd22018-01-04 23:35:26 -0800980 s = &s[1..];
981 }
982 b'}' => break,
983 _ => panic!("unexpected non-hex character after \\u"),
984 }
985 }
986 assert!(byte(s, 0) == b'}');
987 s = &s[1..];
988
989 if let Some(ch) = char::from_u32(ch) {
990 (ch, s)
991 } else {
992 panic!("character code {:x} is not a valid unicode character", ch);
993 }
994 }
995
996 pub fn parse_lit_int(mut s: &str) -> Option<u64> {
997 let base = match (byte(s, 0), byte(s, 1)) {
998 (b'0', b'x') => {
999 s = &s[2..];
1000 16
1001 }
1002 (b'0', b'o') => {
1003 s = &s[2..];
1004 8
1005 }
1006 (b'0', b'b') => {
1007 s = &s[2..];
1008 2
1009 }
1010 (b'0'...b'9', _) => 10,
1011 _ => unreachable!(),
1012 };
1013
1014 let mut value = 0u64;
1015 loop {
1016 let b = byte(s, 0);
1017 let digit = match b {
David Tolnay76ebcdd2018-01-05 17:07:26 -08001018 b'0'...b'9' => u64::from(b - b'0'),
1019 b'a'...b'f' if base > 10 => 10 + u64::from(b - b'a'),
1020 b'A'...b'F' if base > 10 => 10 + u64::from(b - b'A'),
David Tolnay360efd22018-01-04 23:35:26 -08001021 b'_' => {
1022 s = &s[1..];
1023 continue;
1024 }
1025 // NOTE: Looking at a floating point literal, we don't want to
1026 // consider these integers.
1027 b'.' if base == 10 => return None,
1028 b'e' | b'E' if base == 10 => return None,
1029 _ => break,
1030 };
1031
1032 if digit >= base {
1033 panic!("Unexpected digit {:x} out of base range", digit);
1034 }
1035
1036 value = match value.checked_mul(base) {
1037 Some(value) => value,
1038 None => return None,
1039 };
1040 value = match value.checked_add(digit) {
1041 Some(value) => value,
1042 None => return None,
1043 };
1044 s = &s[1..];
1045 }
1046
1047 Some(value)
1048 }
1049
1050 pub fn parse_lit_float(input: &str) -> f64 {
1051 // Rust's floating point literals are very similar to the ones parsed by
1052 // the standard library, except that rust's literals can contain
1053 // ignorable underscores. Let's remove those underscores.
1054 let mut bytes = input.to_owned().into_bytes();
1055 let mut write = 0;
1056 for read in 0..bytes.len() {
1057 if bytes[read] == b'_' {
1058 continue; // Don't increase write
David Tolnay76ebcdd2018-01-05 17:07:26 -08001059 }
1060 if write != read {
David Tolnay360efd22018-01-04 23:35:26 -08001061 let x = bytes[read];
1062 bytes[write] = x;
1063 }
1064 write += 1;
1065 }
1066 bytes.truncate(write);
1067 let input = String::from_utf8(bytes).unwrap();
David Tolnay76ebcdd2018-01-05 17:07:26 -08001068 let end = input.find('f').unwrap_or_else(|| input.len());
David Tolnay360efd22018-01-04 23:35:26 -08001069 input[..end].parse().unwrap()
1070 }
1071
1072 pub fn to_literal(s: &str) -> Literal {
1073 let stream = s.parse::<TokenStream>().unwrap();
Alex Crichton9a4dca22018-03-28 06:32:19 -07001074 match stream.into_iter().next().unwrap() {
1075 TokenTree::Literal(l) => l,
David Tolnay360efd22018-01-04 23:35:26 -08001076 _ => unreachable!(),
David Tolnayf17fd2f2016-10-07 23:38:08 -07001077 }
1078 }
David Tolnayf4bbbd92016-09-23 14:41:55 -07001079}