blob: 206e319bd0117df669751f1312d597b26cefbace [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 /// //
144 /// // or returns the path `Self` as a default if the attribute is not of
145 /// // that form.
146 /// fn get_path(attr: &Attribute) -> Result<Path> {
147 /// let default = || Path::from(Ident::new("Self", Span::call_site()));
148 ///
149 /// let meta = match attr.interpret_meta() {
150 /// Some(meta) => meta,
151 /// None => return Ok(default()),
152 /// };
153 ///
154 /// if meta.name() != "path" {
155 /// return Ok(default());
156 /// }
157 ///
158 /// match meta {
159 /// Meta::NameValue(MetaNameValue { lit: Lit::Str(lit_str), .. }) => {
160 /// lit_str.parse()
161 /// }
162 /// _ => {
163 /// let error_span = attr.bracket_token.span;
164 /// let message = "expected #[path = \"...\"]";
165 /// Err(Error::new(error_span, message))
166 /// }
167 /// }
168 /// }
169 /// ```
David Tolnayd53ac2b2018-01-27 19:00:06 -0800170 #[cfg(feature = "parsing")]
David Tolnaye82a2b12018-08-30 16:31:10 -0700171 pub fn parse<T: Parse>(&self) -> Result<T, Error> {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700172 use proc_macro2::Group;
173
David Tolnayd53ac2b2018-01-27 19:00:06 -0800174 // Parse string literal into a token stream with every span equal to the
175 // original literal's span.
David Tolnayad4b2472018-08-25 08:25:24 -0400176 fn spanned_tokens(s: &LitStr) -> Result<TokenStream, Error> {
David Tolnayd53ac2b2018-01-27 19:00:06 -0800177 let stream = ::parse_str(&s.value())?;
Alex Crichton9a4dca22018-03-28 06:32:19 -0700178 Ok(respan_token_stream(stream, s.span()))
David Tolnayd53ac2b2018-01-27 19:00:06 -0800179 }
180
181 // Token stream with every span replaced by the given one.
182 fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
David Tolnay94d2b792018-04-29 12:26:10 -0700183 stream
184 .into_iter()
185 .map(|token| respan_token_tree(token, span))
186 .collect()
David Tolnayd53ac2b2018-01-27 19:00:06 -0800187 }
188
189 // Token tree with every span replaced by the given one.
Alex Crichton9a4dca22018-03-28 06:32:19 -0700190 fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
191 match token {
192 TokenTree::Group(ref mut g) => {
193 let stream = respan_token_stream(g.stream().clone(), span);
194 *g = Group::new(g.delimiter(), stream);
195 g.set_span(span);
196 }
197 ref mut other => other.set_span(span),
David Tolnayd53ac2b2018-01-27 19:00:06 -0800198 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700199 token
David Tolnayd53ac2b2018-01-27 19:00:06 -0800200 }
201
202 spanned_tokens(self).and_then(::parse2)
203 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700204
205 pub fn span(&self) -> Span {
206 self.token.span()
207 }
208
209 pub fn set_span(&mut self, span: Span) {
210 self.token.set_span(span)
211 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700212}
213
David Tolnay360efd22018-01-04 23:35:26 -0800214impl LitByteStr {
215 pub fn new(value: &[u8], span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700216 let mut token = Literal::byte_string(value);
217 token.set_span(span);
218 LitByteStr { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800219 }
220
221 pub fn value(&self) -> Vec<u8> {
222 value::parse_lit_byte_str(&self.token.to_string())
223 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700224
225 pub fn span(&self) -> Span {
226 self.token.span()
227 }
228
229 pub fn set_span(&mut self, span: Span) {
230 self.token.set_span(span)
231 }
David Tolnay360efd22018-01-04 23:35:26 -0800232}
233
234impl LitByte {
235 pub fn new(value: u8, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700236 let mut token = Literal::u8_suffixed(value);
237 token.set_span(span);
238 LitByte { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800239 }
240
241 pub fn value(&self) -> u8 {
242 value::parse_lit_byte(&self.token.to_string())
243 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700244
245 pub fn span(&self) -> Span {
246 self.token.span()
247 }
248
249 pub fn set_span(&mut self, span: Span) {
250 self.token.set_span(span)
251 }
David Tolnay360efd22018-01-04 23:35:26 -0800252}
253
254impl LitChar {
255 pub fn new(value: char, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700256 let mut token = Literal::character(value);
257 token.set_span(span);
258 LitChar { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800259 }
260
261 pub fn value(&self) -> char {
262 value::parse_lit_char(&self.token.to_string())
263 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700264
265 pub fn span(&self) -> Span {
266 self.token.span()
267 }
268
269 pub fn set_span(&mut self, span: Span) {
270 self.token.set_span(span)
271 }
David Tolnay360efd22018-01-04 23:35:26 -0800272}
273
274impl LitInt {
275 pub fn new(value: u64, suffix: IntSuffix, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700276 let mut token = match suffix {
277 IntSuffix::Isize => Literal::isize_suffixed(value as isize),
278 IntSuffix::I8 => Literal::i8_suffixed(value as i8),
279 IntSuffix::I16 => Literal::i16_suffixed(value as i16),
280 IntSuffix::I32 => Literal::i32_suffixed(value as i32),
281 IntSuffix::I64 => Literal::i64_suffixed(value as i64),
282 IntSuffix::I128 => value::to_literal(&format!("{}i128", value)),
283 IntSuffix::Usize => Literal::usize_suffixed(value as usize),
284 IntSuffix::U8 => Literal::u8_suffixed(value as u8),
285 IntSuffix::U16 => Literal::u16_suffixed(value as u16),
286 IntSuffix::U32 => Literal::u32_suffixed(value as u32),
287 IntSuffix::U64 => Literal::u64_suffixed(value),
288 IntSuffix::U128 => value::to_literal(&format!("{}u128", value)),
289 IntSuffix::None => Literal::u64_unsuffixed(value),
290 };
291 token.set_span(span);
292 LitInt { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800293 }
294
295 pub fn value(&self) -> u64 {
296 value::parse_lit_int(&self.token.to_string()).unwrap()
297 }
298
299 pub fn suffix(&self) -> IntSuffix {
300 let value = self.token.to_string();
301 for (s, suffix) in vec![
302 ("i8", IntSuffix::I8),
303 ("i16", IntSuffix::I16),
304 ("i32", IntSuffix::I32),
305 ("i64", IntSuffix::I64),
306 ("i128", IntSuffix::I128),
307 ("isize", IntSuffix::Isize),
308 ("u8", IntSuffix::U8),
309 ("u16", IntSuffix::U16),
310 ("u32", IntSuffix::U32),
311 ("u64", IntSuffix::U64),
312 ("u128", IntSuffix::U128),
313 ("usize", IntSuffix::Usize),
314 ] {
315 if value.ends_with(s) {
316 return suffix;
317 }
318 }
319 IntSuffix::None
320 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700321
322 pub fn span(&self) -> Span {
323 self.token.span()
324 }
325
326 pub fn set_span(&mut self, span: Span) {
327 self.token.set_span(span)
328 }
David Tolnay360efd22018-01-04 23:35:26 -0800329}
330
331impl LitFloat {
332 pub fn new(value: f64, suffix: FloatSuffix, span: Span) -> Self {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700333 let mut token = match suffix {
334 FloatSuffix::F32 => Literal::f32_suffixed(value as f32),
335 FloatSuffix::F64 => Literal::f64_suffixed(value),
336 FloatSuffix::None => Literal::f64_unsuffixed(value),
337 };
338 token.set_span(span);
339 LitFloat { token: token }
David Tolnay360efd22018-01-04 23:35:26 -0800340 }
341
342 pub fn value(&self) -> f64 {
343 value::parse_lit_float(&self.token.to_string())
344 }
345
346 pub fn suffix(&self) -> FloatSuffix {
347 let value = self.token.to_string();
David Tolnay61037c62018-01-05 16:21:03 -0800348 for (s, suffix) in vec![("f32", FloatSuffix::F32), ("f64", FloatSuffix::F64)] {
David Tolnay360efd22018-01-04 23:35:26 -0800349 if value.ends_with(s) {
350 return suffix;
351 }
352 }
353 FloatSuffix::None
354 }
Alex Crichton9a4dca22018-03-28 06:32:19 -0700355
356 pub fn span(&self) -> Span {
357 self.token.span()
358 }
359
360 pub fn set_span(&mut self, span: Span) {
361 self.token.set_span(span)
362 }
David Tolnay360efd22018-01-04 23:35:26 -0800363}
364
365macro_rules! lit_extra_traits {
366 ($ty:ident, $field:ident) => {
367 #[cfg(feature = "extra-traits")]
368 impl Eq for $ty {}
369
370 #[cfg(feature = "extra-traits")]
371 impl PartialEq for $ty {
372 fn eq(&self, other: &Self) -> bool {
373 self.$field.to_string() == other.$field.to_string()
374 }
375 }
376
377 #[cfg(feature = "extra-traits")]
378 impl Hash for $ty {
379 fn hash<H>(&self, state: &mut H)
380 where
381 H: Hasher,
382 {
383 self.$field.to_string().hash(state);
384 }
David Tolnay9c76bcb2017-12-26 23:14:59 -0500385 }
David Tolnay6a170ce2018-08-26 22:29:24 -0700386
387 #[cfg(feature = "parsing")]
388 #[doc(hidden)]
389 #[allow(non_snake_case)]
390 pub fn $ty(marker: lookahead::TokenMarker) -> $ty {
391 match marker {}
392 }
David Tolnay94d2b792018-04-29 12:26:10 -0700393 };
David Tolnayf4bbbd92016-09-23 14:41:55 -0700394}
395
Alex Crichton9a4dca22018-03-28 06:32:19 -0700396impl LitVerbatim {
397 pub fn span(&self) -> Span {
398 self.token.span()
399 }
400
401 pub fn set_span(&mut self, span: Span) {
402 self.token.set_span(span)
403 }
404}
405
David Tolnay360efd22018-01-04 23:35:26 -0800406lit_extra_traits!(LitStr, token);
407lit_extra_traits!(LitByteStr, token);
408lit_extra_traits!(LitByte, token);
409lit_extra_traits!(LitChar, token);
410lit_extra_traits!(LitInt, token);
411lit_extra_traits!(LitFloat, token);
412lit_extra_traits!(LitBool, value);
413lit_extra_traits!(LitVerbatim, token);
414
415ast_enum! {
David Tolnay05658502018-01-07 09:56:37 -0800416 /// The style of a string literal, either plain quoted or a raw string like
David Tolnayabf5c2e2018-01-06 23:30:04 -0800417 /// `r##"data"##`.
David Tolnay461d98e2018-01-07 11:07:19 -0800418 ///
419 /// *This type is available if Syn is built with the `"derive"` or `"full"`
420 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800421 pub enum StrStyle #no_visit {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800422 /// An ordinary string like `"data"`.
David Tolnay360efd22018-01-04 23:35:26 -0800423 Cooked,
David Tolnayabf5c2e2018-01-06 23:30:04 -0800424 /// A raw string like `r##"data"##`.
David Tolnay360efd22018-01-04 23:35:26 -0800425 ///
426 /// The unsigned integer is the number of `#` symbols used.
427 Raw(usize),
Alex Crichton62a0a592017-05-22 13:58:53 -0700428 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700429}
430
David Tolnay360efd22018-01-04 23:35:26 -0800431ast_enum! {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800432 /// The suffix on an integer literal if any, like the `u8` in `127u8`.
David Tolnay461d98e2018-01-07 11:07:19 -0800433 ///
434 /// *This type is available if Syn is built with the `"derive"` or `"full"`
435 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800436 pub enum IntSuffix #no_visit {
437 I8,
438 I16,
439 I32,
440 I64,
441 I128,
442 Isize,
443 U8,
444 U16,
445 U32,
446 U64,
447 U128,
448 Usize,
449 None,
Pascal Hertleif36342c52016-10-19 10:31:42 +0200450 }
451}
452
David Tolnay360efd22018-01-04 23:35:26 -0800453ast_enum! {
David Tolnayabf5c2e2018-01-06 23:30:04 -0800454 /// The suffix on a floating point literal if any, like the `f32` in
455 /// `1.0f32`.
David Tolnay461d98e2018-01-07 11:07:19 -0800456 ///
457 /// *This type is available if Syn is built with the `"derive"` or `"full"`
458 /// feature.*
David Tolnay360efd22018-01-04 23:35:26 -0800459 pub enum FloatSuffix #no_visit {
460 F32,
461 F64,
462 None,
Alex Crichton2e0229c2017-05-23 09:34:50 -0700463 }
David Tolnay5fe14fc2017-01-27 16:22:08 -0800464}
465
466#[cfg(feature = "parsing")]
David Tolnay4fb71232018-08-25 23:14:50 -0400467#[doc(hidden)]
468#[allow(non_snake_case)]
469pub fn Lit(marker: lookahead::TokenMarker) -> Lit {
470 match marker {}
471}
472
473#[cfg(feature = "parsing")]
David Tolnayf4bbbd92016-09-23 14:41:55 -0700474pub mod parsing {
475 use super::*;
David Tolnay4fb71232018-08-25 23:14:50 -0400476 use parse::{Parse, ParseStream, Result};
David Tolnayf4bbbd92016-09-23 14:41:55 -0700477
David Tolnay4fb71232018-08-25 23:14:50 -0400478 impl Parse for Lit {
479 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay924e0af2018-09-01 13:07:34 -0700480 input.step(|cursor| {
481 if let Some((lit, rest)) = cursor.literal() {
482 return Ok((Lit::new(lit), rest));
483 }
484 while let Some((ident, rest)) = cursor.ident() {
485 let value = if ident == "true" {
486 true
487 } else if ident == "false" {
488 false
489 } else {
490 break;
491 };
492 let lit_bool = LitBool {
493 value: value,
494 span: ident.span(),
495 };
496 return Ok((Lit::Bool(lit_bool), rest));
497 }
498 Err(cursor.error("expected literal"))
David Tolnay4fb71232018-08-25 23:14:50 -0400499 })
Sergio Benitez5680d6a2017-12-29 11:20:29 -0800500 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700501 }
David Tolnay360efd22018-01-04 23:35:26 -0800502
David Tolnaya7d69fc2018-08-26 13:30:24 -0400503 impl Parse for LitStr {
504 fn parse(input: ParseStream) -> Result<Self> {
505 let head = input.fork();
506 match input.parse()? {
507 Lit::Str(lit) => Ok(lit),
508 _ => Err(head.error("expected string literal")),
509 }
510 }
511 }
David Tolnay360efd22018-01-04 23:35:26 -0800512
David Tolnaya7d69fc2018-08-26 13:30:24 -0400513 impl Parse for LitByteStr {
514 fn parse(input: ParseStream) -> Result<Self> {
515 let head = input.fork();
516 match input.parse()? {
517 Lit::ByteStr(lit) => Ok(lit),
518 _ => Err(head.error("expected byte string literal")),
519 }
520 }
521 }
David Tolnay360efd22018-01-04 23:35:26 -0800522
David Tolnaya7d69fc2018-08-26 13:30:24 -0400523 impl Parse for LitByte {
524 fn parse(input: ParseStream) -> Result<Self> {
525 let head = input.fork();
526 match input.parse()? {
527 Lit::Byte(lit) => Ok(lit),
528 _ => Err(head.error("expected byte literal")),
529 }
530 }
531 }
David Tolnay360efd22018-01-04 23:35:26 -0800532
David Tolnaya7d69fc2018-08-26 13:30:24 -0400533 impl Parse for LitChar {
534 fn parse(input: ParseStream) -> Result<Self> {
535 let head = input.fork();
536 match input.parse()? {
537 Lit::Char(lit) => Ok(lit),
538 _ => Err(head.error("expected character literal")),
539 }
540 }
541 }
David Tolnay360efd22018-01-04 23:35:26 -0800542
David Tolnaya7d69fc2018-08-26 13:30:24 -0400543 impl Parse for LitInt {
544 fn parse(input: ParseStream) -> Result<Self> {
545 let head = input.fork();
546 match input.parse()? {
547 Lit::Int(lit) => Ok(lit),
548 _ => Err(head.error("expected integer literal")),
549 }
550 }
551 }
David Tolnay360efd22018-01-04 23:35:26 -0800552
David Tolnaya7d69fc2018-08-26 13:30:24 -0400553 impl Parse for LitFloat {
554 fn parse(input: ParseStream) -> Result<Self> {
555 let head = input.fork();
556 match input.parse()? {
557 Lit::Float(lit) => Ok(lit),
558 _ => Err(head.error("expected floating point literal")),
559 }
560 }
561 }
David Tolnay360efd22018-01-04 23:35:26 -0800562
David Tolnaya7d69fc2018-08-26 13:30:24 -0400563 impl Parse for LitBool {
564 fn parse(input: ParseStream) -> Result<Self> {
565 let head = input.fork();
566 match input.parse()? {
567 Lit::Bool(lit) => Ok(lit),
568 _ => Err(head.error("expected boolean literal")),
569 }
570 }
571 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700572}
573
574#[cfg(feature = "printing")]
575mod printing {
576 use super::*;
Alex Crichtona74a1c82018-05-16 10:20:44 -0700577 use proc_macro2::TokenStream;
David Tolnay65fb5662018-05-20 20:02:28 -0700578 use quote::{ToTokens, TokenStreamExt};
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700579
David Tolnay360efd22018-01-04 23:35:26 -0800580 impl ToTokens for LitStr {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700581 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700582 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800583 }
584 }
585
586 impl ToTokens for LitByteStr {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700587 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700588 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800589 }
590 }
591
592 impl ToTokens for LitByte {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700593 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700594 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800595 }
596 }
597
598 impl ToTokens for LitChar {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700599 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700600 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800601 }
602 }
603
604 impl ToTokens for LitInt {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700605 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700606 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800607 }
608 }
609
610 impl ToTokens for LitFloat {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700611 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700612 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800613 }
614 }
615
616 impl ToTokens for LitBool {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700617 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700618 let s = if self.value { "true" } else { "false" };
Alex Crichtona74a1c82018-05-16 10:20:44 -0700619 tokens.append(Ident::new(s, self.span));
David Tolnay360efd22018-01-04 23:35:26 -0800620 }
621 }
622
623 impl ToTokens for LitVerbatim {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700624 fn to_tokens(&self, tokens: &mut TokenStream) {
Alex Crichton9a4dca22018-03-28 06:32:19 -0700625 self.token.to_tokens(tokens);
David Tolnay360efd22018-01-04 23:35:26 -0800626 }
627 }
628}
629
630mod value {
631 use super::*;
David Tolnay94d2b792018-04-29 12:26:10 -0700632 use proc_macro2::TokenStream;
David Tolnay360efd22018-01-04 23:35:26 -0800633 use std::char;
634 use std::ops::{Index, RangeFrom};
David Tolnay360efd22018-01-04 23:35:26 -0800635
David Tolnay7d1d1282018-01-06 16:10:51 -0800636 impl Lit {
David Tolnay780292d2018-01-22 23:26:44 -0800637 /// Interpret a Syn literal from a proc-macro2 literal.
638 ///
639 /// Not all proc-macro2 literals are valid Syn literals. In particular,
640 /// doc comments are considered by proc-macro2 to be literals but in Syn
641 /// they are [`Attribute`].
642 ///
643 /// [`Attribute`]: struct.Attribute.html
644 ///
645 /// # Panics
646 ///
647 /// Panics if the input is a doc comment literal.
Alex Crichton9a4dca22018-03-28 06:32:19 -0700648 pub fn new(token: Literal) -> Self {
David Tolnay7d1d1282018-01-06 16:10:51 -0800649 let value = token.to_string();
650
651 match value::byte(&value, 0) {
David Tolnay94d2b792018-04-29 12:26:10 -0700652 b'"' | b'r' => return Lit::Str(LitStr { token: token }),
David Tolnay7d1d1282018-01-06 16:10:51 -0800653 b'b' => match value::byte(&value, 1) {
David Tolnay94d2b792018-04-29 12:26:10 -0700654 b'"' | b'r' => return Lit::ByteStr(LitByteStr { token: token }),
655 b'\'' => return Lit::Byte(LitByte { token: token }),
David Tolnay7d1d1282018-01-06 16:10:51 -0800656 _ => {}
657 },
David Tolnay94d2b792018-04-29 12:26:10 -0700658 b'\'' => return Lit::Char(LitChar { token: token }),
David Tolnayfb84fc02018-10-02 21:01:30 -0700659 b'0'...b'9' => {
660 if number_is_int(&value) {
661 return Lit::Int(LitInt { token: token });
662 } else if number_is_float(&value) {
663 return Lit::Float(LitFloat { token: token });
664 } else {
665 // number overflow
666 return Lit::Verbatim(LitVerbatim { token: token });
667 }
668 }
669 _ => {
670 if value == "true" || value == "false" {
671 return Lit::Bool(LitBool {
672 value: value == "true",
673 span: token.span(),
674 });
675 }
676 }
David Tolnay7d1d1282018-01-06 16:10:51 -0800677 }
678
679 panic!("Unrecognized literal: {}", value);
680 }
681 }
682
683 fn number_is_int(value: &str) -> bool {
684 if number_is_float(value) {
685 false
686 } else {
687 value::parse_lit_int(value).is_some()
688 }
689 }
690
691 fn number_is_float(value: &str) -> bool {
692 if value.contains('.') {
693 true
694 } else if value.starts_with("0x") || value.ends_with("size") {
695 false
696 } else {
697 value.contains('e') || value.contains('E')
698 }
699 }
700
David Tolnay360efd22018-01-04 23:35:26 -0800701 /// Get the byte at offset idx, or a default of `b'\0'` if we're looking
702 /// past the end of the input buffer.
703 pub fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 {
704 let s = s.as_ref();
705 if idx < s.len() {
706 s[idx]
707 } else {
708 0
709 }
710 }
711
712 fn next_chr(s: &str) -> char {
713 s.chars().next().unwrap_or('\0')
714 }
715
716 pub fn parse_lit_str(s: &str) -> String {
717 match byte(s, 0) {
718 b'"' => parse_lit_str_cooked(s),
719 b'r' => parse_lit_str_raw(s),
720 _ => unreachable!(),
721 }
722 }
723
David Tolnay76ebcdd2018-01-05 17:07:26 -0800724 // Clippy false positive
725 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
726 #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))]
David Tolnay360efd22018-01-04 23:35:26 -0800727 fn parse_lit_str_cooked(mut s: &str) -> String {
728 assert_eq!(byte(s, 0), b'"');
729 s = &s[1..];
730
731 let mut out = String::new();
732 'outer: loop {
733 let ch = match byte(s, 0) {
734 b'"' => break,
735 b'\\' => {
736 let b = byte(s, 1);
737 s = &s[2..];
738 match b {
739 b'x' => {
740 let (byte, rest) = backslash_x(s);
741 s = rest;
742 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
David Tolnay76ebcdd2018-01-05 17:07:26 -0800743 char::from_u32(u32::from(byte)).unwrap()
David Tolnay360efd22018-01-04 23:35:26 -0800744 }
745 b'u' => {
David Tolnay76ebcdd2018-01-05 17:07:26 -0800746 let (chr, rest) = backslash_u(s);
David Tolnay360efd22018-01-04 23:35:26 -0800747 s = rest;
748 chr
749 }
750 b'n' => '\n',
751 b'r' => '\r',
752 b't' => '\t',
753 b'\\' => '\\',
754 b'0' => '\0',
755 b'\'' => '\'',
756 b'"' => '"',
David Tolnay61037c62018-01-05 16:21:03 -0800757 b'\r' | b'\n' => loop {
758 let ch = next_chr(s);
759 if ch.is_whitespace() {
760 s = &s[ch.len_utf8()..];
761 } else {
762 continue 'outer;
David Tolnay360efd22018-01-04 23:35:26 -0800763 }
David Tolnay61037c62018-01-05 16:21:03 -0800764 },
765 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800766 }
767 }
768 b'\r' => {
769 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
770 s = &s[2..];
771 '\n'
772 }
773 _ => {
774 let ch = next_chr(s);
775 s = &s[ch.len_utf8()..];
776 ch
777 }
778 };
779 out.push(ch);
780 }
781
782 assert_eq!(s, "\"");
783 out
784 }
785
786 fn parse_lit_str_raw(mut s: &str) -> String {
787 assert_eq!(byte(s, 0), b'r');
788 s = &s[1..];
789
790 let mut pounds = 0;
791 while byte(s, pounds) == b'#' {
792 pounds += 1;
793 }
794 assert_eq!(byte(s, pounds), b'"');
795 assert_eq!(byte(s, s.len() - pounds - 1), b'"');
796 for end in s[s.len() - pounds..].bytes() {
797 assert_eq!(end, b'#');
798 }
799
800 s[pounds + 1..s.len() - pounds - 1].to_owned()
801 }
802
803 pub fn parse_lit_byte_str(s: &str) -> Vec<u8> {
804 assert_eq!(byte(s, 0), b'b');
805 match byte(s, 1) {
806 b'"' => parse_lit_byte_str_cooked(s),
807 b'r' => parse_lit_byte_str_raw(s),
808 _ => unreachable!(),
809 }
810 }
811
David Tolnay76ebcdd2018-01-05 17:07:26 -0800812 // Clippy false positive
813 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
814 #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))]
David Tolnay360efd22018-01-04 23:35:26 -0800815 fn parse_lit_byte_str_cooked(mut s: &str) -> Vec<u8> {
816 assert_eq!(byte(s, 0), b'b');
817 assert_eq!(byte(s, 1), b'"');
818 s = &s[2..];
819
820 // We're going to want to have slices which don't respect codepoint boundaries.
821 let mut s = s.as_bytes();
822
823 let mut out = Vec::new();
824 'outer: loop {
825 let byte = match byte(s, 0) {
826 b'"' => break,
827 b'\\' => {
828 let b = byte(s, 1);
829 s = &s[2..];
830 match b {
831 b'x' => {
832 let (b, rest) = backslash_x(s);
833 s = rest;
834 b
835 }
836 b'n' => b'\n',
837 b'r' => b'\r',
838 b't' => b'\t',
839 b'\\' => b'\\',
840 b'0' => b'\0',
841 b'\'' => b'\'',
842 b'"' => b'"',
David Tolnay61037c62018-01-05 16:21:03 -0800843 b'\r' | b'\n' => loop {
844 let byte = byte(s, 0);
David Tolnay76ebcdd2018-01-05 17:07:26 -0800845 let ch = char::from_u32(u32::from(byte)).unwrap();
David Tolnay61037c62018-01-05 16:21:03 -0800846 if ch.is_whitespace() {
847 s = &s[1..];
848 } else {
849 continue 'outer;
David Tolnay360efd22018-01-04 23:35:26 -0800850 }
David Tolnay61037c62018-01-05 16:21:03 -0800851 },
852 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800853 }
854 }
855 b'\r' => {
856 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
857 s = &s[2..];
858 b'\n'
859 }
860 b => {
861 s = &s[1..];
862 b
863 }
864 };
865 out.push(byte);
866 }
867
868 assert_eq!(s, b"\"");
869 out
870 }
871
872 fn parse_lit_byte_str_raw(s: &str) -> Vec<u8> {
873 assert_eq!(byte(s, 0), b'b');
874 parse_lit_str_raw(&s[1..]).into_bytes()
875 }
876
877 pub fn parse_lit_byte(s: &str) -> u8 {
878 assert_eq!(byte(s, 0), b'b');
879 assert_eq!(byte(s, 1), b'\'');
880
881 // We're going to want to have slices which don't respect codepoint boundaries.
882 let mut s = s[2..].as_bytes();
883
884 let b = match byte(s, 0) {
885 b'\\' => {
886 let b = byte(s, 1);
887 s = &s[2..];
888 match b {
889 b'x' => {
890 let (b, rest) = backslash_x(s);
891 s = rest;
892 b
893 }
894 b'n' => b'\n',
895 b'r' => b'\r',
896 b't' => b'\t',
897 b'\\' => b'\\',
898 b'0' => b'\0',
899 b'\'' => b'\'',
900 b'"' => b'"',
David Tolnay61037c62018-01-05 16:21:03 -0800901 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800902 }
903 }
904 b => {
905 s = &s[1..];
906 b
907 }
908 };
909
910 assert_eq!(byte(s, 0), b'\'');
911 b
912 }
913
914 pub fn parse_lit_char(mut s: &str) -> char {
915 assert_eq!(byte(s, 0), b'\'');
916 s = &s[1..];
917
918 let ch = match byte(s, 0) {
919 b'\\' => {
920 let b = byte(s, 1);
921 s = &s[2..];
922 match b {
923 b'x' => {
924 let (byte, rest) = backslash_x(s);
925 s = rest;
926 assert!(byte <= 0x80, "Invalid \\x byte in string literal");
David Tolnay76ebcdd2018-01-05 17:07:26 -0800927 char::from_u32(u32::from(byte)).unwrap()
David Tolnay360efd22018-01-04 23:35:26 -0800928 }
929 b'u' => {
930 let (chr, rest) = backslash_u(s);
931 s = rest;
932 chr
933 }
934 b'n' => '\n',
935 b'r' => '\r',
936 b't' => '\t',
937 b'\\' => '\\',
938 b'0' => '\0',
939 b'\'' => '\'',
940 b'"' => '"',
David Tolnay61037c62018-01-05 16:21:03 -0800941 b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
David Tolnay360efd22018-01-04 23:35:26 -0800942 }
943 }
944 _ => {
945 let ch = next_chr(s);
946 s = &s[ch.len_utf8()..];
947 ch
948 }
949 };
950 assert_eq!(s, "\'", "Expected end of char literal");
951 ch
952 }
953
954 fn backslash_x<S>(s: &S) -> (u8, &S)
David Tolnay61037c62018-01-05 16:21:03 -0800955 where
956 S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
David Tolnay360efd22018-01-04 23:35:26 -0800957 {
958 let mut ch = 0;
959 let b0 = byte(s, 0);
960 let b1 = byte(s, 1);
961 ch += 0x10 * match b0 {
962 b'0'...b'9' => b0 - b'0',
963 b'a'...b'f' => 10 + (b0 - b'a'),
964 b'A'...b'F' => 10 + (b0 - b'A'),
965 _ => panic!("unexpected non-hex character after \\x"),
966 };
David Tolnay76ebcdd2018-01-05 17:07:26 -0800967 ch += match b1 {
David Tolnay360efd22018-01-04 23:35:26 -0800968 b'0'...b'9' => b1 - b'0',
969 b'a'...b'f' => 10 + (b1 - b'a'),
970 b'A'...b'F' => 10 + (b1 - b'A'),
971 _ => panic!("unexpected non-hex character after \\x"),
972 };
973 (ch, &s[2..])
974 }
975
976 fn backslash_u(mut s: &str) -> (char, &str) {
977 if byte(s, 0) != b'{' {
978 panic!("expected {{ after \\u");
979 }
980 s = &s[1..];
981
982 let mut ch = 0;
983 for _ in 0..6 {
984 let b = byte(s, 0);
985 match b {
986 b'0'...b'9' => {
987 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800988 ch += u32::from(b - b'0');
David Tolnay360efd22018-01-04 23:35:26 -0800989 s = &s[1..];
990 }
991 b'a'...b'f' => {
992 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800993 ch += u32::from(10 + b - b'a');
David Tolnay360efd22018-01-04 23:35:26 -0800994 s = &s[1..];
995 }
996 b'A'...b'F' => {
997 ch *= 0x10;
David Tolnay76ebcdd2018-01-05 17:07:26 -0800998 ch += u32::from(10 + b - b'A');
David Tolnay360efd22018-01-04 23:35:26 -0800999 s = &s[1..];
1000 }
1001 b'}' => break,
1002 _ => panic!("unexpected non-hex character after \\u"),
1003 }
1004 }
1005 assert!(byte(s, 0) == b'}');
1006 s = &s[1..];
1007
1008 if let Some(ch) = char::from_u32(ch) {
1009 (ch, s)
1010 } else {
1011 panic!("character code {:x} is not a valid unicode character", ch);
1012 }
1013 }
1014
1015 pub fn parse_lit_int(mut s: &str) -> Option<u64> {
1016 let base = match (byte(s, 0), byte(s, 1)) {
1017 (b'0', b'x') => {
1018 s = &s[2..];
1019 16
1020 }
1021 (b'0', b'o') => {
1022 s = &s[2..];
1023 8
1024 }
1025 (b'0', b'b') => {
1026 s = &s[2..];
1027 2
1028 }
1029 (b'0'...b'9', _) => 10,
1030 _ => unreachable!(),
1031 };
1032
1033 let mut value = 0u64;
1034 loop {
1035 let b = byte(s, 0);
1036 let digit = match b {
David Tolnay76ebcdd2018-01-05 17:07:26 -08001037 b'0'...b'9' => u64::from(b - b'0'),
1038 b'a'...b'f' if base > 10 => 10 + u64::from(b - b'a'),
1039 b'A'...b'F' if base > 10 => 10 + u64::from(b - b'A'),
David Tolnay360efd22018-01-04 23:35:26 -08001040 b'_' => {
1041 s = &s[1..];
1042 continue;
1043 }
1044 // NOTE: Looking at a floating point literal, we don't want to
1045 // consider these integers.
1046 b'.' if base == 10 => return None,
1047 b'e' | b'E' if base == 10 => return None,
1048 _ => break,
1049 };
1050
1051 if digit >= base {
1052 panic!("Unexpected digit {:x} out of base range", digit);
1053 }
1054
1055 value = match value.checked_mul(base) {
1056 Some(value) => value,
1057 None => return None,
1058 };
1059 value = match value.checked_add(digit) {
1060 Some(value) => value,
1061 None => return None,
1062 };
1063 s = &s[1..];
1064 }
1065
1066 Some(value)
1067 }
1068
1069 pub fn parse_lit_float(input: &str) -> f64 {
1070 // Rust's floating point literals are very similar to the ones parsed by
1071 // the standard library, except that rust's literals can contain
1072 // ignorable underscores. Let's remove those underscores.
1073 let mut bytes = input.to_owned().into_bytes();
1074 let mut write = 0;
1075 for read in 0..bytes.len() {
1076 if bytes[read] == b'_' {
1077 continue; // Don't increase write
David Tolnay76ebcdd2018-01-05 17:07:26 -08001078 }
1079 if write != read {
David Tolnay360efd22018-01-04 23:35:26 -08001080 let x = bytes[read];
1081 bytes[write] = x;
1082 }
1083 write += 1;
1084 }
1085 bytes.truncate(write);
1086 let input = String::from_utf8(bytes).unwrap();
David Tolnay76ebcdd2018-01-05 17:07:26 -08001087 let end = input.find('f').unwrap_or_else(|| input.len());
David Tolnay360efd22018-01-04 23:35:26 -08001088 input[..end].parse().unwrap()
1089 }
1090
1091 pub fn to_literal(s: &str) -> Literal {
1092 let stream = s.parse::<TokenStream>().unwrap();
Alex Crichton9a4dca22018-03-28 06:32:19 -07001093 match stream.into_iter().next().unwrap() {
1094 TokenTree::Literal(l) => l,
David Tolnay360efd22018-01-04 23:35:26 -08001095 _ => unreachable!(),
David Tolnayf17fd2f2016-10-07 23:38:08 -07001096 }
1097 }
David Tolnayf4bbbd92016-09-23 14:41:55 -07001098}