blob: d4670c0d7a6a260ec86e0560bfee33406588ff01 [file] [log] [blame]
David Tolnay55535012018-01-05 16:39:23 -08001// Copyright 2018 Syn Developers
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
Alex Crichton9a4dca22018-03-28 06:32:19 -07009use proc_macro2::{Literal, Span};
David Tolnay360efd22018-01-04 23:35:26 -080010use std::str;
11
David Tolnay7d1d1282018-01-06 16:10:51 -080012#[cfg(feature = "printing")]
Alex Crichtona74a1c82018-05-16 10:20:44 -070013use proc_macro2::Ident;
David Tolnay7d1d1282018-01-06 16:10:51 -080014
David Tolnayd53ac2b2018-01-27 19:00:06 -080015#[cfg(feature = "parsing")]
16use proc_macro2::TokenStream;
17#[cfg(feature = "parsing")]
David Tolnaye82a2b12018-08-30 16:31:10 -070018use Error;
David Tolnayd53ac2b2018-01-27 19:00:06 -080019
David Tolnay60fafad2018-02-03 09:18:03 -080020use proc_macro2::TokenTree;
21
David Tolnay360efd22018-01-04 23:35:26 -080022#[cfg(feature = "extra-traits")]
Alex Crichtonccbb45d2017-05-23 10:58:24 -070023use std::hash::{Hash, Hasher};
24
David Tolnay4fb71232018-08-25 23:14:50 -040025#[cfg(feature = "parsing")]
26use lookahead;
David Tolnaye82a2b12018-08-30 16:31:10 -070027#[cfg(feature = "parsing")]
28use parse::Parse;
David Tolnay4fb71232018-08-25 23:14:50 -040029
David Tolnay360efd22018-01-04 23:35:26 -080030ast_enum_of_structs! {
David Tolnayabf5c2e2018-01-06 23:30:04 -080031 /// A Rust literal such as a string or integer or boolean.
David Tolnay614a0142018-01-07 10:25:43 -080032 ///
David Tolnay461d98e2018-01-07 11:07:19 -080033 /// *This type is available if Syn is built with the `"derive"` or `"full"`
34 /// feature.*
35 ///
David Tolnay614a0142018-01-07 10:25:43 -080036 /// # Syntax tree enum
37 ///
38 /// This type is a [syntax tree enum].
39 ///
40 /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
David Tolnay360efd22018-01-04 23:35:26 -080041 pub enum Lit {
David Tolnayabf5c2e2018-01-06 23:30:04 -080042 /// A UTF-8 string literal: `"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 Str(LitStr #manual_extra_traits {
47 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080048 }),
Alex Crichtonccbb45d2017-05-23 10:58:24 -070049
David Tolnayabf5c2e2018-01-06 23:30:04 -080050 /// A byte string literal: `b"foo"`.
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 ByteStr(LitByteStr #manual_extra_traits {
55 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080056 }),
57
David Tolnayabf5c2e2018-01-06 23:30:04 -080058 /// A byte literal: `b'f'`.
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 Byte(LitByte #manual_extra_traits {
63 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080064 }),
65
David Tolnayabf5c2e2018-01-06 23:30:04 -080066 /// A character literal: `'a'`.
David Tolnay461d98e2018-01-07 11:07:19 -080067 ///
68 /// *This type is available if Syn is built with the `"derive"` or
69 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080070 pub Char(LitChar #manual_extra_traits {
71 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080072 }),
73
David Tolnayabf5c2e2018-01-06 23:30:04 -080074 /// An integer literal: `1` or `1u16`.
David Tolnay360efd22018-01-04 23:35:26 -080075 ///
76 /// Holds up to 64 bits of data. Use `LitVerbatim` for any larger
77 /// integer literal.
David Tolnay461d98e2018-01-07 11:07:19 -080078 ///
79 /// *This type is available if Syn is built with the `"derive"` or
80 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080081 pub Int(LitInt #manual_extra_traits {
82 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080083 }),
84
David Tolnayabf5c2e2018-01-06 23:30:04 -080085 /// A floating point literal: `1f64` or `1.0e10f64`.
David Tolnay360efd22018-01-04 23:35:26 -080086 ///
87 /// Must be finite. May not be infinte or NaN.
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 Float(LitFloat #manual_extra_traits {
92 token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -080093 }),
94
David Tolnayabf5c2e2018-01-06 23:30:04 -080095 /// A boolean literal: `true` or `false`.
David Tolnay461d98e2018-01-07 11:07:19 -080096 ///
97 /// *This type is available if Syn is built with the `"derive"` or
98 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -080099 pub Bool(LitBool #manual_extra_traits {
100 pub value: bool,
101 pub span: Span,
102 }),
103
David Tolnayabf5c2e2018-01-06 23:30:04 -0800104 /// A raw token literal not interpreted by Syn, possibly because it
105 /// represents an integer larger than 64 bits.
David Tolnay461d98e2018-01-07 11:07:19 -0800106 ///
107 /// *This type is available if Syn is built with the `"derive"` or
108 /// `"full"` feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800109 pub Verbatim(LitVerbatim #manual_extra_traits {
110 pub token: Literal,
David Tolnay360efd22018-01-04 23:35:26 -0800111 }),
112 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700113}
114
David Tolnay360efd22018-01-04 23:35:26 -0800115impl LitStr {
116 pub fn new(value: &str, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700117 let mut lit = Literal::string(value);
118 lit.set_span(span);
David Tolnay94d2b792018-04-29 12:26:10 -0700119 LitStr { token: lit }
David Tolnay360efd22018-01-04 23:35:26 -0800120 }
121
122 pub fn value(&self) -> String {
123 value::parse_lit_str(&self.token.to_string())
124 }
David Tolnayd53ac2b2018-01-27 19:00:06 -0800125
126 /// Parse a syntax tree node from the content of this string literal.
127 ///
128 /// All spans in the syntax tree will point to the span of this `LitStr`.
David Tolnay3b0444a2018-09-01 17:17:19 -0700129 ///
130 /// # Example
131 ///
132 /// ```
133 /// # extern crate proc_macro2;
134 /// # extern crate syn;
135 /// #
136 /// use proc_macro2::Span;
David Tolnay67fea042018-11-24 14:50:20 -0800137 /// use syn::{Attribute, Error, Ident, Lit, Meta, MetaNameValue, Path, Result};
David Tolnay3b0444a2018-09-01 17:17:19 -0700138 ///
139 /// // Parses the path from an attribute that looks like:
140 /// //
141 /// // #[path = "a::b::c"]
142 /// //
David Tolnay4ac734f2018-11-10 14:19:00 -0800143 /// // or returns `None` if the input is some other attribute.
144 /// fn get_path(attr: &Attribute) -> Result<Option<Path>> {
145 /// if !attr.path.is_ident("path") {
146 /// return Ok(None);
David Tolnay3b0444a2018-09-01 17:17:19 -0700147 /// }
148 ///
David Tolnay4ac734f2018-11-10 14:19:00 -0800149 /// match attr.parse_meta()? {
David Tolnay3b0444a2018-09-01 17:17:19 -0700150 /// Meta::NameValue(MetaNameValue { lit: Lit::Str(lit_str), .. }) => {
David Tolnay4ac734f2018-11-10 14:19:00 -0800151 /// lit_str.parse().map(Some)
David Tolnay3b0444a2018-09-01 17:17:19 -0700152 /// }
153 /// _ => {
154 /// let error_span = attr.bracket_token.span;
155 /// let message = "expected #[path = \"...\"]";
156 /// Err(Error::new(error_span, message))
157 /// }
158 /// }
159 /// }
160 /// ```
David Tolnayd53ac2b2018-01-27 19:00:06 -0800161 #[cfg(feature = "parsing")]
David Tolnaye82a2b12018-08-30 16:31:10 -0700162 pub fn parse<T: Parse>(&self) -> Result<T, Error> {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700163 use proc_macro2::Group;
164
David Tolnayd53ac2b2018-01-27 19:00:06 -0800165 // Parse string literal into a token stream with every span equal to the
166 // original literal's span.
David Tolnayad4b2472018-08-25 08:25:24 -0400167 fn spanned_tokens(s: &LitStr) -> Result<TokenStream, Error> {
David Tolnayd53ac2b2018-01-27 19:00:06 -0800168 let stream = ::parse_str(&s.value())?;
Alex Crichton9a4dca22018-03-28 06:32:19 -0700169 Ok(respan_token_stream(stream, s.span()))
David Tolnayd53ac2b2018-01-27 19:00:06 -0800170 }
171
172 // Token stream with every span replaced by the given one.
173 fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
David Tolnay94d2b792018-04-29 12:26:10 -0700174 stream
175 .into_iter()
176 .map(|token| respan_token_tree(token, span))
177 .collect()
David Tolnayd53ac2b2018-01-27 19:00:06 -0800178 }
179
180 // Token tree with every span replaced by the given one.
Alex Crichton9a4dca22018-03-28 06:32:19 -0700181 fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
182 match token {
183 TokenTree::Group(ref mut g) => {
184 let stream = respan_token_stream(g.stream().clone(), span);
185 *g = Group::new(g.delimiter(), stream);
186 g.set_span(span);
187 }
188 ref mut other => other.set_span(span),
David Tolnayd53ac2b2018-01-27 19:00:06 -0800189 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700190 token
David Tolnayd53ac2b2018-01-27 19:00:06 -0800191 }
192
193 spanned_tokens(self).and_then(::parse2)
194 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700195
196 pub fn span(&self) -> Span {
197 self.token.span()
198 }
199
200 pub fn set_span(&mut self, span: Span) {
201 self.token.set_span(span)
202 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700203}
204
David Tolnay360efd22018-01-04 23:35:26 -0800205impl LitByteStr {
206 pub fn new(value: &[u8], span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700207 let mut token = Literal::byte_string(value);
208 token.set_span(span);
209 LitByteStr { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800210 }
211
212 pub fn value(&self) -> Vec<u8> {
213 value::parse_lit_byte_str(&self.token.to_string())
214 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700215
216 pub fn span(&self) -> Span {
217 self.token.span()
218 }
219
220 pub fn set_span(&mut self, span: Span) {
221 self.token.set_span(span)
222 }
David Tolnay360efd22018-01-04 23:35:26 -0800223}
224
225impl LitByte {
226 pub fn new(value: u8, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700227 let mut token = Literal::u8_suffixed(value);
228 token.set_span(span);
229 LitByte { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800230 }
231
232 pub fn value(&self) -> u8 {
233 value::parse_lit_byte(&self.token.to_string())
234 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700235
236 pub fn span(&self) -> Span {
237 self.token.span()
238 }
239
240 pub fn set_span(&mut self, span: Span) {
241 self.token.set_span(span)
242 }
David Tolnay360efd22018-01-04 23:35:26 -0800243}
244
245impl LitChar {
246 pub fn new(value: char, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700247 let mut token = Literal::character(value);
248 token.set_span(span);
249 LitChar { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800250 }
251
252 pub fn value(&self) -> char {
253 value::parse_lit_char(&self.token.to_string())
254 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700255
256 pub fn span(&self) -> Span {
257 self.token.span()
258 }
259
260 pub fn set_span(&mut self, span: Span) {
261 self.token.set_span(span)
262 }
David Tolnay360efd22018-01-04 23:35:26 -0800263}
264
265impl LitInt {
266 pub fn new(value: u64, suffix: IntSuffix, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700267 let mut token = match suffix {
268 IntSuffix::Isize => Literal::isize_suffixed(value as isize),
269 IntSuffix::I8 => Literal::i8_suffixed(value as i8),
270 IntSuffix::I16 => Literal::i16_suffixed(value as i16),
271 IntSuffix::I32 => Literal::i32_suffixed(value as i32),
272 IntSuffix::I64 => Literal::i64_suffixed(value as i64),
273 IntSuffix::I128 => value::to_literal(&format!("{}i128", value)),
274 IntSuffix::Usize => Literal::usize_suffixed(value as usize),
275 IntSuffix::U8 => Literal::u8_suffixed(value as u8),
276 IntSuffix::U16 => Literal::u16_suffixed(value as u16),
277 IntSuffix::U32 => Literal::u32_suffixed(value as u32),
278 IntSuffix::U64 => Literal::u64_suffixed(value),
279 IntSuffix::U128 => value::to_literal(&format!("{}u128", value)),
280 IntSuffix::None => Literal::u64_unsuffixed(value),
281 };
282 token.set_span(span);
283 LitInt { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800284 }
285
286 pub fn value(&self) -> u64 {
287 value::parse_lit_int(&self.token.to_string()).unwrap()
288 }
289
290 pub fn suffix(&self) -> IntSuffix {
291 let value = self.token.to_string();
292 for (s, suffix) in vec![
293 ("i8", IntSuffix::I8),
294 ("i16", IntSuffix::I16),
295 ("i32", IntSuffix::I32),
296 ("i64", IntSuffix::I64),
297 ("i128", IntSuffix::I128),
298 ("isize", IntSuffix::Isize),
299 ("u8", IntSuffix::U8),
300 ("u16", IntSuffix::U16),
301 ("u32", IntSuffix::U32),
302 ("u64", IntSuffix::U64),
303 ("u128", IntSuffix::U128),
304 ("usize", IntSuffix::Usize),
305 ] {
306 if value.ends_with(s) {
307 return suffix;
308 }
309 }
310 IntSuffix::None
311 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700312
313 pub fn span(&self) -> Span {
314 self.token.span()
315 }
316
317 pub fn set_span(&mut self, span: Span) {
318 self.token.set_span(span)
319 }
David Tolnay360efd22018-01-04 23:35:26 -0800320}
321
322impl LitFloat {
323 pub fn new(value: f64, suffix: FloatSuffix, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700324 let mut token = match suffix {
325 FloatSuffix::F32 => Literal::f32_suffixed(value as f32),
326 FloatSuffix::F64 => Literal::f64_suffixed(value),
327 FloatSuffix::None => Literal::f64_unsuffixed(value),
328 };
329 token.set_span(span);
330 LitFloat { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800331 }
332
333 pub fn value(&self) -> f64 {
334 value::parse_lit_float(&self.token.to_string())
335 }
336
337 pub fn suffix(&self) -> FloatSuffix {
338 let value = self.token.to_string();
David Tolnay61037c62018-01-05 16:21:03 -0800339 for (s, suffix) in vec![("f32", FloatSuffix::F32), ("f64", FloatSuffix::F64)] {
David Tolnay360efd22018-01-04 23:35:26 -0800340 if value.ends_with(s) {
341 return suffix;
342 }
343 }
344 FloatSuffix::None
345 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700346
347 pub fn span(&self) -> Span {
348 self.token.span()
349 }
350
351 pub fn set_span(&mut self, span: Span) {
352 self.token.set_span(span)
353 }
David Tolnay360efd22018-01-04 23:35:26 -0800354}
355
356macro_rules! lit_extra_traits {
357 ($ty:ident, $field:ident) => {
358 #[cfg(feature = "extra-traits")]
359 impl Eq for $ty {}
360
361 #[cfg(feature = "extra-traits")]
362 impl PartialEq for $ty {
363 fn eq(&self, other: &Self) -> bool {
364 self.$field.to_string() == other.$field.to_string()
365 }
366 }
367
368 #[cfg(feature = "extra-traits")]
369 impl Hash for $ty {
370 fn hash<H>(&self, state: &mut H)
371 where
372 H: Hasher,
373 {
374 self.$field.to_string().hash(state);
375 }
David Tolnay9c76bcb2017-12-26 23:14:59 -0500376 }
David Tolnay6a170ce2018-08-26 22:29:24 -0700377
378 #[cfg(feature = "parsing")]
379 #[doc(hidden)]
380 #[allow(non_snake_case)]
381 pub fn $ty(marker: lookahead::TokenMarker) -> $ty {
382 match marker {}
383 }
David Tolnay94d2b792018-04-29 12:26:10 -0700384 };
David Tolnayf4bbbd92016-09-23 14:41:55 -0700385}
386
Alex Crichton9a4dca22018-03-28 06:32:19 -0700387impl LitVerbatim {
388 pub fn span(&self) -> Span {
389 self.token.span()
390 }
391
392 pub fn set_span(&mut self, span: Span) {
393 self.token.set_span(span)
394 }
395}
396
David Tolnay360efd22018-01-04 23:35:26 -0800397lit_extra_traits!(LitStr, token);
398lit_extra_traits!(LitByteStr, token);
399lit_extra_traits!(LitByte, token);
400lit_extra_traits!(LitChar, token);
401lit_extra_traits!(LitInt, token);
402lit_extra_traits!(LitFloat, token);
403lit_extra_traits!(LitBool, value);
404lit_extra_traits!(LitVerbatim, token);
405
406ast_enum! {
David Tolnay05658502018-01-07 09:56:37 -0800407 /// The style of a string literal, either plain quoted or a raw string like
David Tolnayabf5c2e2018-01-06 23:30:04 -0800408 /// `r##"data"##`.
David Tolnay461d98e2018-01-07 11:07:19 -0800409 ///
410 /// *This type is available if Syn is built with the `"derive"` or `"full"`
411 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800412 pub enum StrStyle #no_visit {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800413 /// An ordinary string like `"data"`.
David Tolnay360efd22018-01-04 23:35:26 -0800414 Cooked,
David Tolnayabf5c2e2018-01-06 23:30:04 -0800415 /// A raw string like `r##"data"##`.
David Tolnay360efd22018-01-04 23:35:26 -0800416 ///
417 /// The unsigned integer is the number of `#` symbols used.
418 Raw(usize),
Alex Crichton62a0a592017-05-22 13:58:53 -0700419 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700420}
421
David Tolnay360efd22018-01-04 23:35:26 -0800422ast_enum! {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800423 /// The suffix on an integer literal if any, like the `u8` in `127u8`.
David Tolnay461d98e2018-01-07 11:07:19 -0800424 ///
425 /// *This type is available if Syn is built with the `"derive"` or `"full"`
426 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800427 pub enum IntSuffix #no_visit {
428 I8,
429 I16,
430 I32,
431 I64,
432 I128,
433 Isize,
434 U8,
435 U16,
436 U32,
437 U64,
438 U128,
439 Usize,
440 None,
Pascal Hertleif36342c52016-10-19 10:31:42 +0200441 }
442}
443
David Tolnay360efd22018-01-04 23:35:26 -0800444ast_enum! {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800445 /// The suffix on a floating point literal if any, like the `f32` in
446 /// `1.0f32`.
David Tolnay461d98e2018-01-07 11:07:19 -0800447 ///
448 /// *This type is available if Syn is built with the `"derive"` or `"full"`
449 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800450 pub enum FloatSuffix #no_visit {
451 F32,
452 F64,
453 None,
Alex Crichton2e0229c2017-05-23 09:34:50 -0700454 }
David Tolnay5fe14fc2017-01-27 16:22:08 -0800455}
456
457#[cfg(feature = "parsing")]
David Tolnay4fb71232018-08-25 23:14:50 -0400458#[doc(hidden)]
459#[allow(non_snake_case)]
460pub fn Lit(marker: lookahead::TokenMarker) -> Lit {
461 match marker {}
462}
463
464#[cfg(feature = "parsing")]
David Tolnayf4bbbd92016-09-23 14:41:55 -0700465pub mod parsing {
466 use super::*;
David Tolnay4fb71232018-08-25 23:14:50 -0400467 use parse::{Parse, ParseStream, Result};
David Tolnayf4bbbd92016-09-23 14:41:55 -0700468
David Tolnay4fb71232018-08-25 23:14:50 -0400469 impl Parse for Lit {
470 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay924e0af2018-09-01 13:07:34 -0700471 input.step(|cursor| {
472 if let Some((lit, rest)) = cursor.literal() {
473 return Ok((Lit::new(lit), rest));
474 }
475 while let Some((ident, rest)) = cursor.ident() {
476 let value = if ident == "true" {
477 true
478 } else if ident == "false" {
479 false
480 } else {
481 break;
482 };
483 let lit_bool = LitBool {
484 value: value,
485 span: ident.span(),
486 };
487 return Ok((Lit::Bool(lit_bool), rest));
488 }
489 Err(cursor.error("expected literal"))
David Tolnay4fb71232018-08-25 23:14:50 -0400490 })
Sergio Benitez5680d6a2017-12-29 11:20:29 -0800491 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700492 }
David Tolnay360efd22018-01-04 23:35:26 -0800493
David Tolnaya7d69fc2018-08-26 13:30:24 -0400494 impl Parse for LitStr {
495 fn parse(input: ParseStream) -> Result<Self> {
496 let head = input.fork();
497 match input.parse()? {
498 Lit::Str(lit) => Ok(lit),
499 _ => Err(head.error("expected string literal")),
500 }
501 }
502 }
David Tolnay360efd22018-01-04 23:35:26 -0800503
David Tolnaya7d69fc2018-08-26 13:30:24 -0400504 impl Parse for LitByteStr {
505 fn parse(input: ParseStream) -> Result<Self> {
506 let head = input.fork();
507 match input.parse()? {
508 Lit::ByteStr(lit) => Ok(lit),
509 _ => Err(head.error("expected byte string literal")),
510 }
511 }
512 }
David Tolnay360efd22018-01-04 23:35:26 -0800513
David Tolnaya7d69fc2018-08-26 13:30:24 -0400514 impl Parse for LitByte {
515 fn parse(input: ParseStream) -> Result<Self> {
516 let head = input.fork();
517 match input.parse()? {
518 Lit::Byte(lit) => Ok(lit),
519 _ => Err(head.error("expected byte literal")),
520 }
521 }
522 }
David Tolnay360efd22018-01-04 23:35:26 -0800523
David Tolnaya7d69fc2018-08-26 13:30:24 -0400524 impl Parse for LitChar {
525 fn parse(input: ParseStream) -> Result<Self> {
526 let head = input.fork();
527 match input.parse()? {
528 Lit::Char(lit) => Ok(lit),
529 _ => Err(head.error("expected character literal")),
530 }
531 }
532 }
David Tolnay360efd22018-01-04 23:35:26 -0800533
David Tolnaya7d69fc2018-08-26 13:30:24 -0400534 impl Parse for LitInt {
535 fn parse(input: ParseStream) -> Result<Self> {
536 let head = input.fork();
537 match input.parse()? {
538 Lit::Int(lit) => Ok(lit),
539 _ => Err(head.error("expected integer literal")),
540 }
541 }
542 }
David Tolnay360efd22018-01-04 23:35:26 -0800543
David Tolnaya7d69fc2018-08-26 13:30:24 -0400544 impl Parse for LitFloat {
545 fn parse(input: ParseStream) -> Result<Self> {
546 let head = input.fork();
547 match input.parse()? {
548 Lit::Float(lit) => Ok(lit),
549 _ => Err(head.error("expected floating point literal")),
550 }
551 }
552 }
David Tolnay360efd22018-01-04 23:35:26 -0800553
David Tolnaya7d69fc2018-08-26 13:30:24 -0400554 impl Parse for LitBool {
555 fn parse(input: ParseStream) -> Result<Self> {
556 let head = input.fork();
557 match input.parse()? {
558 Lit::Bool(lit) => Ok(lit),
559 _ => Err(head.error("expected boolean literal")),
560 }
561 }
562 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700563}
564
565#[cfg(feature = "printing")]
566mod printing {
567 use super::*;
Alex Crichtona74a1c82018-05-16 10:20:44 -0700568 use proc_macro2::TokenStream;
David Tolnay65fb5662018-05-20 20:02:28 -0700569 use quote::{ToTokens, TokenStreamExt};
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700570
David Tolnay360efd22018-01-04 23:35:26 -0800571 impl ToTokens for LitStr {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700572 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700573 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800574 }
575 }
576
577 impl ToTokens for LitByteStr {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700578 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700579 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800580 }
581 }
582
583 impl ToTokens for LitByte {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700584 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700585 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800586 }
587 }
588
589 impl ToTokens for LitChar {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700590 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700591 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800592 }
593 }
594
595 impl ToTokens for LitInt {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700596 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700597 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800598 }
599 }
600
601 impl ToTokens for LitFloat {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700602 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700603 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800604 }
605 }
606
607 impl ToTokens for LitBool {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700608 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700609 let s = if self.value { "true" } else { "false" };
Alex Crichtona74a1c82018-05-16 10:20:44 -0700610 tokens.append(Ident::new(s, self.span));
David Tolnay360efd22018-01-04 23:35:26 -0800611 }
612 }
613
614 impl ToTokens for LitVerbatim {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700615 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700616 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800617 }
618 }
619}
620
621mod value {
622 use super::*;
David Tolnay94d2b792018-04-29 12:26:10 -0700623 use proc_macro2::TokenStream;
David Tolnay360efd22018-01-04 23:35:26 -0800624 use std::char;
625 use std::ops::{Index, RangeFrom};
David Tolnay360efd22018-01-04 23:35:26 -0800626
David Tolnay7d1d1282018-01-06 16:10:51 -0800627 impl Lit {
David Tolnay780292d2018-01-22 23:26:44 -0800628 /// Interpret a Syn literal from a proc-macro2 literal.
629 ///
630 /// Not all proc-macro2 literals are valid Syn literals. In particular,
631 /// doc comments are considered by proc-macro2 to be literals but in Syn
632 /// they are [`Attribute`].
633 ///
634 /// [`Attribute`]: struct.Attribute.html
635 ///
636 /// # Panics
637 ///
638 /// Panics if the input is a doc comment literal.
Alex Crichton9a4dca22018-03-28 06:32:19 -0700639 pub fn new(token: Literal) -> Self {
David Tolnay7d1d1282018-01-06 16:10:51 -0800640 let value = token.to_string();
641
642 match value::byte(&value, 0) {
David Tolnay94d2b792018-04-29 12:26:10 -0700643 b'"' | b'r' => return Lit::Str(LitStr { token: token }),
David Tolnay7d1d1282018-01-06 16:10:51 -0800644 b'b' => match value::byte(&value, 1) {
David Tolnay94d2b792018-04-29 12:26:10 -0700645 b'"' | b'r' => return Lit::ByteStr(LitByteStr { token: token }),
646 b'\'' => return Lit::Byte(LitByte { token: token }),
David Tolnay7d1d1282018-01-06 16:10:51 -0800647 _ => {}
648 },
David Tolnay94d2b792018-04-29 12:26:10 -0700649 b'\'' => return Lit::Char(LitChar { token: token }),
David Tolnayfb84fc02018-10-02 21:01:30 -0700650 b'0'...b'9' => {
651 if number_is_int(&value) {
652 return Lit::Int(LitInt { token: token });
653 } else if number_is_float(&value) {
654 return Lit::Float(LitFloat { token: token });
655 } else {
656 // number overflow
657 return Lit::Verbatim(LitVerbatim { token: token });
658 }
659 }
660 _ => {
661 if value == "true" || value == "false" {
662 return Lit::Bool(LitBool {
663 value: value == "true",
664 span: token.span(),
665 });
666 }
667 }
David Tolnay7d1d1282018-01-06 16:10:51 -0800668 }
669
670 panic!("Unrecognized literal: {}", value);
671 }
672 }
673
674 fn number_is_int(value: &str) -> bool {
675 if number_is_float(value) {
676 false
677 } else {
678 value::parse_lit_int(value).is_some()
679 }
680 }
681
682 fn number_is_float(value: &str) -> bool {
683 if value.contains('.') {
684 true
685 } else if value.starts_with("0x") || value.ends_with("size") {
686 false
687 } else {
688 value.contains('e') || value.contains('E')
689 }
690 }
691
David Tolnay360efd22018-01-04 23:35:26 -0800692 /// Get the byte at offset idx, or a default of `b'\0'` if we're looking
693 /// past the end of the input buffer.
694 pub fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 {
695 let s = s.as_ref();
696 if idx < s.len() {
697 s[idx]
698 } else {
699 0
700 }
701 }
702
703 fn next_chr(s: &str) -> char {
704 s.chars().next().unwrap_or('\0')
705 }
706
707 pub fn parse_lit_str(s: &str) -> String {
708 match byte(s, 0) {
709 b'"' => parse_lit_str_cooked(s),
710 b'r' => parse_lit_str_raw(s),
711 _ => unreachable!(),
712 }
713 }
714
David Tolnay76ebcdd2018-01-05 17:07:26 -0800715 // Clippy false positive
716 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
717 #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))]
David Tolnay360efd22018-01-04 23:35:26 -0800718 fn parse_lit_str_cooked(mut s: &str) -> String {
719 assert_eq!(byte(s, 0), b'"');
720 s = &s[1..];
721
722 let mut out = String::new();
723 'outer: loop {
724 let ch = match byte(s, 0) {
725 b'"' => break,
726 b'\\' => {
727 let b = byte(s, 1);
728 s = &s[2..];
729 match b {
730 b'x' => {
731 let (byte, rest) = backslash_x(s);
732 s = rest;
733 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
David Tolnay76ebcdd2018-01-05 17:07:26 -0800734 char::from_u32(u32::from(byte)).unwrap()
David Tolnay360efd22018-01-04 23:35:26 -0800735 }
736 b'u' => {
David Tolnay76ebcdd2018-01-05 17:07:26 -0800737 let (chr, rest) = backslash_u(s);
David Tolnay360efd22018-01-04 23:35:26 -0800738 s = rest;
739 chr
740 }
741 b'n' => '\n',
742 b'r' => '\r',
743 b't' => '\t',
744 b'\\' => '\\',
745 b'0' => '\0',
746 b'\'' => '\'',
747 b'"' => '"',
David Tolnay61037c62018-01-05 16:21:03 -0800748 b'\r' | b'\n' => loop {
749 let ch = next_chr(s);
750 if ch.is_whitespace() {
751 s = &s[ch.len_utf8()..];
752 } else {
753 continue 'outer;
David Tolnay360efd22018-01-04 23:35:26 -0800754 }
David Tolnay61037c62018-01-05 16:21:03 -0800755 },
756 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800757 }
758 }
759 b'\r' => {
760 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
761 s = &s[2..];
762 '\n'
763 }
764 _ => {
765 let ch = next_chr(s);
766 s = &s[ch.len_utf8()..];
767 ch
768 }
769 };
770 out.push(ch);
771 }
772
773 assert_eq!(s, "\"");
774 out
775 }
776
777 fn parse_lit_str_raw(mut s: &str) -> String {
778 assert_eq!(byte(s, 0), b'r');
779 s = &s[1..];
780
781 let mut pounds = 0;
782 while byte(s, pounds) == b'#' {
783 pounds += 1;
784 }
785 assert_eq!(byte(s, pounds), b'"');
786 assert_eq!(byte(s, s.len() - pounds - 1), b'"');
787 for end in s[s.len() - pounds..].bytes() {
788 assert_eq!(end, b'#');
789 }
790
791 s[pounds + 1..s.len() - pounds - 1].to_owned()
792 }
793
794 pub fn parse_lit_byte_str(s: &str) -> Vec<u8> {
795 assert_eq!(byte(s, 0), b'b');
796 match byte(s, 1) {
797 b'"' => parse_lit_byte_str_cooked(s),
798 b'r' => parse_lit_byte_str_raw(s),
799 _ => unreachable!(),
800 }
801 }
802
David Tolnay76ebcdd2018-01-05 17:07:26 -0800803 // Clippy false positive
804 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
805 #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))]
David Tolnay360efd22018-01-04 23:35:26 -0800806 fn parse_lit_byte_str_cooked(mut s: &str) -> Vec<u8> {
807 assert_eq!(byte(s, 0), b'b');
808 assert_eq!(byte(s, 1), b'"');
809 s = &s[2..];
810
811 // We're going to want to have slices which don't respect codepoint boundaries.
812 let mut s = s.as_bytes();
813
814 let mut out = Vec::new();
815 'outer: loop {
816 let byte = match byte(s, 0) {
817 b'"' => break,
818 b'\\' => {
819 let b = byte(s, 1);
820 s = &s[2..];
821 match b {
822 b'x' => {
823 let (b, rest) = backslash_x(s);
824 s = rest;
825 b
826 }
827 b'n' => b'\n',
828 b'r' => b'\r',
829 b't' => b'\t',
830 b'\\' => b'\\',
831 b'0' => b'\0',
832 b'\'' => b'\'',
833 b'"' => b'"',
David Tolnay61037c62018-01-05 16:21:03 -0800834 b'\r' | b'\n' => loop {
835 let byte = byte(s, 0);
David Tolnay76ebcdd2018-01-05 17:07:26 -0800836 let ch = char::from_u32(u32::from(byte)).unwrap();
David Tolnay61037c62018-01-05 16:21:03 -0800837 if ch.is_whitespace() {
838 s = &s[1..];
839 } else {
840 continue 'outer;
David Tolnay360efd22018-01-04 23:35:26 -0800841 }
David Tolnay61037c62018-01-05 16:21:03 -0800842 },
843 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800844 }
845 }
846 b'\r' => {
847 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
848 s = &s[2..];
849 b'\n'
850 }
851 b => {
852 s = &s[1..];
853 b
854 }
855 };
856 out.push(byte);
857 }
858
859 assert_eq!(s, b"\"");
860 out
861 }
862
863 fn parse_lit_byte_str_raw(s: &str) -> Vec<u8> {
864 assert_eq!(byte(s, 0), b'b');
865 parse_lit_str_raw(&s[1..]).into_bytes()
866 }
867
868 pub fn parse_lit_byte(s: &str) -> u8 {
869 assert_eq!(byte(s, 0), b'b');
870 assert_eq!(byte(s, 1), b'\'');
871
872 // We're going to want to have slices which don't respect codepoint boundaries.
873 let mut s = s[2..].as_bytes();
874
875 let b = match byte(s, 0) {
876 b'\\' => {
877 let b = byte(s, 1);
878 s = &s[2..];
879 match b {
880 b'x' => {
881 let (b, rest) = backslash_x(s);
882 s = rest;
883 b
884 }
885 b'n' => b'\n',
886 b'r' => b'\r',
887 b't' => b'\t',
888 b'\\' => b'\\',
889 b'0' => b'\0',
890 b'\'' => b'\'',
891 b'"' => b'"',
David Tolnay61037c62018-01-05 16:21:03 -0800892 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800893 }
894 }
895 b => {
896 s = &s[1..];
897 b
898 }
899 };
900
901 assert_eq!(byte(s, 0), b'\'');
902 b
903 }
904
905 pub fn parse_lit_char(mut s: &str) -> char {
906 assert_eq!(byte(s, 0), b'\'');
907 s = &s[1..];
908
909 let ch = match byte(s, 0) {
910 b'\\' => {
911 let b = byte(s, 1);
912 s = &s[2..];
913 match b {
914 b'x' => {
915 let (byte, rest) = backslash_x(s);
916 s = rest;
917 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
David Tolnay76ebcdd2018-01-05 17:07:26 -0800918 char::from_u32(u32::from(byte)).unwrap()
David Tolnay360efd22018-01-04 23:35:26 -0800919 }
920 b'u' => {
921 let (chr, rest) = backslash_u(s);
922 s = rest;
923 chr
924 }
925 b'n' => '\n',
926 b'r' => '\r',
927 b't' => '\t',
928 b'\\' => '\\',
929 b'0' => '\0',
930 b'\'' => '\'',
931 b'"' => '"',
David Tolnay61037c62018-01-05 16:21:03 -0800932 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800933 }
934 }
935 _ => {
936 let ch = next_chr(s);
937 s = &s[ch.len_utf8()..];
938 ch
939 }
940 };
941 assert_eq!(s, "\'", "Expected end of char literal");
942 ch
943 }
944
945 fn backslash_x<S>(s: &S) -> (u8, &S)
David Tolnay61037c62018-01-05 16:21:03 -0800946 where
947 S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
David Tolnay360efd22018-01-04 23:35:26 -0800948 {
949 let mut ch = 0;
950 let b0 = byte(s, 0);
951 let b1 = byte(s, 1);
David Tolnaye614f282018-10-27 22:50:12 -0700952 ch += 0x10
953 * match b0 {
954 b'0'...b'9' => b0 - b'0',
955 b'a'...b'f' => 10 + (b0 - b'a'),
956 b'A'...b'F' => 10 + (b0 - b'A'),
957 _ => panic!("unexpected non-hex character after \\x"),
958 };
David Tolnay76ebcdd2018-01-05 17:07:26 -0800959 ch += match b1 {
David Tolnay360efd22018-01-04 23:35:26 -0800960 b'0'...b'9' => b1 - b'0',
961 b'a'...b'f' => 10 + (b1 - b'a'),
962 b'A'...b'F' => 10 + (b1 - b'A'),
963 _ => panic!("unexpected non-hex character after \\x"),
964 };
965 (ch, &s[2..])
966 }
967
968 fn backslash_u(mut s: &str) -> (char, &str) {
969 if byte(s, 0) != b'{' {
970 panic!("expected {{ after \\u");
971 }
972 s = &s[1..];
973
974 let mut ch = 0;
975 for _ in 0..6 {
976 let b = byte(s, 0);
977 match b {
978 b'0'...b'9' => {
979 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800980 ch += u32::from(b - b'0');
David Tolnay360efd22018-01-04 23:35:26 -0800981 s = &s[1..];
982 }
983 b'a'...b'f' => {
984 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800985 ch += u32::from(10 + b - b'a');
David Tolnay360efd22018-01-04 23:35:26 -0800986 s = &s[1..];
987 }
988 b'A'...b'F' => {
989 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800990 ch += u32::from(10 + b - b'A');
David Tolnay360efd22018-01-04 23:35:26 -0800991 s = &s[1..];
992 }
993 b'}' => break,
994 _ => panic!("unexpected non-hex character after \\u"),
995 }
996 }
997 assert!(byte(s, 0) == b'}');
998 s = &s[1..];
999
1000 if let Some(ch) = char::from_u32(ch) {
1001 (ch, s)
1002 } else {
1003 panic!("character code {:x} is not a valid unicode character", ch);
1004 }
1005 }
1006
1007 pub fn parse_lit_int(mut s: &str) -> Option<u64> {
1008 let base = match (byte(s, 0), byte(s, 1)) {
1009 (b'0', b'x') => {
1010 s = &s[2..];
1011 16
1012 }
1013 (b'0', b'o') => {
1014 s = &s[2..];
1015 8
1016 }
1017 (b'0', b'b') => {
1018 s = &s[2..];
1019 2
1020 }
1021 (b'0'...b'9', _) => 10,
1022 _ => unreachable!(),
1023 };
1024
1025 let mut value = 0u64;
1026 loop {
1027 let b = byte(s, 0);
1028 let digit = match b {
David Tolnay76ebcdd2018-01-05 17:07:26 -08001029 b'0'...b'9' => u64::from(b - b'0'),
1030 b'a'...b'f' if base > 10 => 10 + u64::from(b - b'a'),
1031 b'A'...b'F' if base > 10 => 10 + u64::from(b - b'A'),
David Tolnay360efd22018-01-04 23:35:26 -08001032 b'_' => {
1033 s = &s[1..];
1034 continue;
1035 }
1036 // NOTE: Looking at a floating point literal, we don't want to
1037 // consider these integers.
1038 b'.' if base == 10 => return None,
1039 b'e' | b'E' if base == 10 => return None,
1040 _ => break,
1041 };
1042
1043 if digit >= base {
1044 panic!("Unexpected digit {:x} out of base range", digit);
1045 }
1046
1047 value = match value.checked_mul(base) {
1048 Some(value) => value,
1049 None => return None,
1050 };
1051 value = match value.checked_add(digit) {
1052 Some(value) => value,
1053 None => return None,
1054 };
1055 s = &s[1..];
1056 }
1057
1058 Some(value)
1059 }
1060
1061 pub fn parse_lit_float(input: &str) -> f64 {
1062 // Rust's floating point literals are very similar to the ones parsed by
1063 // the standard library, except that rust's literals can contain
1064 // ignorable underscores. Let's remove those underscores.
1065 let mut bytes = input.to_owned().into_bytes();
1066 let mut write = 0;
1067 for read in 0..bytes.len() {
1068 if bytes[read] == b'_' {
1069 continue; // Don't increase write
David Tolnay76ebcdd2018-01-05 17:07:26 -08001070 }
1071 if write != read {
David Tolnay360efd22018-01-04 23:35:26 -08001072 let x = bytes[read];
1073 bytes[write] = x;
1074 }
1075 write += 1;
1076 }
1077 bytes.truncate(write);
1078 let input = String::from_utf8(bytes).unwrap();
David Tolnay76ebcdd2018-01-05 17:07:26 -08001079 let end = input.find('f').unwrap_or_else(|| input.len());
David Tolnay360efd22018-01-04 23:35:26 -08001080 input[..end].parse().unwrap()
1081 }
1082
1083 pub fn to_literal(s: &str) -> Literal {
1084 let stream = s.parse::<TokenStream>().unwrap();
Alex Crichton9a4dca22018-03-28 06:32:19 -07001085 match stream.into_iter().next().unwrap() {
1086 TokenTree::Literal(l) => l,
David Tolnay360efd22018-01-04 23:35:26 -08001087 _ => unreachable!(),
David Tolnayf17fd2f2016-10-07 23:38:08 -07001088 }
1089 }
David Tolnayf4bbbd92016-09-23 14:41:55 -07001090}