blob: c1af9f2128724fe6836c5a8824c508a904564884 [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;
137 /// use syn::{Attribute, Ident, Lit, Meta, MetaNameValue, Path};
138 /// use syn::parse::{Error, Result};
139 ///
140 /// // Parses the path from an attribute that looks like:
141 /// //
142 /// // #[path = "a::b::c"]
143 /// //
David Tolnay4ac734f2018-11-10 14:19:00 -0800144 /// // or returns `None` if the input is some other attribute.
145 /// fn get_path(attr: &Attribute) -> Result<Option<Path>> {
146 /// if !attr.path.is_ident("path") {
147 /// return Ok(None);
David Tolnay3b0444a2018-09-01 17:17:19 -0700148 /// }
149 ///
David Tolnay4ac734f2018-11-10 14:19:00 -0800150 /// match attr.parse_meta()? {
David Tolnay3b0444a2018-09-01 17:17:19 -0700151 /// Meta::NameValue(MetaNameValue { lit: Lit::Str(lit_str), .. }) => {
David Tolnay4ac734f2018-11-10 14:19:00 -0800152 /// lit_str.parse().map(Some)
David Tolnay3b0444a2018-09-01 17:17:19 -0700153 /// }
154 /// _ => {
155 /// let error_span = attr.bracket_token.span;
156 /// let message = "expected #[path = \"...\"]";
157 /// Err(Error::new(error_span, message))
158 /// }
159 /// }
160 /// }
161 /// ```
David Tolnayd53ac2b2018-01-27 19:00:06 -0800162 #[cfg(feature = "parsing")]
David Tolnaye82a2b12018-08-30 16:31:10 -0700163 pub fn parse<T: Parse>(&self) -> Result<T, Error> {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700164 use proc_macro2::Group;
165
David Tolnayd53ac2b2018-01-27 19:00:06 -0800166 // Parse string literal into a token stream with every span equal to the
167 // original literal's span.
David Tolnayad4b2472018-08-25 08:25:24 -0400168 fn spanned_tokens(s: &LitStr) -> Result<TokenStream, Error> {
David Tolnayd53ac2b2018-01-27 19:00:06 -0800169 let stream = ::parse_str(&s.value())?;
Alex Crichton9a4dca22018-03-28 06:32:19 -0700170 Ok(respan_token_stream(stream, s.span()))
David Tolnayd53ac2b2018-01-27 19:00:06 -0800171 }
172
173 // Token stream with every span replaced by the given one.
174 fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
David Tolnay94d2b792018-04-29 12:26:10 -0700175 stream
176 .into_iter()
177 .map(|token| respan_token_tree(token, span))
178 .collect()
David Tolnayd53ac2b2018-01-27 19:00:06 -0800179 }
180
181 // Token tree with every span replaced by the given one.
Alex Crichton9a4dca22018-03-28 06:32:19 -0700182 fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
183 match token {
184 TokenTree::Group(ref mut g) => {
185 let stream = respan_token_stream(g.stream().clone(), span);
186 *g = Group::new(g.delimiter(), stream);
187 g.set_span(span);
188 }
189 ref mut other => other.set_span(span),
David Tolnayd53ac2b2018-01-27 19:00:06 -0800190 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700191 token
David Tolnayd53ac2b2018-01-27 19:00:06 -0800192 }
193
194 spanned_tokens(self).and_then(::parse2)
195 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700196
197 pub fn span(&self) -> Span {
198 self.token.span()
199 }
200
201 pub fn set_span(&mut self, span: Span) {
202 self.token.set_span(span)
203 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700204}
205
David Tolnay360efd22018-01-04 23:35:26 -0800206impl LitByteStr {
207 pub fn new(value: &[u8], span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700208 let mut token = Literal::byte_string(value);
209 token.set_span(span);
210 LitByteStr { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800211 }
212
213 pub fn value(&self) -> Vec<u8> {
214 value::parse_lit_byte_str(&self.token.to_string())
215 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700216
217 pub fn span(&self) -> Span {
218 self.token.span()
219 }
220
221 pub fn set_span(&mut self, span: Span) {
222 self.token.set_span(span)
223 }
David Tolnay360efd22018-01-04 23:35:26 -0800224}
225
226impl LitByte {
227 pub fn new(value: u8, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700228 let mut token = Literal::u8_suffixed(value);
229 token.set_span(span);
230 LitByte { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800231 }
232
233 pub fn value(&self) -> u8 {
234 value::parse_lit_byte(&self.token.to_string())
235 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700236
237 pub fn span(&self) -> Span {
238 self.token.span()
239 }
240
241 pub fn set_span(&mut self, span: Span) {
242 self.token.set_span(span)
243 }
David Tolnay360efd22018-01-04 23:35:26 -0800244}
245
246impl LitChar {
247 pub fn new(value: char, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700248 let mut token = Literal::character(value);
249 token.set_span(span);
250 LitChar { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800251 }
252
253 pub fn value(&self) -> char {
254 value::parse_lit_char(&self.token.to_string())
255 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700256
257 pub fn span(&self) -> Span {
258 self.token.span()
259 }
260
261 pub fn set_span(&mut self, span: Span) {
262 self.token.set_span(span)
263 }
David Tolnay360efd22018-01-04 23:35:26 -0800264}
265
266impl LitInt {
267 pub fn new(value: u64, suffix: IntSuffix, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700268 let mut token = match suffix {
269 IntSuffix::Isize => Literal::isize_suffixed(value as isize),
270 IntSuffix::I8 => Literal::i8_suffixed(value as i8),
271 IntSuffix::I16 => Literal::i16_suffixed(value as i16),
272 IntSuffix::I32 => Literal::i32_suffixed(value as i32),
273 IntSuffix::I64 => Literal::i64_suffixed(value as i64),
274 IntSuffix::I128 => value::to_literal(&format!("{}i128", value)),
275 IntSuffix::Usize => Literal::usize_suffixed(value as usize),
276 IntSuffix::U8 => Literal::u8_suffixed(value as u8),
277 IntSuffix::U16 => Literal::u16_suffixed(value as u16),
278 IntSuffix::U32 => Literal::u32_suffixed(value as u32),
279 IntSuffix::U64 => Literal::u64_suffixed(value),
280 IntSuffix::U128 => value::to_literal(&format!("{}u128", value)),
281 IntSuffix::None => Literal::u64_unsuffixed(value),
282 };
283 token.set_span(span);
284 LitInt { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800285 }
286
287 pub fn value(&self) -> u64 {
288 value::parse_lit_int(&self.token.to_string()).unwrap()
289 }
290
291 pub fn suffix(&self) -> IntSuffix {
292 let value = self.token.to_string();
293 for (s, suffix) in vec![
294 ("i8", IntSuffix::I8),
295 ("i16", IntSuffix::I16),
296 ("i32", IntSuffix::I32),
297 ("i64", IntSuffix::I64),
298 ("i128", IntSuffix::I128),
299 ("isize", IntSuffix::Isize),
300 ("u8", IntSuffix::U8),
301 ("u16", IntSuffix::U16),
302 ("u32", IntSuffix::U32),
303 ("u64", IntSuffix::U64),
304 ("u128", IntSuffix::U128),
305 ("usize", IntSuffix::Usize),
306 ] {
307 if value.ends_with(s) {
308 return suffix;
309 }
310 }
311 IntSuffix::None
312 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700313
314 pub fn span(&self) -> Span {
315 self.token.span()
316 }
317
318 pub fn set_span(&mut self, span: Span) {
319 self.token.set_span(span)
320 }
David Tolnay360efd22018-01-04 23:35:26 -0800321}
322
323impl LitFloat {
324 pub fn new(value: f64, suffix: FloatSuffix, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700325 let mut token = match suffix {
326 FloatSuffix::F32 => Literal::f32_suffixed(value as f32),
327 FloatSuffix::F64 => Literal::f64_suffixed(value),
328 FloatSuffix::None => Literal::f64_unsuffixed(value),
329 };
330 token.set_span(span);
331 LitFloat { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800332 }
333
334 pub fn value(&self) -> f64 {
335 value::parse_lit_float(&self.token.to_string())
336 }
337
338 pub fn suffix(&self) -> FloatSuffix {
339 let value = self.token.to_string();
David Tolnay61037c62018-01-05 16:21:03 -0800340 for (s, suffix) in vec![("f32", FloatSuffix::F32), ("f64", FloatSuffix::F64)] {
David Tolnay360efd22018-01-04 23:35:26 -0800341 if value.ends_with(s) {
342 return suffix;
343 }
344 }
345 FloatSuffix::None
346 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700347
348 pub fn span(&self) -> Span {
349 self.token.span()
350 }
351
352 pub fn set_span(&mut self, span: Span) {
353 self.token.set_span(span)
354 }
David Tolnay360efd22018-01-04 23:35:26 -0800355}
356
357macro_rules! lit_extra_traits {
358 ($ty:ident, $field:ident) => {
359 #[cfg(feature = "extra-traits")]
360 impl Eq for $ty {}
361
362 #[cfg(feature = "extra-traits")]
363 impl PartialEq for $ty {
364 fn eq(&self, other: &Self) -> bool {
365 self.$field.to_string() == other.$field.to_string()
366 }
367 }
368
369 #[cfg(feature = "extra-traits")]
370 impl Hash for $ty {
371 fn hash<H>(&self, state: &mut H)
372 where
373 H: Hasher,
374 {
375 self.$field.to_string().hash(state);
376 }
David Tolnay9c76bcb2017-12-26 23:14:59 -0500377 }
David Tolnay6a170ce2018-08-26 22:29:24 -0700378
379 #[cfg(feature = "parsing")]
380 #[doc(hidden)]
381 #[allow(non_snake_case)]
382 pub fn $ty(marker: lookahead::TokenMarker) -> $ty {
383 match marker {}
384 }
David Tolnay94d2b792018-04-29 12:26:10 -0700385 };
David Tolnayf4bbbd92016-09-23 14:41:55 -0700386}
387
Alex Crichton9a4dca22018-03-28 06:32:19 -0700388impl LitVerbatim {
389 pub fn span(&self) -> Span {
390 self.token.span()
391 }
392
393 pub fn set_span(&mut self, span: Span) {
394 self.token.set_span(span)
395 }
396}
397
David Tolnay360efd22018-01-04 23:35:26 -0800398lit_extra_traits!(LitStr, token);
399lit_extra_traits!(LitByteStr, token);
400lit_extra_traits!(LitByte, token);
401lit_extra_traits!(LitChar, token);
402lit_extra_traits!(LitInt, token);
403lit_extra_traits!(LitFloat, token);
404lit_extra_traits!(LitBool, value);
405lit_extra_traits!(LitVerbatim, token);
406
407ast_enum! {
David Tolnay05658502018-01-07 09:56:37 -0800408 /// The style of a string literal, either plain quoted or a raw string like
David Tolnayabf5c2e2018-01-06 23:30:04 -0800409 /// `r##"data"##`.
David Tolnay461d98e2018-01-07 11:07:19 -0800410 ///
411 /// *This type is available if Syn is built with the `"derive"` or `"full"`
412 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800413 pub enum StrStyle #no_visit {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800414 /// An ordinary string like `"data"`.
David Tolnay360efd22018-01-04 23:35:26 -0800415 Cooked,
David Tolnayabf5c2e2018-01-06 23:30:04 -0800416 /// A raw string like `r##"data"##`.
David Tolnay360efd22018-01-04 23:35:26 -0800417 ///
418 /// The unsigned integer is the number of `#` symbols used.
419 Raw(usize),
Alex Crichton62a0a592017-05-22 13:58:53 -0700420 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700421}
422
David Tolnay360efd22018-01-04 23:35:26 -0800423ast_enum! {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800424 /// The suffix on an integer literal if any, like the `u8` in `127u8`.
David Tolnay461d98e2018-01-07 11:07:19 -0800425 ///
426 /// *This type is available if Syn is built with the `"derive"` or `"full"`
427 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800428 pub enum IntSuffix #no_visit {
429 I8,
430 I16,
431 I32,
432 I64,
433 I128,
434 Isize,
435 U8,
436 U16,
437 U32,
438 U64,
439 U128,
440 Usize,
441 None,
Pascal Hertleif36342c52016-10-19 10:31:42 +0200442 }
443}
444
David Tolnay360efd22018-01-04 23:35:26 -0800445ast_enum! {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800446 /// The suffix on a floating point literal if any, like the `f32` in
447 /// `1.0f32`.
David Tolnay461d98e2018-01-07 11:07:19 -0800448 ///
449 /// *This type is available if Syn is built with the `"derive"` or `"full"`
450 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800451 pub enum FloatSuffix #no_visit {
452 F32,
453 F64,
454 None,
Alex Crichton2e0229c2017-05-23 09:34:50 -0700455 }
David Tolnay5fe14fc2017-01-27 16:22:08 -0800456}
457
458#[cfg(feature = "parsing")]
David Tolnay4fb71232018-08-25 23:14:50 -0400459#[doc(hidden)]
460#[allow(non_snake_case)]
461pub fn Lit(marker: lookahead::TokenMarker) -> Lit {
462 match marker {}
463}
464
465#[cfg(feature = "parsing")]
David Tolnayf4bbbd92016-09-23 14:41:55 -0700466pub mod parsing {
467 use super::*;
David Tolnay4fb71232018-08-25 23:14:50 -0400468 use parse::{Parse, ParseStream, Result};
David Tolnayf4bbbd92016-09-23 14:41:55 -0700469
David Tolnay4fb71232018-08-25 23:14:50 -0400470 impl Parse for Lit {
471 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay924e0af2018-09-01 13:07:34 -0700472 input.step(|cursor| {
473 if let Some((lit, rest)) = cursor.literal() {
474 return Ok((Lit::new(lit), rest));
475 }
476 while let Some((ident, rest)) = cursor.ident() {
477 let value = if ident == "true" {
478 true
479 } else if ident == "false" {
480 false
481 } else {
482 break;
483 };
484 let lit_bool = LitBool {
485 value: value,
486 span: ident.span(),
487 };
488 return Ok((Lit::Bool(lit_bool), rest));
489 }
490 Err(cursor.error("expected literal"))
David Tolnay4fb71232018-08-25 23:14:50 -0400491 })
Sergio Benitez5680d6a2017-12-29 11:20:29 -0800492 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700493 }
David Tolnay360efd22018-01-04 23:35:26 -0800494
David Tolnaya7d69fc2018-08-26 13:30:24 -0400495 impl Parse for LitStr {
496 fn parse(input: ParseStream) -> Result<Self> {
497 let head = input.fork();
498 match input.parse()? {
499 Lit::Str(lit) => Ok(lit),
500 _ => Err(head.error("expected string literal")),
501 }
502 }
503 }
David Tolnay360efd22018-01-04 23:35:26 -0800504
David Tolnaya7d69fc2018-08-26 13:30:24 -0400505 impl Parse for LitByteStr {
506 fn parse(input: ParseStream) -> Result<Self> {
507 let head = input.fork();
508 match input.parse()? {
509 Lit::ByteStr(lit) => Ok(lit),
510 _ => Err(head.error("expected byte string literal")),
511 }
512 }
513 }
David Tolnay360efd22018-01-04 23:35:26 -0800514
David Tolnaya7d69fc2018-08-26 13:30:24 -0400515 impl Parse for LitByte {
516 fn parse(input: ParseStream) -> Result<Self> {
517 let head = input.fork();
518 match input.parse()? {
519 Lit::Byte(lit) => Ok(lit),
520 _ => Err(head.error("expected byte literal")),
521 }
522 }
523 }
David Tolnay360efd22018-01-04 23:35:26 -0800524
David Tolnaya7d69fc2018-08-26 13:30:24 -0400525 impl Parse for LitChar {
526 fn parse(input: ParseStream) -> Result<Self> {
527 let head = input.fork();
528 match input.parse()? {
529 Lit::Char(lit) => Ok(lit),
530 _ => Err(head.error("expected character literal")),
531 }
532 }
533 }
David Tolnay360efd22018-01-04 23:35:26 -0800534
David Tolnaya7d69fc2018-08-26 13:30:24 -0400535 impl Parse for LitInt {
536 fn parse(input: ParseStream) -> Result<Self> {
537 let head = input.fork();
538 match input.parse()? {
539 Lit::Int(lit) => Ok(lit),
540 _ => Err(head.error("expected integer literal")),
541 }
542 }
543 }
David Tolnay360efd22018-01-04 23:35:26 -0800544
David Tolnaya7d69fc2018-08-26 13:30:24 -0400545 impl Parse for LitFloat {
546 fn parse(input: ParseStream) -> Result<Self> {
547 let head = input.fork();
548 match input.parse()? {
549 Lit::Float(lit) => Ok(lit),
550 _ => Err(head.error("expected floating point literal")),
551 }
552 }
553 }
David Tolnay360efd22018-01-04 23:35:26 -0800554
David Tolnaya7d69fc2018-08-26 13:30:24 -0400555 impl Parse for LitBool {
556 fn parse(input: ParseStream) -> Result<Self> {
557 let head = input.fork();
558 match input.parse()? {
559 Lit::Bool(lit) => Ok(lit),
560 _ => Err(head.error("expected boolean literal")),
561 }
562 }
563 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700564}
565
566#[cfg(feature = "printing")]
567mod printing {
568 use super::*;
Alex Crichtona74a1c82018-05-16 10:20:44 -0700569 use proc_macro2::TokenStream;
David Tolnay65fb5662018-05-20 20:02:28 -0700570 use quote::{ToTokens, TokenStreamExt};
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700571
David Tolnay360efd22018-01-04 23:35:26 -0800572 impl ToTokens for LitStr {
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 LitByteStr {
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 LitByte {
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 LitChar {
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 LitInt {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700597 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700598 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800599 }
600 }
601
602 impl ToTokens for LitFloat {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700603 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700604 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800605 }
606 }
607
608 impl ToTokens for LitBool {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700609 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700610 let s = if self.value { "true" } else { "false" };
Alex Crichtona74a1c82018-05-16 10:20:44 -0700611 tokens.append(Ident::new(s, self.span));
David Tolnay360efd22018-01-04 23:35:26 -0800612 }
613 }
614
615 impl ToTokens for LitVerbatim {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700616 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700617 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800618 }
619 }
620}
621
622mod value {
623 use super::*;
David Tolnay94d2b792018-04-29 12:26:10 -0700624 use proc_macro2::TokenStream;
David Tolnay360efd22018-01-04 23:35:26 -0800625 use std::char;
626 use std::ops::{Index, RangeFrom};
David Tolnay360efd22018-01-04 23:35:26 -0800627
David Tolnay7d1d1282018-01-06 16:10:51 -0800628 impl Lit {
David Tolnay780292d2018-01-22 23:26:44 -0800629 /// Interpret a Syn literal from a proc-macro2 literal.
630 ///
631 /// Not all proc-macro2 literals are valid Syn literals. In particular,
632 /// doc comments are considered by proc-macro2 to be literals but in Syn
633 /// they are [`Attribute`].
634 ///
635 /// [`Attribute`]: struct.Attribute.html
636 ///
637 /// # Panics
638 ///
639 /// Panics if the input is a doc comment literal.
Alex Crichton9a4dca22018-03-28 06:32:19 -0700640 pub fn new(token: Literal) -> Self {
David Tolnay7d1d1282018-01-06 16:10:51 -0800641 let value = token.to_string();
642
643 match value::byte(&value, 0) {
David Tolnay94d2b792018-04-29 12:26:10 -0700644 b'"' | b'r' => return Lit::Str(LitStr { token: token }),
David Tolnay7d1d1282018-01-06 16:10:51 -0800645 b'b' => match value::byte(&value, 1) {
David Tolnay94d2b792018-04-29 12:26:10 -0700646 b'"' | b'r' => return Lit::ByteStr(LitByteStr { token: token }),
647 b'\'' => return Lit::Byte(LitByte { token: token }),
David Tolnay7d1d1282018-01-06 16:10:51 -0800648 _ => {}
649 },
David Tolnay94d2b792018-04-29 12:26:10 -0700650 b'\'' => return Lit::Char(LitChar { token: token }),
David Tolnayfb84fc02018-10-02 21:01:30 -0700651 b'0'...b'9' => {
652 if number_is_int(&value) {
653 return Lit::Int(LitInt { token: token });
654 } else if number_is_float(&value) {
655 return Lit::Float(LitFloat { token: token });
656 } else {
657 // number overflow
658 return Lit::Verbatim(LitVerbatim { token: token });
659 }
660 }
661 _ => {
662 if value == "true" || value == "false" {
663 return Lit::Bool(LitBool {
664 value: value == "true",
665 span: token.span(),
666 });
667 }
668 }
David Tolnay7d1d1282018-01-06 16:10:51 -0800669 }
670
671 panic!("Unrecognized literal: {}", value);
672 }
673 }
674
675 fn number_is_int(value: &str) -> bool {
676 if number_is_float(value) {
677 false
678 } else {
679 value::parse_lit_int(value).is_some()
680 }
681 }
682
683 fn number_is_float(value: &str) -> bool {
684 if value.contains('.') {
685 true
686 } else if value.starts_with("0x") || value.ends_with("size") {
687 false
688 } else {
689 value.contains('e') || value.contains('E')
690 }
691 }
692
David Tolnay360efd22018-01-04 23:35:26 -0800693 /// Get the byte at offset idx, or a default of `b'\0'` if we're looking
694 /// past the end of the input buffer.
695 pub fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 {
696 let s = s.as_ref();
697 if idx < s.len() {
698 s[idx]
699 } else {
700 0
701 }
702 }
703
704 fn next_chr(s: &str) -> char {
705 s.chars().next().unwrap_or('\0')
706 }
707
708 pub fn parse_lit_str(s: &str) -> String {
709 match byte(s, 0) {
710 b'"' => parse_lit_str_cooked(s),
711 b'r' => parse_lit_str_raw(s),
712 _ => unreachable!(),
713 }
714 }
715
David Tolnay76ebcdd2018-01-05 17:07:26 -0800716 // Clippy false positive
717 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
718 #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))]
David Tolnay360efd22018-01-04 23:35:26 -0800719 fn parse_lit_str_cooked(mut s: &str) -> String {
720 assert_eq!(byte(s, 0), b'"');
721 s = &s[1..];
722
723 let mut out = String::new();
724 'outer: loop {
725 let ch = match byte(s, 0) {
726 b'"' => break,
727 b'\\' => {
728 let b = byte(s, 1);
729 s = &s[2..];
730 match b {
731 b'x' => {
732 let (byte, rest) = backslash_x(s);
733 s = rest;
734 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
David Tolnay76ebcdd2018-01-05 17:07:26 -0800735 char::from_u32(u32::from(byte)).unwrap()
David Tolnay360efd22018-01-04 23:35:26 -0800736 }
737 b'u' => {
David Tolnay76ebcdd2018-01-05 17:07:26 -0800738 let (chr, rest) = backslash_u(s);
David Tolnay360efd22018-01-04 23:35:26 -0800739 s = rest;
740 chr
741 }
742 b'n' => '\n',
743 b'r' => '\r',
744 b't' => '\t',
745 b'\\' => '\\',
746 b'0' => '\0',
747 b'\'' => '\'',
748 b'"' => '"',
David Tolnay61037c62018-01-05 16:21:03 -0800749 b'\r' | b'\n' => loop {
750 let ch = next_chr(s);
751 if ch.is_whitespace() {
752 s = &s[ch.len_utf8()..];
753 } else {
754 continue 'outer;
David Tolnay360efd22018-01-04 23:35:26 -0800755 }
David Tolnay61037c62018-01-05 16:21:03 -0800756 },
757 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800758 }
759 }
760 b'\r' => {
761 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
762 s = &s[2..];
763 '\n'
764 }
765 _ => {
766 let ch = next_chr(s);
767 s = &s[ch.len_utf8()..];
768 ch
769 }
770 };
771 out.push(ch);
772 }
773
774 assert_eq!(s, "\"");
775 out
776 }
777
778 fn parse_lit_str_raw(mut s: &str) -> String {
779 assert_eq!(byte(s, 0), b'r');
780 s = &s[1..];
781
782 let mut pounds = 0;
783 while byte(s, pounds) == b'#' {
784 pounds += 1;
785 }
786 assert_eq!(byte(s, pounds), b'"');
787 assert_eq!(byte(s, s.len() - pounds - 1), b'"');
788 for end in s[s.len() - pounds..].bytes() {
789 assert_eq!(end, b'#');
790 }
791
792 s[pounds + 1..s.len() - pounds - 1].to_owned()
793 }
794
795 pub fn parse_lit_byte_str(s: &str) -> Vec<u8> {
796 assert_eq!(byte(s, 0), b'b');
797 match byte(s, 1) {
798 b'"' => parse_lit_byte_str_cooked(s),
799 b'r' => parse_lit_byte_str_raw(s),
800 _ => unreachable!(),
801 }
802 }
803
David Tolnay76ebcdd2018-01-05 17:07:26 -0800804 // Clippy false positive
805 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
806 #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))]
David Tolnay360efd22018-01-04 23:35:26 -0800807 fn parse_lit_byte_str_cooked(mut s: &str) -> Vec<u8> {
808 assert_eq!(byte(s, 0), b'b');
809 assert_eq!(byte(s, 1), b'"');
810 s = &s[2..];
811
812 // We're going to want to have slices which don't respect codepoint boundaries.
813 let mut s = s.as_bytes();
814
815 let mut out = Vec::new();
816 'outer: loop {
817 let byte = match byte(s, 0) {
818 b'"' => break,
819 b'\\' => {
820 let b = byte(s, 1);
821 s = &s[2..];
822 match b {
823 b'x' => {
824 let (b, rest) = backslash_x(s);
825 s = rest;
826 b
827 }
828 b'n' => b'\n',
829 b'r' => b'\r',
830 b't' => b'\t',
831 b'\\' => b'\\',
832 b'0' => b'\0',
833 b'\'' => b'\'',
834 b'"' => b'"',
David Tolnay61037c62018-01-05 16:21:03 -0800835 b'\r' | b'\n' => loop {
836 let byte = byte(s, 0);
David Tolnay76ebcdd2018-01-05 17:07:26 -0800837 let ch = char::from_u32(u32::from(byte)).unwrap();
David Tolnay61037c62018-01-05 16:21:03 -0800838 if ch.is_whitespace() {
839 s = &s[1..];
840 } else {
841 continue 'outer;
David Tolnay360efd22018-01-04 23:35:26 -0800842 }
David Tolnay61037c62018-01-05 16:21:03 -0800843 },
844 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800845 }
846 }
847 b'\r' => {
848 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
849 s = &s[2..];
850 b'\n'
851 }
852 b => {
853 s = &s[1..];
854 b
855 }
856 };
857 out.push(byte);
858 }
859
860 assert_eq!(s, b"\"");
861 out
862 }
863
864 fn parse_lit_byte_str_raw(s: &str) -> Vec<u8> {
865 assert_eq!(byte(s, 0), b'b');
866 parse_lit_str_raw(&s[1..]).into_bytes()
867 }
868
869 pub fn parse_lit_byte(s: &str) -> u8 {
870 assert_eq!(byte(s, 0), b'b');
871 assert_eq!(byte(s, 1), b'\'');
872
873 // We're going to want to have slices which don't respect codepoint boundaries.
874 let mut s = s[2..].as_bytes();
875
876 let b = match byte(s, 0) {
877 b'\\' => {
878 let b = byte(s, 1);
879 s = &s[2..];
880 match b {
881 b'x' => {
882 let (b, rest) = backslash_x(s);
883 s = rest;
884 b
885 }
886 b'n' => b'\n',
887 b'r' => b'\r',
888 b't' => b'\t',
889 b'\\' => b'\\',
890 b'0' => b'\0',
891 b'\'' => b'\'',
892 b'"' => b'"',
David Tolnay61037c62018-01-05 16:21:03 -0800893 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800894 }
895 }
896 b => {
897 s = &s[1..];
898 b
899 }
900 };
901
902 assert_eq!(byte(s, 0), b'\'');
903 b
904 }
905
906 pub fn parse_lit_char(mut s: &str) -> char {
907 assert_eq!(byte(s, 0), b'\'');
908 s = &s[1..];
909
910 let ch = match byte(s, 0) {
911 b'\\' => {
912 let b = byte(s, 1);
913 s = &s[2..];
914 match b {
915 b'x' => {
916 let (byte, rest) = backslash_x(s);
917 s = rest;
918 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
David Tolnay76ebcdd2018-01-05 17:07:26 -0800919 char::from_u32(u32::from(byte)).unwrap()
David Tolnay360efd22018-01-04 23:35:26 -0800920 }
921 b'u' => {
922 let (chr, rest) = backslash_u(s);
923 s = rest;
924 chr
925 }
926 b'n' => '\n',
927 b'r' => '\r',
928 b't' => '\t',
929 b'\\' => '\\',
930 b'0' => '\0',
931 b'\'' => '\'',
932 b'"' => '"',
David Tolnay61037c62018-01-05 16:21:03 -0800933 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800934 }
935 }
936 _ => {
937 let ch = next_chr(s);
938 s = &s[ch.len_utf8()..];
939 ch
940 }
941 };
942 assert_eq!(s, "\'", "Expected end of char literal");
943 ch
944 }
945
946 fn backslash_x<S>(s: &S) -> (u8, &S)
David Tolnay61037c62018-01-05 16:21:03 -0800947 where
948 S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
David Tolnay360efd22018-01-04 23:35:26 -0800949 {
950 let mut ch = 0;
951 let b0 = byte(s, 0);
952 let b1 = byte(s, 1);
David Tolnaye614f282018-10-27 22:50:12 -0700953 ch += 0x10
954 * match b0 {
955 b'0'...b'9' => b0 - b'0',
956 b'a'...b'f' => 10 + (b0 - b'a'),
957 b'A'...b'F' => 10 + (b0 - b'A'),
958 _ => panic!("unexpected non-hex character after \\x"),
959 };
David Tolnay76ebcdd2018-01-05 17:07:26 -0800960 ch += match b1 {
David Tolnay360efd22018-01-04 23:35:26 -0800961 b'0'...b'9' => b1 - b'0',
962 b'a'...b'f' => 10 + (b1 - b'a'),
963 b'A'...b'F' => 10 + (b1 - b'A'),
964 _ => panic!("unexpected non-hex character after \\x"),
965 };
966 (ch, &s[2..])
967 }
968
969 fn backslash_u(mut s: &str) -> (char, &str) {
970 if byte(s, 0) != b'{' {
971 panic!("expected {{ after \\u");
972 }
973 s = &s[1..];
974
975 let mut ch = 0;
976 for _ in 0..6 {
977 let b = byte(s, 0);
978 match b {
979 b'0'...b'9' => {
980 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800981 ch += u32::from(b - b'0');
David Tolnay360efd22018-01-04 23:35:26 -0800982 s = &s[1..];
983 }
984 b'a'...b'f' => {
985 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800986 ch += u32::from(10 + b - b'a');
David Tolnay360efd22018-01-04 23:35:26 -0800987 s = &s[1..];
988 }
989 b'A'...b'F' => {
990 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800991 ch += u32::from(10 + b - b'A');
David Tolnay360efd22018-01-04 23:35:26 -0800992 s = &s[1..];
993 }
994 b'}' => break,
995 _ => panic!("unexpected non-hex character after \\u"),
996 }
997 }
998 assert!(byte(s, 0) == b'}');
999 s = &s[1..];
1000
1001 if let Some(ch) = char::from_u32(ch) {
1002 (ch, s)
1003 } else {
1004 panic!("character code {:x} is not a valid unicode character", ch);
1005 }
1006 }
1007
1008 pub fn parse_lit_int(mut s: &str) -> Option<u64> {
1009 let base = match (byte(s, 0), byte(s, 1)) {
1010 (b'0', b'x') => {
1011 s = &s[2..];
1012 16
1013 }
1014 (b'0', b'o') => {
1015 s = &s[2..];
1016 8
1017 }
1018 (b'0', b'b') => {
1019 s = &s[2..];
1020 2
1021 }
1022 (b'0'...b'9', _) => 10,
1023 _ => unreachable!(),
1024 };
1025
1026 let mut value = 0u64;
1027 loop {
1028 let b = byte(s, 0);
1029 let digit = match b {
David Tolnay76ebcdd2018-01-05 17:07:26 -08001030 b'0'...b'9' => u64::from(b - b'0'),
1031 b'a'...b'f' if base > 10 => 10 + u64::from(b - b'a'),
1032 b'A'...b'F' if base > 10 => 10 + u64::from(b - b'A'),
David Tolnay360efd22018-01-04 23:35:26 -08001033 b'_' => {
1034 s = &s[1..];
1035 continue;
1036 }
1037 // NOTE: Looking at a floating point literal, we don't want to
1038 // consider these integers.
1039 b'.' if base == 10 => return None,
1040 b'e' | b'E' if base == 10 => return None,
1041 _ => break,
1042 };
1043
1044 if digit >= base {
1045 panic!("Unexpected digit {:x} out of base range", digit);
1046 }
1047
1048 value = match value.checked_mul(base) {
1049 Some(value) => value,
1050 None => return None,
1051 };
1052 value = match value.checked_add(digit) {
1053 Some(value) => value,
1054 None => return None,
1055 };
1056 s = &s[1..];
1057 }
1058
1059 Some(value)
1060 }
1061
1062 pub fn parse_lit_float(input: &str) -> f64 {
1063 // Rust's floating point literals are very similar to the ones parsed by
1064 // the standard library, except that rust's literals can contain
1065 // ignorable underscores. Let's remove those underscores.
1066 let mut bytes = input.to_owned().into_bytes();
1067 let mut write = 0;
1068 for read in 0..bytes.len() {
1069 if bytes[read] == b'_' {
1070 continue; // Don't increase write
David Tolnay76ebcdd2018-01-05 17:07:26 -08001071 }
1072 if write != read {
David Tolnay360efd22018-01-04 23:35:26 -08001073 let x = bytes[read];
1074 bytes[write] = x;
1075 }
1076 write += 1;
1077 }
1078 bytes.truncate(write);
1079 let input = String::from_utf8(bytes).unwrap();
David Tolnay76ebcdd2018-01-05 17:07:26 -08001080 let end = input.find('f').unwrap_or_else(|| input.len());
David Tolnay360efd22018-01-04 23:35:26 -08001081 input[..end].parse().unwrap()
1082 }
1083
1084 pub fn to_literal(s: &str) -> Literal {
1085 let stream = s.parse::<TokenStream>().unwrap();
Alex Crichton9a4dca22018-03-28 06:32:19 -07001086 match stream.into_iter().next().unwrap() {
1087 TokenTree::Literal(l) => l,
David Tolnay360efd22018-01-04 23:35:26 -08001088 _ => unreachable!(),
David Tolnayf17fd2f2016-10-07 23:38:08 -07001089 }
1090 }
David Tolnayf4bbbd92016-09-23 14:41:55 -07001091}