blob: a39cd3c5818731e6d8866fc750701a06306f3e1f [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;
126 /// # extern crate syn;
127 /// #
128 /// use proc_macro2::Span;
David Tolnay67fea042018-11-24 14:50:20 -0800129 /// use syn::{Attribute, Error, Ident, Lit, Meta, MetaNameValue, Path, Result};
David Tolnay3b0444a2018-09-01 17:17:19 -0700130 ///
131 /// // Parses the path from an attribute that looks like:
132 /// //
133 /// // #[path = "a::b::c"]
134 /// //
David Tolnay4ac734f2018-11-10 14:19:00 -0800135 /// // or returns `None` if the input is some other attribute.
136 /// fn get_path(attr: &Attribute) -> Result<Option<Path>> {
137 /// if !attr.path.is_ident("path") {
138 /// return Ok(None);
David Tolnay3b0444a2018-09-01 17:17:19 -0700139 /// }
140 ///
David Tolnay4ac734f2018-11-10 14:19:00 -0800141 /// match attr.parse_meta()? {
David Tolnay3b0444a2018-09-01 17:17:19 -0700142 /// Meta::NameValue(MetaNameValue { lit: Lit::Str(lit_str), .. }) => {
David Tolnay4ac734f2018-11-10 14:19:00 -0800143 /// lit_str.parse().map(Some)
David Tolnay3b0444a2018-09-01 17:17:19 -0700144 /// }
145 /// _ => {
146 /// let error_span = attr.bracket_token.span;
147 /// let message = "expected #[path = \"...\"]";
148 /// Err(Error::new(error_span, message))
149 /// }
150 /// }
151 /// }
152 /// ```
David Tolnayd53ac2b2018-01-27 19:00:06 -0800153 #[cfg(feature = "parsing")]
David Tolnaye82a2b12018-08-30 16:31:10 -0700154 pub fn parse<T: Parse>(&self) -> Result<T, Error> {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700155 use proc_macro2::Group;
156
David Tolnayd53ac2b2018-01-27 19:00:06 -0800157 // Parse string literal into a token stream with every span equal to the
158 // original literal's span.
David Tolnayad4b2472018-08-25 08:25:24 -0400159 fn spanned_tokens(s: &LitStr) -> Result<TokenStream, Error> {
David Tolnayd53ac2b2018-01-27 19:00:06 -0800160 let stream = ::parse_str(&s.value())?;
Alex Crichton9a4dca22018-03-28 06:32:19 -0700161 Ok(respan_token_stream(stream, s.span()))
David Tolnayd53ac2b2018-01-27 19:00:06 -0800162 }
163
164 // Token stream with every span replaced by the given one.
165 fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
David Tolnay94d2b792018-04-29 12:26:10 -0700166 stream
167 .into_iter()
168 .map(|token| respan_token_tree(token, span))
169 .collect()
David Tolnayd53ac2b2018-01-27 19:00:06 -0800170 }
171
172 // Token tree with every span replaced by the given one.
Alex Crichton9a4dca22018-03-28 06:32:19 -0700173 fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
174 match token {
175 TokenTree::Group(ref mut g) => {
176 let stream = respan_token_stream(g.stream().clone(), span);
177 *g = Group::new(g.delimiter(), stream);
178 g.set_span(span);
179 }
180 ref mut other => other.set_span(span),
David Tolnayd53ac2b2018-01-27 19:00:06 -0800181 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700182 token
David Tolnayd53ac2b2018-01-27 19:00:06 -0800183 }
184
185 spanned_tokens(self).and_then(::parse2)
186 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700187
188 pub fn span(&self) -> Span {
189 self.token.span()
190 }
191
192 pub fn set_span(&mut self, span: Span) {
193 self.token.set_span(span)
194 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700195}
196
David Tolnay360efd22018-01-04 23:35:26 -0800197impl LitByteStr {
198 pub fn new(value: &[u8], span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700199 let mut token = Literal::byte_string(value);
200 token.set_span(span);
201 LitByteStr { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800202 }
203
204 pub fn value(&self) -> Vec<u8> {
205 value::parse_lit_byte_str(&self.token.to_string())
206 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700207
208 pub fn span(&self) -> Span {
209 self.token.span()
210 }
211
212 pub fn set_span(&mut self, span: Span) {
213 self.token.set_span(span)
214 }
David Tolnay360efd22018-01-04 23:35:26 -0800215}
216
217impl LitByte {
218 pub fn new(value: u8, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700219 let mut token = Literal::u8_suffixed(value);
220 token.set_span(span);
221 LitByte { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800222 }
223
224 pub fn value(&self) -> u8 {
225 value::parse_lit_byte(&self.token.to_string())
226 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700227
228 pub fn span(&self) -> Span {
229 self.token.span()
230 }
231
232 pub fn set_span(&mut self, span: Span) {
233 self.token.set_span(span)
234 }
David Tolnay360efd22018-01-04 23:35:26 -0800235}
236
237impl LitChar {
238 pub fn new(value: char, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700239 let mut token = Literal::character(value);
240 token.set_span(span);
241 LitChar { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800242 }
243
244 pub fn value(&self) -> char {
245 value::parse_lit_char(&self.token.to_string())
246 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700247
248 pub fn span(&self) -> Span {
249 self.token.span()
250 }
251
252 pub fn set_span(&mut self, span: Span) {
253 self.token.set_span(span)
254 }
David Tolnay360efd22018-01-04 23:35:26 -0800255}
256
257impl LitInt {
258 pub fn new(value: u64, suffix: IntSuffix, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700259 let mut token = match suffix {
260 IntSuffix::Isize => Literal::isize_suffixed(value as isize),
261 IntSuffix::I8 => Literal::i8_suffixed(value as i8),
262 IntSuffix::I16 => Literal::i16_suffixed(value as i16),
263 IntSuffix::I32 => Literal::i32_suffixed(value as i32),
264 IntSuffix::I64 => Literal::i64_suffixed(value as i64),
265 IntSuffix::I128 => value::to_literal(&format!("{}i128", value)),
266 IntSuffix::Usize => Literal::usize_suffixed(value as usize),
267 IntSuffix::U8 => Literal::u8_suffixed(value as u8),
268 IntSuffix::U16 => Literal::u16_suffixed(value as u16),
269 IntSuffix::U32 => Literal::u32_suffixed(value as u32),
270 IntSuffix::U64 => Literal::u64_suffixed(value),
271 IntSuffix::U128 => value::to_literal(&format!("{}u128", value)),
272 IntSuffix::None => Literal::u64_unsuffixed(value),
273 };
274 token.set_span(span);
275 LitInt { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800276 }
277
278 pub fn value(&self) -> u64 {
279 value::parse_lit_int(&self.token.to_string()).unwrap()
280 }
281
282 pub fn suffix(&self) -> IntSuffix {
283 let value = self.token.to_string();
284 for (s, suffix) in vec![
285 ("i8", IntSuffix::I8),
286 ("i16", IntSuffix::I16),
287 ("i32", IntSuffix::I32),
288 ("i64", IntSuffix::I64),
289 ("i128", IntSuffix::I128),
290 ("isize", IntSuffix::Isize),
291 ("u8", IntSuffix::U8),
292 ("u16", IntSuffix::U16),
293 ("u32", IntSuffix::U32),
294 ("u64", IntSuffix::U64),
295 ("u128", IntSuffix::U128),
296 ("usize", IntSuffix::Usize),
297 ] {
298 if value.ends_with(s) {
299 return suffix;
300 }
301 }
302 IntSuffix::None
303 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700304
305 pub fn span(&self) -> Span {
306 self.token.span()
307 }
308
309 pub fn set_span(&mut self, span: Span) {
310 self.token.set_span(span)
311 }
David Tolnay360efd22018-01-04 23:35:26 -0800312}
313
314impl LitFloat {
315 pub fn new(value: f64, suffix: FloatSuffix, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700316 let mut token = match suffix {
317 FloatSuffix::F32 => Literal::f32_suffixed(value as f32),
318 FloatSuffix::F64 => Literal::f64_suffixed(value),
319 FloatSuffix::None => Literal::f64_unsuffixed(value),
320 };
321 token.set_span(span);
322 LitFloat { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800323 }
324
325 pub fn value(&self) -> f64 {
326 value::parse_lit_float(&self.token.to_string())
327 }
328
329 pub fn suffix(&self) -> FloatSuffix {
330 let value = self.token.to_string();
David Tolnay61037c62018-01-05 16:21:03 -0800331 for (s, suffix) in vec![("f32", FloatSuffix::F32), ("f64", FloatSuffix::F64)] {
David Tolnay360efd22018-01-04 23:35:26 -0800332 if value.ends_with(s) {
333 return suffix;
334 }
335 }
336 FloatSuffix::None
337 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700338
339 pub fn span(&self) -> Span {
340 self.token.span()
341 }
342
343 pub fn set_span(&mut self, span: Span) {
344 self.token.set_span(span)
345 }
David Tolnay360efd22018-01-04 23:35:26 -0800346}
347
348macro_rules! lit_extra_traits {
349 ($ty:ident, $field:ident) => {
350 #[cfg(feature = "extra-traits")]
351 impl Eq for $ty {}
352
353 #[cfg(feature = "extra-traits")]
354 impl PartialEq for $ty {
355 fn eq(&self, other: &Self) -> bool {
356 self.$field.to_string() == other.$field.to_string()
357 }
358 }
359
360 #[cfg(feature = "extra-traits")]
361 impl Hash for $ty {
362 fn hash<H>(&self, state: &mut H)
363 where
364 H: Hasher,
365 {
366 self.$field.to_string().hash(state);
367 }
David Tolnay9c76bcb2017-12-26 23:14:59 -0500368 }
David Tolnay6a170ce2018-08-26 22:29:24 -0700369
370 #[cfg(feature = "parsing")]
371 #[doc(hidden)]
372 #[allow(non_snake_case)]
373 pub fn $ty(marker: lookahead::TokenMarker) -> $ty {
374 match marker {}
375 }
David Tolnay94d2b792018-04-29 12:26:10 -0700376 };
David Tolnayf4bbbd92016-09-23 14:41:55 -0700377}
378
Alex Crichton9a4dca22018-03-28 06:32:19 -0700379impl LitVerbatim {
380 pub fn span(&self) -> Span {
381 self.token.span()
382 }
383
384 pub fn set_span(&mut self, span: Span) {
385 self.token.set_span(span)
386 }
387}
388
David Tolnay360efd22018-01-04 23:35:26 -0800389lit_extra_traits!(LitStr, token);
390lit_extra_traits!(LitByteStr, token);
391lit_extra_traits!(LitByte, token);
392lit_extra_traits!(LitChar, token);
393lit_extra_traits!(LitInt, token);
394lit_extra_traits!(LitFloat, token);
395lit_extra_traits!(LitBool, value);
396lit_extra_traits!(LitVerbatim, token);
397
398ast_enum! {
David Tolnay05658502018-01-07 09:56:37 -0800399 /// The style of a string literal, either plain quoted or a raw string like
David Tolnayabf5c2e2018-01-06 23:30:04 -0800400 /// `r##"data"##`.
David Tolnay461d98e2018-01-07 11:07:19 -0800401 ///
402 /// *This type is available if Syn is built with the `"derive"` or `"full"`
403 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800404 pub enum StrStyle #no_visit {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800405 /// An ordinary string like `"data"`.
David Tolnay360efd22018-01-04 23:35:26 -0800406 Cooked,
David Tolnayabf5c2e2018-01-06 23:30:04 -0800407 /// A raw string like `r##"data"##`.
David Tolnay360efd22018-01-04 23:35:26 -0800408 ///
409 /// The unsigned integer is the number of `#` symbols used.
410 Raw(usize),
Alex Crichton62a0a592017-05-22 13:58:53 -0700411 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700412}
413
David Tolnay360efd22018-01-04 23:35:26 -0800414ast_enum! {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800415 /// The suffix on an integer literal if any, like the `u8` in `127u8`.
David Tolnay461d98e2018-01-07 11:07:19 -0800416 ///
417 /// *This type is available if Syn is built with the `"derive"` or `"full"`
418 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800419 pub enum IntSuffix #no_visit {
420 I8,
421 I16,
422 I32,
423 I64,
424 I128,
425 Isize,
426 U8,
427 U16,
428 U32,
429 U64,
430 U128,
431 Usize,
432 None,
Pascal Hertleif36342c52016-10-19 10:31:42 +0200433 }
434}
435
David Tolnay360efd22018-01-04 23:35:26 -0800436ast_enum! {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800437 /// The suffix on a floating point literal if any, like the `f32` in
438 /// `1.0f32`.
David Tolnay461d98e2018-01-07 11:07:19 -0800439 ///
440 /// *This type is available if Syn is built with the `"derive"` or `"full"`
441 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800442 pub enum FloatSuffix #no_visit {
443 F32,
444 F64,
445 None,
Alex Crichton2e0229c2017-05-23 09:34:50 -0700446 }
David Tolnay5fe14fc2017-01-27 16:22:08 -0800447}
448
449#[cfg(feature = "parsing")]
David Tolnay4fb71232018-08-25 23:14:50 -0400450#[doc(hidden)]
451#[allow(non_snake_case)]
452pub fn Lit(marker: lookahead::TokenMarker) -> Lit {
453 match marker {}
454}
455
456#[cfg(feature = "parsing")]
David Tolnayf4bbbd92016-09-23 14:41:55 -0700457pub mod parsing {
458 use super::*;
David Tolnay4fb71232018-08-25 23:14:50 -0400459 use parse::{Parse, ParseStream, Result};
David Tolnayf4bbbd92016-09-23 14:41:55 -0700460
David Tolnay4fb71232018-08-25 23:14:50 -0400461 impl Parse for Lit {
462 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay924e0af2018-09-01 13:07:34 -0700463 input.step(|cursor| {
464 if let Some((lit, rest)) = cursor.literal() {
465 return Ok((Lit::new(lit), rest));
466 }
467 while let Some((ident, rest)) = cursor.ident() {
468 let value = if ident == "true" {
469 true
470 } else if ident == "false" {
471 false
472 } else {
473 break;
474 };
475 let lit_bool = LitBool {
476 value: value,
477 span: ident.span(),
478 };
479 return Ok((Lit::Bool(lit_bool), rest));
480 }
481 Err(cursor.error("expected literal"))
David Tolnay4fb71232018-08-25 23:14:50 -0400482 })
Sergio Benitez5680d6a2017-12-29 11:20:29 -0800483 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700484 }
David Tolnay360efd22018-01-04 23:35:26 -0800485
David Tolnaya7d69fc2018-08-26 13:30:24 -0400486 impl Parse for LitStr {
487 fn parse(input: ParseStream) -> Result<Self> {
488 let head = input.fork();
489 match input.parse()? {
490 Lit::Str(lit) => Ok(lit),
491 _ => Err(head.error("expected string literal")),
492 }
493 }
494 }
David Tolnay360efd22018-01-04 23:35:26 -0800495
David Tolnaya7d69fc2018-08-26 13:30:24 -0400496 impl Parse for LitByteStr {
497 fn parse(input: ParseStream) -> Result<Self> {
498 let head = input.fork();
499 match input.parse()? {
500 Lit::ByteStr(lit) => Ok(lit),
501 _ => Err(head.error("expected byte string literal")),
502 }
503 }
504 }
David Tolnay360efd22018-01-04 23:35:26 -0800505
David Tolnaya7d69fc2018-08-26 13:30:24 -0400506 impl Parse for LitByte {
507 fn parse(input: ParseStream) -> Result<Self> {
508 let head = input.fork();
509 match input.parse()? {
510 Lit::Byte(lit) => Ok(lit),
511 _ => Err(head.error("expected byte literal")),
512 }
513 }
514 }
David Tolnay360efd22018-01-04 23:35:26 -0800515
David Tolnaya7d69fc2018-08-26 13:30:24 -0400516 impl Parse for LitChar {
517 fn parse(input: ParseStream) -> Result<Self> {
518 let head = input.fork();
519 match input.parse()? {
520 Lit::Char(lit) => Ok(lit),
521 _ => Err(head.error("expected character literal")),
522 }
523 }
524 }
David Tolnay360efd22018-01-04 23:35:26 -0800525
David Tolnaya7d69fc2018-08-26 13:30:24 -0400526 impl Parse for LitInt {
527 fn parse(input: ParseStream) -> Result<Self> {
528 let head = input.fork();
529 match input.parse()? {
530 Lit::Int(lit) => Ok(lit),
531 _ => Err(head.error("expected integer literal")),
532 }
533 }
534 }
David Tolnay360efd22018-01-04 23:35:26 -0800535
David Tolnaya7d69fc2018-08-26 13:30:24 -0400536 impl Parse for LitFloat {
537 fn parse(input: ParseStream) -> Result<Self> {
538 let head = input.fork();
539 match input.parse()? {
540 Lit::Float(lit) => Ok(lit),
541 _ => Err(head.error("expected floating point literal")),
542 }
543 }
544 }
David Tolnay360efd22018-01-04 23:35:26 -0800545
David Tolnaya7d69fc2018-08-26 13:30:24 -0400546 impl Parse for LitBool {
547 fn parse(input: ParseStream) -> Result<Self> {
548 let head = input.fork();
549 match input.parse()? {
550 Lit::Bool(lit) => Ok(lit),
551 _ => Err(head.error("expected boolean literal")),
552 }
553 }
554 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700555}
556
557#[cfg(feature = "printing")]
558mod printing {
559 use super::*;
Alex Crichtona74a1c82018-05-16 10:20:44 -0700560 use proc_macro2::TokenStream;
David Tolnay65fb5662018-05-20 20:02:28 -0700561 use quote::{ToTokens, TokenStreamExt};
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700562
David Tolnay360efd22018-01-04 23:35:26 -0800563 impl ToTokens for LitStr {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700564 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700565 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800566 }
567 }
568
569 impl ToTokens for LitByteStr {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700570 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700571 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800572 }
573 }
574
575 impl ToTokens for LitByte {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700576 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700577 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800578 }
579 }
580
581 impl ToTokens for LitChar {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700582 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700583 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800584 }
585 }
586
587 impl ToTokens for LitInt {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700588 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700589 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800590 }
591 }
592
593 impl ToTokens for LitFloat {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700594 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700595 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800596 }
597 }
598
599 impl ToTokens for LitBool {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700600 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700601 let s = if self.value { "true" } else { "false" };
Alex Crichtona74a1c82018-05-16 10:20:44 -0700602 tokens.append(Ident::new(s, self.span));
David Tolnay360efd22018-01-04 23:35:26 -0800603 }
604 }
605
606 impl ToTokens for LitVerbatim {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700607 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700608 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800609 }
610 }
611}
612
613mod value {
614 use super::*;
David Tolnay94d2b792018-04-29 12:26:10 -0700615 use proc_macro2::TokenStream;
David Tolnay360efd22018-01-04 23:35:26 -0800616 use std::char;
617 use std::ops::{Index, RangeFrom};
David Tolnay360efd22018-01-04 23:35:26 -0800618
David Tolnay7d1d1282018-01-06 16:10:51 -0800619 impl Lit {
David Tolnay780292d2018-01-22 23:26:44 -0800620 /// Interpret a Syn literal from a proc-macro2 literal.
621 ///
622 /// Not all proc-macro2 literals are valid Syn literals. In particular,
623 /// doc comments are considered by proc-macro2 to be literals but in Syn
624 /// they are [`Attribute`].
625 ///
626 /// [`Attribute`]: struct.Attribute.html
627 ///
628 /// # Panics
629 ///
630 /// Panics if the input is a doc comment literal.
Alex Crichton9a4dca22018-03-28 06:32:19 -0700631 pub fn new(token: Literal) -> Self {
David Tolnay7d1d1282018-01-06 16:10:51 -0800632 let value = token.to_string();
633
634 match value::byte(&value, 0) {
David Tolnay94d2b792018-04-29 12:26:10 -0700635 b'"' | b'r' => return Lit::Str(LitStr { token: token }),
David Tolnay7d1d1282018-01-06 16:10:51 -0800636 b'b' => match value::byte(&value, 1) {
David Tolnay94d2b792018-04-29 12:26:10 -0700637 b'"' | b'r' => return Lit::ByteStr(LitByteStr { token: token }),
638 b'\'' => return Lit::Byte(LitByte { token: token }),
David Tolnay7d1d1282018-01-06 16:10:51 -0800639 _ => {}
640 },
David Tolnay94d2b792018-04-29 12:26:10 -0700641 b'\'' => return Lit::Char(LitChar { token: token }),
David Tolnayfb84fc02018-10-02 21:01:30 -0700642 b'0'...b'9' => {
643 if number_is_int(&value) {
644 return Lit::Int(LitInt { token: token });
645 } else if number_is_float(&value) {
646 return Lit::Float(LitFloat { token: token });
647 } else {
648 // number overflow
649 return Lit::Verbatim(LitVerbatim { token: token });
650 }
651 }
652 _ => {
653 if value == "true" || value == "false" {
654 return Lit::Bool(LitBool {
655 value: value == "true",
656 span: token.span(),
657 });
658 }
659 }
David Tolnay7d1d1282018-01-06 16:10:51 -0800660 }
661
662 panic!("Unrecognized literal: {}", value);
663 }
664 }
665
666 fn number_is_int(value: &str) -> bool {
667 if number_is_float(value) {
668 false
669 } else {
670 value::parse_lit_int(value).is_some()
671 }
672 }
673
674 fn number_is_float(value: &str) -> bool {
675 if value.contains('.') {
676 true
677 } else if value.starts_with("0x") || value.ends_with("size") {
678 false
679 } else {
680 value.contains('e') || value.contains('E')
681 }
682 }
683
David Tolnay360efd22018-01-04 23:35:26 -0800684 /// Get the byte at offset idx, or a default of `b'\0'` if we're looking
685 /// past the end of the input buffer.
686 pub fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 {
687 let s = s.as_ref();
688 if idx < s.len() {
689 s[idx]
690 } else {
691 0
692 }
693 }
694
695 fn next_chr(s: &str) -> char {
696 s.chars().next().unwrap_or('\0')
697 }
698
699 pub fn parse_lit_str(s: &str) -> String {
700 match byte(s, 0) {
701 b'"' => parse_lit_str_cooked(s),
702 b'r' => parse_lit_str_raw(s),
703 _ => unreachable!(),
704 }
705 }
706
David Tolnay76ebcdd2018-01-05 17:07:26 -0800707 // Clippy false positive
708 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
709 #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))]
David Tolnay360efd22018-01-04 23:35:26 -0800710 fn parse_lit_str_cooked(mut s: &str) -> String {
711 assert_eq!(byte(s, 0), b'"');
712 s = &s[1..];
713
714 let mut out = String::new();
715 'outer: loop {
716 let ch = match byte(s, 0) {
717 b'"' => break,
718 b'\\' => {
719 let b = byte(s, 1);
720 s = &s[2..];
721 match b {
722 b'x' => {
723 let (byte, rest) = backslash_x(s);
724 s = rest;
725 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
David Tolnay76ebcdd2018-01-05 17:07:26 -0800726 char::from_u32(u32::from(byte)).unwrap()
David Tolnay360efd22018-01-04 23:35:26 -0800727 }
728 b'u' => {
David Tolnay76ebcdd2018-01-05 17:07:26 -0800729 let (chr, rest) = backslash_u(s);
David Tolnay360efd22018-01-04 23:35:26 -0800730 s = rest;
731 chr
732 }
733 b'n' => '\n',
734 b'r' => '\r',
735 b't' => '\t',
736 b'\\' => '\\',
737 b'0' => '\0',
738 b'\'' => '\'',
739 b'"' => '"',
David Tolnay61037c62018-01-05 16:21:03 -0800740 b'\r' | b'\n' => loop {
741 let ch = next_chr(s);
742 if ch.is_whitespace() {
743 s = &s[ch.len_utf8()..];
744 } else {
745 continue 'outer;
David Tolnay360efd22018-01-04 23:35:26 -0800746 }
David Tolnay61037c62018-01-05 16:21:03 -0800747 },
748 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800749 }
750 }
751 b'\r' => {
752 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
753 s = &s[2..];
754 '\n'
755 }
756 _ => {
757 let ch = next_chr(s);
758 s = &s[ch.len_utf8()..];
759 ch
760 }
761 };
762 out.push(ch);
763 }
764
765 assert_eq!(s, "\"");
766 out
767 }
768
769 fn parse_lit_str_raw(mut s: &str) -> String {
770 assert_eq!(byte(s, 0), b'r');
771 s = &s[1..];
772
773 let mut pounds = 0;
774 while byte(s, pounds) == b'#' {
775 pounds += 1;
776 }
777 assert_eq!(byte(s, pounds), b'"');
778 assert_eq!(byte(s, s.len() - pounds - 1), b'"');
779 for end in s[s.len() - pounds..].bytes() {
780 assert_eq!(end, b'#');
781 }
782
783 s[pounds + 1..s.len() - pounds - 1].to_owned()
784 }
785
786 pub fn parse_lit_byte_str(s: &str) -> Vec<u8> {
787 assert_eq!(byte(s, 0), b'b');
788 match byte(s, 1) {
789 b'"' => parse_lit_byte_str_cooked(s),
790 b'r' => parse_lit_byte_str_raw(s),
791 _ => unreachable!(),
792 }
793 }
794
David Tolnay76ebcdd2018-01-05 17:07:26 -0800795 // Clippy false positive
796 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
797 #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))]
David Tolnay360efd22018-01-04 23:35:26 -0800798 fn parse_lit_byte_str_cooked(mut s: &str) -> Vec<u8> {
799 assert_eq!(byte(s, 0), b'b');
800 assert_eq!(byte(s, 1), b'"');
801 s = &s[2..];
802
803 // We're going to want to have slices which don't respect codepoint boundaries.
804 let mut s = s.as_bytes();
805
806 let mut out = Vec::new();
807 'outer: loop {
808 let byte = match byte(s, 0) {
809 b'"' => break,
810 b'\\' => {
811 let b = byte(s, 1);
812 s = &s[2..];
813 match b {
814 b'x' => {
815 let (b, rest) = backslash_x(s);
816 s = rest;
817 b
818 }
819 b'n' => b'\n',
820 b'r' => b'\r',
821 b't' => b'\t',
822 b'\\' => b'\\',
823 b'0' => b'\0',
824 b'\'' => b'\'',
825 b'"' => b'"',
David Tolnay61037c62018-01-05 16:21:03 -0800826 b'\r' | b'\n' => loop {
827 let byte = byte(s, 0);
David Tolnay76ebcdd2018-01-05 17:07:26 -0800828 let ch = char::from_u32(u32::from(byte)).unwrap();
David Tolnay61037c62018-01-05 16:21:03 -0800829 if ch.is_whitespace() {
830 s = &s[1..];
831 } else {
832 continue 'outer;
David Tolnay360efd22018-01-04 23:35:26 -0800833 }
David Tolnay61037c62018-01-05 16:21:03 -0800834 },
835 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800836 }
837 }
838 b'\r' => {
839 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
840 s = &s[2..];
841 b'\n'
842 }
843 b => {
844 s = &s[1..];
845 b
846 }
847 };
848 out.push(byte);
849 }
850
851 assert_eq!(s, b"\"");
852 out
853 }
854
855 fn parse_lit_byte_str_raw(s: &str) -> Vec<u8> {
856 assert_eq!(byte(s, 0), b'b');
857 parse_lit_str_raw(&s[1..]).into_bytes()
858 }
859
860 pub fn parse_lit_byte(s: &str) -> u8 {
861 assert_eq!(byte(s, 0), b'b');
862 assert_eq!(byte(s, 1), b'\'');
863
864 // We're going to want to have slices which don't respect codepoint boundaries.
865 let mut s = s[2..].as_bytes();
866
867 let b = match byte(s, 0) {
868 b'\\' => {
869 let b = byte(s, 1);
870 s = &s[2..];
871 match b {
872 b'x' => {
873 let (b, rest) = backslash_x(s);
874 s = rest;
875 b
876 }
877 b'n' => b'\n',
878 b'r' => b'\r',
879 b't' => b'\t',
880 b'\\' => b'\\',
881 b'0' => b'\0',
882 b'\'' => b'\'',
883 b'"' => b'"',
David Tolnay61037c62018-01-05 16:21:03 -0800884 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800885 }
886 }
887 b => {
888 s = &s[1..];
889 b
890 }
891 };
892
893 assert_eq!(byte(s, 0), b'\'');
894 b
895 }
896
897 pub fn parse_lit_char(mut s: &str) -> char {
898 assert_eq!(byte(s, 0), b'\'');
899 s = &s[1..];
900
901 let ch = match byte(s, 0) {
902 b'\\' => {
903 let b = byte(s, 1);
904 s = &s[2..];
905 match b {
906 b'x' => {
907 let (byte, rest) = backslash_x(s);
908 s = rest;
909 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
David Tolnay76ebcdd2018-01-05 17:07:26 -0800910 char::from_u32(u32::from(byte)).unwrap()
David Tolnay360efd22018-01-04 23:35:26 -0800911 }
912 b'u' => {
913 let (chr, rest) = backslash_u(s);
914 s = rest;
915 chr
916 }
917 b'n' => '\n',
918 b'r' => '\r',
919 b't' => '\t',
920 b'\\' => '\\',
921 b'0' => '\0',
922 b'\'' => '\'',
923 b'"' => '"',
David Tolnay61037c62018-01-05 16:21:03 -0800924 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800925 }
926 }
927 _ => {
928 let ch = next_chr(s);
929 s = &s[ch.len_utf8()..];
930 ch
931 }
932 };
933 assert_eq!(s, "\'", "Expected end of char literal");
934 ch
935 }
936
937 fn backslash_x<S>(s: &S) -> (u8, &S)
David Tolnay61037c62018-01-05 16:21:03 -0800938 where
939 S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
David Tolnay360efd22018-01-04 23:35:26 -0800940 {
941 let mut ch = 0;
942 let b0 = byte(s, 0);
943 let b1 = byte(s, 1);
David Tolnaye614f282018-10-27 22:50:12 -0700944 ch += 0x10
945 * match b0 {
946 b'0'...b'9' => b0 - b'0',
947 b'a'...b'f' => 10 + (b0 - b'a'),
948 b'A'...b'F' => 10 + (b0 - b'A'),
949 _ => panic!("unexpected non-hex character after \\x"),
950 };
David Tolnay76ebcdd2018-01-05 17:07:26 -0800951 ch += match b1 {
David Tolnay360efd22018-01-04 23:35:26 -0800952 b'0'...b'9' => b1 - b'0',
953 b'a'...b'f' => 10 + (b1 - b'a'),
954 b'A'...b'F' => 10 + (b1 - b'A'),
955 _ => panic!("unexpected non-hex character after \\x"),
956 };
957 (ch, &s[2..])
958 }
959
960 fn backslash_u(mut s: &str) -> (char, &str) {
961 if byte(s, 0) != b'{' {
962 panic!("expected {{ after \\u");
963 }
964 s = &s[1..];
965
966 let mut ch = 0;
967 for _ in 0..6 {
968 let b = byte(s, 0);
969 match b {
970 b'0'...b'9' => {
971 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800972 ch += u32::from(b - b'0');
David Tolnay360efd22018-01-04 23:35:26 -0800973 s = &s[1..];
974 }
975 b'a'...b'f' => {
976 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800977 ch += u32::from(10 + b - b'a');
David Tolnay360efd22018-01-04 23:35:26 -0800978 s = &s[1..];
979 }
980 b'A'...b'F' => {
981 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800982 ch += u32::from(10 + b - b'A');
David Tolnay360efd22018-01-04 23:35:26 -0800983 s = &s[1..];
984 }
985 b'}' => break,
986 _ => panic!("unexpected non-hex character after \\u"),
987 }
988 }
989 assert!(byte(s, 0) == b'}');
990 s = &s[1..];
991
992 if let Some(ch) = char::from_u32(ch) {
993 (ch, s)
994 } else {
995 panic!("character code {:x} is not a valid unicode character", ch);
996 }
997 }
998
999 pub fn parse_lit_int(mut s: &str) -> Option<u64> {
1000 let base = match (byte(s, 0), byte(s, 1)) {
1001 (b'0', b'x') => {
1002 s = &s[2..];
1003 16
1004 }
1005 (b'0', b'o') => {
1006 s = &s[2..];
1007 8
1008 }
1009 (b'0', b'b') => {
1010 s = &s[2..];
1011 2
1012 }
1013 (b'0'...b'9', _) => 10,
1014 _ => unreachable!(),
1015 };
1016
1017 let mut value = 0u64;
1018 loop {
1019 let b = byte(s, 0);
1020 let digit = match b {
David Tolnay76ebcdd2018-01-05 17:07:26 -08001021 b'0'...b'9' => u64::from(b - b'0'),
1022 b'a'...b'f' if base > 10 => 10 + u64::from(b - b'a'),
1023 b'A'...b'F' if base > 10 => 10 + u64::from(b - b'A'),
David Tolnay360efd22018-01-04 23:35:26 -08001024 b'_' => {
1025 s = &s[1..];
1026 continue;
1027 }
1028 // NOTE: Looking at a floating point literal, we don't want to
1029 // consider these integers.
1030 b'.' if base == 10 => return None,
1031 b'e' | b'E' if base == 10 => return None,
1032 _ => break,
1033 };
1034
1035 if digit >= base {
1036 panic!("Unexpected digit {:x} out of base range", digit);
1037 }
1038
1039 value = match value.checked_mul(base) {
1040 Some(value) => value,
1041 None => return None,
1042 };
1043 value = match value.checked_add(digit) {
1044 Some(value) => value,
1045 None => return None,
1046 };
1047 s = &s[1..];
1048 }
1049
1050 Some(value)
1051 }
1052
1053 pub fn parse_lit_float(input: &str) -> f64 {
1054 // Rust's floating point literals are very similar to the ones parsed by
1055 // the standard library, except that rust's literals can contain
1056 // ignorable underscores. Let's remove those underscores.
1057 let mut bytes = input.to_owned().into_bytes();
1058 let mut write = 0;
1059 for read in 0..bytes.len() {
1060 if bytes[read] == b'_' {
1061 continue; // Don't increase write
David Tolnay76ebcdd2018-01-05 17:07:26 -08001062 }
1063 if write != read {
David Tolnay360efd22018-01-04 23:35:26 -08001064 let x = bytes[read];
1065 bytes[write] = x;
1066 }
1067 write += 1;
1068 }
1069 bytes.truncate(write);
1070 let input = String::from_utf8(bytes).unwrap();
David Tolnay76ebcdd2018-01-05 17:07:26 -08001071 let end = input.find('f').unwrap_or_else(|| input.len());
David Tolnay360efd22018-01-04 23:35:26 -08001072 input[..end].parse().unwrap()
1073 }
1074
1075 pub fn to_literal(s: &str) -> Literal {
1076 let stream = s.parse::<TokenStream>().unwrap();
Alex Crichton9a4dca22018-03-28 06:32:19 -07001077 match stream.into_iter().next().unwrap() {
1078 TokenTree::Literal(l) => l,
David Tolnay360efd22018-01-04 23:35:26 -08001079 _ => unreachable!(),
David Tolnayf17fd2f2016-10-07 23:38:08 -07001080 }
1081 }
David Tolnayf4bbbd92016-09-23 14:41:55 -07001082}