1 #[cfg(feature = "parsing")]
2 use crate::lookahead;
3 #[cfg(feature = "parsing")]
4 use crate::parse::{Parse, Parser};
5 use crate::{Error, Result};
6 #[cfg(feature = "printing")]
7 use proc_macro2::Ident;
8 #[cfg(feature = "parsing")]
9 use proc_macro2::TokenStream;
10 use proc_macro2::TokenTree;
11 use proc_macro2::{Literal, Span};
12 use std::fmt::{self, Display};
13 #[cfg(feature = "extra-traits")]
14 use std::hash::{Hash, Hasher};
15 use std::str::{self, FromStr};
16 
17 ast_enum_of_structs! {
18     /// A Rust literal such as a string or integer or boolean.
19     ///
20     /// # Syntax tree enum
21     ///
22     /// This type is a [syntax tree enum].
23     ///
24     /// [syntax tree enum]: crate::Expr#syntax-tree-enums
25     pub enum Lit {
26         /// A UTF-8 string literal: `"foo"`.
27         Str(LitStr),
28 
29         /// A byte string literal: `b"foo"`.
30         ByteStr(LitByteStr),
31 
32         /// A byte literal: `b'f'`.
33         Byte(LitByte),
34 
35         /// A character literal: `'a'`.
36         Char(LitChar),
37 
38         /// An integer literal: `1` or `1u16`.
39         Int(LitInt),
40 
41         /// A floating point literal: `1f64` or `1.0e10f64`.
42         ///
43         /// Must be finite. May not be infinite or NaN.
44         Float(LitFloat),
45 
46         /// A boolean literal: `true` or `false`.
47         Bool(LitBool),
48 
49         /// A raw token literal not interpreted by Syn.
50         Verbatim(Literal),
51     }
52 }
53 
54 ast_struct! {
55     /// A UTF-8 string literal: `"foo"`.
56     pub struct LitStr {
57         repr: Box<LitRepr>,
58     }
59 }
60 
61 ast_struct! {
62     /// A byte string literal: `b"foo"`.
63     pub struct LitByteStr {
64         repr: Box<LitRepr>,
65     }
66 }
67 
68 ast_struct! {
69     /// A byte literal: `b'f'`.
70     pub struct LitByte {
71         repr: Box<LitRepr>,
72     }
73 }
74 
75 ast_struct! {
76     /// A character literal: `'a'`.
77     pub struct LitChar {
78         repr: Box<LitRepr>,
79     }
80 }
81 
82 struct LitRepr {
83     token: Literal,
84     suffix: Box<str>,
85 }
86 
87 ast_struct! {
88     /// An integer literal: `1` or `1u16`.
89     pub struct LitInt {
90         repr: Box<LitIntRepr>,
91     }
92 }
93 
94 struct LitIntRepr {
95     token: Literal,
96     digits: Box<str>,
97     suffix: Box<str>,
98 }
99 
100 ast_struct! {
101     /// A floating point literal: `1f64` or `1.0e10f64`.
102     ///
103     /// Must be finite. May not be infinite or NaN.
104     pub struct LitFloat {
105         repr: Box<LitFloatRepr>,
106     }
107 }
108 
109 struct LitFloatRepr {
110     token: Literal,
111     digits: Box<str>,
112     suffix: Box<str>,
113 }
114 
115 ast_struct! {
116     /// A boolean literal: `true` or `false`.
117     pub struct LitBool {
118         pub value: bool,
119         pub span: Span,
120     }
121 }
122 
123 impl LitStr {
new(value: &str, span: Span) -> Self124     pub fn new(value: &str, span: Span) -> Self {
125         let mut token = Literal::string(value);
126         token.set_span(span);
127         LitStr {
128             repr: Box::new(LitRepr {
129                 token,
130                 suffix: Box::<str>::default(),
131             }),
132         }
133     }
134 
value(&self) -> String135     pub fn value(&self) -> String {
136         let repr = self.repr.token.to_string();
137         let (value, _suffix) = value::parse_lit_str(&repr);
138         String::from(value)
139     }
140 
141     /// Parse a syntax tree node from the content of this string literal.
142     ///
143     /// All spans in the syntax tree will point to the span of this `LitStr`.
144     ///
145     /// # Example
146     ///
147     /// ```
148     /// use proc_macro2::Span;
149     /// use syn::{Attribute, Error, Ident, Lit, Meta, MetaNameValue, Path, Result};
150     ///
151     /// // Parses the path from an attribute that looks like:
152     /// //
153     /// //     #[path = "a::b::c"]
154     /// //
155     /// // or returns `None` if the input is some other attribute.
156     /// fn get_path(attr: &Attribute) -> Result<Option<Path>> {
157     ///     if !attr.path.is_ident("path") {
158     ///         return Ok(None);
159     ///     }
160     ///
161     ///     match attr.parse_meta()? {
162     ///         Meta::NameValue(MetaNameValue { lit: Lit::Str(lit_str), .. }) => {
163     ///             lit_str.parse().map(Some)
164     ///         }
165     ///         _ => {
166     ///             let message = "expected #[path = \"...\"]";
167     ///             Err(Error::new_spanned(attr, message))
168     ///         }
169     ///     }
170     /// }
171     /// ```
172     #[cfg(feature = "parsing")]
173     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
parse<T: Parse>(&self) -> Result<T>174     pub fn parse<T: Parse>(&self) -> Result<T> {
175         self.parse_with(T::parse)
176     }
177 
178     /// Invoke parser on the content of this string literal.
179     ///
180     /// All spans in the syntax tree will point to the span of this `LitStr`.
181     ///
182     /// # Example
183     ///
184     /// ```
185     /// # use proc_macro2::Span;
186     /// # use syn::{LitStr, Result};
187     /// #
188     /// # fn main() -> Result<()> {
189     /// #     let lit_str = LitStr::new("a::b::c", Span::call_site());
190     /// #
191     /// #     const IGNORE: &str = stringify! {
192     /// let lit_str: LitStr = /* ... */;
193     /// #     };
194     ///
195     /// // Parse a string literal like "a::b::c" into a Path, not allowing
196     /// // generic arguments on any of the path segments.
197     /// let basic_path = lit_str.parse_with(syn::Path::parse_mod_style)?;
198     /// #
199     /// #     Ok(())
200     /// # }
201     /// ```
202     #[cfg(feature = "parsing")]
203     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
parse_with<F: Parser>(&self, parser: F) -> Result<F::Output>204     pub fn parse_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
205         use proc_macro2::Group;
206 
207         // Token stream with every span replaced by the given one.
208         fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
209             stream
210                 .into_iter()
211                 .map(|token| respan_token_tree(token, span))
212                 .collect()
213         }
214 
215         // Token tree with every span replaced by the given one.
216         fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
217             match &mut token {
218                 TokenTree::Group(g) => {
219                     let stream = respan_token_stream(g.stream(), span);
220                     *g = Group::new(g.delimiter(), stream);
221                     g.set_span(span);
222                 }
223                 other => other.set_span(span),
224             }
225             token
226         }
227 
228         // Parse string literal into a token stream with every span equal to the
229         // original literal's span.
230         let mut tokens = crate::parse_str(&self.value())?;
231         tokens = respan_token_stream(tokens, self.span());
232 
233         parser.parse2(tokens)
234     }
235 
span(&self) -> Span236     pub fn span(&self) -> Span {
237         self.repr.token.span()
238     }
239 
set_span(&mut self, span: Span)240     pub fn set_span(&mut self, span: Span) {
241         self.repr.token.set_span(span);
242     }
243 
suffix(&self) -> &str244     pub fn suffix(&self) -> &str {
245         &self.repr.suffix
246     }
247 }
248 
249 impl LitByteStr {
new(value: &[u8], span: Span) -> Self250     pub fn new(value: &[u8], span: Span) -> Self {
251         let mut token = Literal::byte_string(value);
252         token.set_span(span);
253         LitByteStr {
254             repr: Box::new(LitRepr {
255                 token,
256                 suffix: Box::<str>::default(),
257             }),
258         }
259     }
260 
value(&self) -> Vec<u8>261     pub fn value(&self) -> Vec<u8> {
262         let repr = self.repr.token.to_string();
263         let (value, _suffix) = value::parse_lit_byte_str(&repr);
264         value
265     }
266 
span(&self) -> Span267     pub fn span(&self) -> Span {
268         self.repr.token.span()
269     }
270 
set_span(&mut self, span: Span)271     pub fn set_span(&mut self, span: Span) {
272         self.repr.token.set_span(span);
273     }
274 
suffix(&self) -> &str275     pub fn suffix(&self) -> &str {
276         &self.repr.suffix
277     }
278 }
279 
280 impl LitByte {
new(value: u8, span: Span) -> Self281     pub fn new(value: u8, span: Span) -> Self {
282         let mut token = Literal::u8_suffixed(value);
283         token.set_span(span);
284         LitByte {
285             repr: Box::new(LitRepr {
286                 token,
287                 suffix: Box::<str>::default(),
288             }),
289         }
290     }
291 
value(&self) -> u8292     pub fn value(&self) -> u8 {
293         let repr = self.repr.token.to_string();
294         let (value, _suffix) = value::parse_lit_byte(&repr);
295         value
296     }
297 
span(&self) -> Span298     pub fn span(&self) -> Span {
299         self.repr.token.span()
300     }
301 
set_span(&mut self, span: Span)302     pub fn set_span(&mut self, span: Span) {
303         self.repr.token.set_span(span);
304     }
305 
suffix(&self) -> &str306     pub fn suffix(&self) -> &str {
307         &self.repr.suffix
308     }
309 }
310 
311 impl LitChar {
new(value: char, span: Span) -> Self312     pub fn new(value: char, span: Span) -> Self {
313         let mut token = Literal::character(value);
314         token.set_span(span);
315         LitChar {
316             repr: Box::new(LitRepr {
317                 token,
318                 suffix: Box::<str>::default(),
319             }),
320         }
321     }
322 
value(&self) -> char323     pub fn value(&self) -> char {
324         let repr = self.repr.token.to_string();
325         let (value, _suffix) = value::parse_lit_char(&repr);
326         value
327     }
328 
span(&self) -> Span329     pub fn span(&self) -> Span {
330         self.repr.token.span()
331     }
332 
set_span(&mut self, span: Span)333     pub fn set_span(&mut self, span: Span) {
334         self.repr.token.set_span(span);
335     }
336 
suffix(&self) -> &str337     pub fn suffix(&self) -> &str {
338         &self.repr.suffix
339     }
340 }
341 
342 impl LitInt {
new(repr: &str, span: Span) -> Self343     pub fn new(repr: &str, span: Span) -> Self {
344         let (digits, suffix) = match value::parse_lit_int(repr) {
345             Some(parse) => parse,
346             None => panic!("Not an integer literal: `{}`", repr),
347         };
348 
349         let mut token = match value::to_literal(repr, &digits, &suffix) {
350             Some(token) => token,
351             None => panic!("Unsupported integer literal: `{}`", repr),
352         };
353 
354         token.set_span(span);
355         LitInt {
356             repr: Box::new(LitIntRepr {
357                 token,
358                 digits,
359                 suffix,
360             }),
361         }
362     }
363 
base10_digits(&self) -> &str364     pub fn base10_digits(&self) -> &str {
365         &self.repr.digits
366     }
367 
368     /// Parses the literal into a selected number type.
369     ///
370     /// This is equivalent to `lit.base10_digits().parse()` except that the
371     /// resulting errors will be correctly spanned to point to the literal token
372     /// in the macro input.
373     ///
374     /// ```
375     /// use syn::LitInt;
376     /// use syn::parse::{Parse, ParseStream, Result};
377     ///
378     /// struct Port {
379     ///     value: u16,
380     /// }
381     ///
382     /// impl Parse for Port {
383     ///     fn parse(input: ParseStream) -> Result<Self> {
384     ///         let lit: LitInt = input.parse()?;
385     ///         let value = lit.base10_parse::<u16>()?;
386     ///         Ok(Port { value })
387     ///     }
388     /// }
389     /// ```
base10_parse<N>(&self) -> Result<N> where N: FromStr, N::Err: Display,390     pub fn base10_parse<N>(&self) -> Result<N>
391     where
392         N: FromStr,
393         N::Err: Display,
394     {
395         self.base10_digits()
396             .parse()
397             .map_err(|err| Error::new(self.span(), err))
398     }
399 
suffix(&self) -> &str400     pub fn suffix(&self) -> &str {
401         &self.repr.suffix
402     }
403 
span(&self) -> Span404     pub fn span(&self) -> Span {
405         self.repr.token.span()
406     }
407 
set_span(&mut self, span: Span)408     pub fn set_span(&mut self, span: Span) {
409         self.repr.token.set_span(span);
410     }
411 }
412 
413 impl From<Literal> for LitInt {
from(token: Literal) -> Self414     fn from(token: Literal) -> Self {
415         let repr = token.to_string();
416         if let Some((digits, suffix)) = value::parse_lit_int(&repr) {
417             LitInt {
418                 repr: Box::new(LitIntRepr {
419                     token,
420                     digits,
421                     suffix,
422                 }),
423             }
424         } else {
425             panic!("Not an integer literal: `{}`", repr);
426         }
427     }
428 }
429 
430 impl Display for LitInt {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result431     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
432         self.repr.token.fmt(formatter)
433     }
434 }
435 
436 impl LitFloat {
new(repr: &str, span: Span) -> Self437     pub fn new(repr: &str, span: Span) -> Self {
438         let (digits, suffix) = match value::parse_lit_float(repr) {
439             Some(parse) => parse,
440             None => panic!("Not a float literal: `{}`", repr),
441         };
442 
443         let mut token = match value::to_literal(repr, &digits, &suffix) {
444             Some(token) => token,
445             None => panic!("Unsupported float literal: `{}`", repr),
446         };
447 
448         token.set_span(span);
449         LitFloat {
450             repr: Box::new(LitFloatRepr {
451                 token,
452                 digits,
453                 suffix,
454             }),
455         }
456     }
457 
base10_digits(&self) -> &str458     pub fn base10_digits(&self) -> &str {
459         &self.repr.digits
460     }
461 
base10_parse<N>(&self) -> Result<N> where N: FromStr, N::Err: Display,462     pub fn base10_parse<N>(&self) -> Result<N>
463     where
464         N: FromStr,
465         N::Err: Display,
466     {
467         self.base10_digits()
468             .parse()
469             .map_err(|err| Error::new(self.span(), err))
470     }
471 
suffix(&self) -> &str472     pub fn suffix(&self) -> &str {
473         &self.repr.suffix
474     }
475 
span(&self) -> Span476     pub fn span(&self) -> Span {
477         self.repr.token.span()
478     }
479 
set_span(&mut self, span: Span)480     pub fn set_span(&mut self, span: Span) {
481         self.repr.token.set_span(span);
482     }
483 }
484 
485 impl From<Literal> for LitFloat {
from(token: Literal) -> Self486     fn from(token: Literal) -> Self {
487         let repr = token.to_string();
488         if let Some((digits, suffix)) = value::parse_lit_float(&repr) {
489             LitFloat {
490                 repr: Box::new(LitFloatRepr {
491                     token,
492                     digits,
493                     suffix,
494                 }),
495             }
496         } else {
497             panic!("Not a float literal: `{}`", repr);
498         }
499     }
500 }
501 
502 impl Display for LitFloat {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result503     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
504         self.repr.token.fmt(formatter)
505     }
506 }
507 
508 impl LitBool {
new(value: bool, span: Span) -> Self509     pub fn new(value: bool, span: Span) -> Self {
510         LitBool { value, span }
511     }
512 
value(&self) -> bool513     pub fn value(&self) -> bool {
514         self.value
515     }
516 
span(&self) -> Span517     pub fn span(&self) -> Span {
518         self.span
519     }
520 
set_span(&mut self, span: Span)521     pub fn set_span(&mut self, span: Span) {
522         self.span = span;
523     }
524 }
525 
526 #[cfg(feature = "extra-traits")]
527 mod debug_impls {
528     use super::*;
529     use std::fmt::{self, Debug};
530 
531     #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
532     impl Debug for LitStr {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result533         fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
534             formatter
535                 .debug_struct("LitStr")
536                 .field("token", &format_args!("{}", self.repr.token))
537                 .finish()
538         }
539     }
540 
541     #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
542     impl Debug for LitByteStr {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result543         fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
544             formatter
545                 .debug_struct("LitByteStr")
546                 .field("token", &format_args!("{}", self.repr.token))
547                 .finish()
548         }
549     }
550 
551     #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
552     impl Debug for LitByte {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result553         fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
554             formatter
555                 .debug_struct("LitByte")
556                 .field("token", &format_args!("{}", self.repr.token))
557                 .finish()
558         }
559     }
560 
561     #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
562     impl Debug for LitChar {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result563         fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
564             formatter
565                 .debug_struct("LitChar")
566                 .field("token", &format_args!("{}", self.repr.token))
567                 .finish()
568         }
569     }
570 
571     #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
572     impl Debug for LitInt {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result573         fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
574             formatter
575                 .debug_struct("LitInt")
576                 .field("token", &format_args!("{}", self.repr.token))
577                 .finish()
578         }
579     }
580 
581     #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
582     impl Debug for LitFloat {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result583         fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
584             formatter
585                 .debug_struct("LitFloat")
586                 .field("token", &format_args!("{}", self.repr.token))
587                 .finish()
588         }
589     }
590 
591     #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
592     impl Debug for LitBool {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result593         fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
594             formatter
595                 .debug_struct("LitBool")
596                 .field("value", &self.value)
597                 .finish()
598         }
599     }
600 }
601 
602 #[cfg(feature = "clone-impls")]
603 #[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
604 impl Clone for LitRepr {
clone(&self) -> Self605     fn clone(&self) -> Self {
606         LitRepr {
607             token: self.token.clone(),
608             suffix: self.suffix.clone(),
609         }
610     }
611 }
612 
613 #[cfg(feature = "clone-impls")]
614 #[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
615 impl Clone for LitIntRepr {
clone(&self) -> Self616     fn clone(&self) -> Self {
617         LitIntRepr {
618             token: self.token.clone(),
619             digits: self.digits.clone(),
620             suffix: self.suffix.clone(),
621         }
622     }
623 }
624 
625 #[cfg(feature = "clone-impls")]
626 #[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
627 impl Clone for LitFloatRepr {
clone(&self) -> Self628     fn clone(&self) -> Self {
629         LitFloatRepr {
630             token: self.token.clone(),
631             digits: self.digits.clone(),
632             suffix: self.suffix.clone(),
633         }
634     }
635 }
636 
637 macro_rules! lit_extra_traits {
638     ($ty:ident) => {
639         #[cfg(feature = "clone-impls")]
640         #[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
641         impl Clone for $ty {
642             fn clone(&self) -> Self {
643                 $ty {
644                     repr: self.repr.clone(),
645                 }
646             }
647         }
648 
649         #[cfg(feature = "extra-traits")]
650         #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
651         impl PartialEq for $ty {
652             fn eq(&self, other: &Self) -> bool {
653                 self.repr.token.to_string() == other.repr.token.to_string()
654             }
655         }
656 
657         #[cfg(feature = "extra-traits")]
658         #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
659         impl Hash for $ty {
660             fn hash<H>(&self, state: &mut H)
661             where
662                 H: Hasher,
663             {
664                 self.repr.token.to_string().hash(state);
665             }
666         }
667 
668         #[cfg(feature = "parsing")]
669         #[doc(hidden)]
670         #[allow(non_snake_case)]
671         pub fn $ty(marker: lookahead::TokenMarker) -> $ty {
672             match marker {}
673         }
674     };
675 }
676 
677 lit_extra_traits!(LitStr);
678 lit_extra_traits!(LitByteStr);
679 lit_extra_traits!(LitByte);
680 lit_extra_traits!(LitChar);
681 lit_extra_traits!(LitInt);
682 lit_extra_traits!(LitFloat);
683 
684 #[cfg(feature = "parsing")]
685 #[doc(hidden)]
686 #[allow(non_snake_case)]
LitBool(marker: lookahead::TokenMarker) -> LitBool687 pub fn LitBool(marker: lookahead::TokenMarker) -> LitBool {
688     match marker {}
689 }
690 
691 ast_enum! {
692     /// The style of a string literal, either plain quoted or a raw string like
693     /// `r##"data"##`.
694     pub enum StrStyle #no_visit {
695         /// An ordinary string like `"data"`.
696         Cooked,
697         /// A raw string like `r##"data"##`.
698         ///
699         /// The unsigned integer is the number of `#` symbols used.
700         Raw(usize),
701     }
702 }
703 
704 #[cfg(feature = "parsing")]
705 #[doc(hidden)]
706 #[allow(non_snake_case)]
Lit(marker: lookahead::TokenMarker) -> Lit707 pub fn Lit(marker: lookahead::TokenMarker) -> Lit {
708     match marker {}
709 }
710 
711 #[cfg(feature = "parsing")]
712 pub mod parsing {
713     use super::*;
714     use crate::buffer::Cursor;
715     use crate::parse::{Parse, ParseStream, Result};
716     use proc_macro2::Punct;
717 
718     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
719     impl Parse for Lit {
parse(input: ParseStream) -> Result<Self>720         fn parse(input: ParseStream) -> Result<Self> {
721             input.step(|cursor| {
722                 if let Some((lit, rest)) = cursor.literal() {
723                     return Ok((Lit::new(lit), rest));
724                 }
725 
726                 if let Some((ident, rest)) = cursor.ident() {
727                     let value = ident == "true";
728                     if value || ident == "false" {
729                         let lit_bool = LitBool {
730                             value,
731                             span: ident.span(),
732                         };
733                         return Ok((Lit::Bool(lit_bool), rest));
734                     }
735                 }
736 
737                 if let Some((punct, rest)) = cursor.punct() {
738                     if punct.as_char() == '-' {
739                         if let Some((lit, rest)) = parse_negative_lit(punct, rest) {
740                             return Ok((lit, rest));
741                         }
742                     }
743                 }
744 
745                 Err(cursor.error("expected literal"))
746             })
747         }
748     }
749 
parse_negative_lit(neg: Punct, cursor: Cursor) -> Option<(Lit, Cursor)>750     fn parse_negative_lit(neg: Punct, cursor: Cursor) -> Option<(Lit, Cursor)> {
751         let (lit, rest) = cursor.literal()?;
752 
753         let mut span = neg.span();
754         span = span.join(lit.span()).unwrap_or(span);
755 
756         let mut repr = lit.to_string();
757         repr.insert(0, '-');
758 
759         if let Some((digits, suffix)) = value::parse_lit_int(&repr) {
760             if let Some(mut token) = value::to_literal(&repr, &digits, &suffix) {
761                 token.set_span(span);
762                 return Some((
763                     Lit::Int(LitInt {
764                         repr: Box::new(LitIntRepr {
765                             token,
766                             digits,
767                             suffix,
768                         }),
769                     }),
770                     rest,
771                 ));
772             }
773         }
774 
775         let (digits, suffix) = value::parse_lit_float(&repr)?;
776         let mut token = value::to_literal(&repr, &digits, &suffix)?;
777         token.set_span(span);
778         Some((
779             Lit::Float(LitFloat {
780                 repr: Box::new(LitFloatRepr {
781                     token,
782                     digits,
783                     suffix,
784                 }),
785             }),
786             rest,
787         ))
788     }
789 
790     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
791     impl Parse for LitStr {
parse(input: ParseStream) -> Result<Self>792         fn parse(input: ParseStream) -> Result<Self> {
793             let head = input.fork();
794             match input.parse() {
795                 Ok(Lit::Str(lit)) => Ok(lit),
796                 _ => Err(head.error("expected string literal")),
797             }
798         }
799     }
800 
801     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
802     impl Parse for LitByteStr {
parse(input: ParseStream) -> Result<Self>803         fn parse(input: ParseStream) -> Result<Self> {
804             let head = input.fork();
805             match input.parse() {
806                 Ok(Lit::ByteStr(lit)) => Ok(lit),
807                 _ => Err(head.error("expected byte string literal")),
808             }
809         }
810     }
811 
812     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
813     impl Parse for LitByte {
parse(input: ParseStream) -> Result<Self>814         fn parse(input: ParseStream) -> Result<Self> {
815             let head = input.fork();
816             match input.parse() {
817                 Ok(Lit::Byte(lit)) => Ok(lit),
818                 _ => Err(head.error("expected byte literal")),
819             }
820         }
821     }
822 
823     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
824     impl Parse for LitChar {
parse(input: ParseStream) -> Result<Self>825         fn parse(input: ParseStream) -> Result<Self> {
826             let head = input.fork();
827             match input.parse() {
828                 Ok(Lit::Char(lit)) => Ok(lit),
829                 _ => Err(head.error("expected character literal")),
830             }
831         }
832     }
833 
834     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
835     impl Parse for LitInt {
parse(input: ParseStream) -> Result<Self>836         fn parse(input: ParseStream) -> Result<Self> {
837             let head = input.fork();
838             match input.parse() {
839                 Ok(Lit::Int(lit)) => Ok(lit),
840                 _ => Err(head.error("expected integer literal")),
841             }
842         }
843     }
844 
845     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
846     impl Parse for LitFloat {
parse(input: ParseStream) -> Result<Self>847         fn parse(input: ParseStream) -> Result<Self> {
848             let head = input.fork();
849             match input.parse() {
850                 Ok(Lit::Float(lit)) => Ok(lit),
851                 _ => Err(head.error("expected floating point literal")),
852             }
853         }
854     }
855 
856     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
857     impl Parse for LitBool {
parse(input: ParseStream) -> Result<Self>858         fn parse(input: ParseStream) -> Result<Self> {
859             let head = input.fork();
860             match input.parse() {
861                 Ok(Lit::Bool(lit)) => Ok(lit),
862                 _ => Err(head.error("expected boolean literal")),
863             }
864         }
865     }
866 }
867 
868 #[cfg(feature = "printing")]
869 mod printing {
870     use super::*;
871     use proc_macro2::TokenStream;
872     use quote::{ToTokens, TokenStreamExt};
873 
874     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
875     impl ToTokens for LitStr {
to_tokens(&self, tokens: &mut TokenStream)876         fn to_tokens(&self, tokens: &mut TokenStream) {
877             self.repr.token.to_tokens(tokens);
878         }
879     }
880 
881     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
882     impl ToTokens for LitByteStr {
to_tokens(&self, tokens: &mut TokenStream)883         fn to_tokens(&self, tokens: &mut TokenStream) {
884             self.repr.token.to_tokens(tokens);
885         }
886     }
887 
888     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
889     impl ToTokens for LitByte {
to_tokens(&self, tokens: &mut TokenStream)890         fn to_tokens(&self, tokens: &mut TokenStream) {
891             self.repr.token.to_tokens(tokens);
892         }
893     }
894 
895     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
896     impl ToTokens for LitChar {
to_tokens(&self, tokens: &mut TokenStream)897         fn to_tokens(&self, tokens: &mut TokenStream) {
898             self.repr.token.to_tokens(tokens);
899         }
900     }
901 
902     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
903     impl ToTokens for LitInt {
to_tokens(&self, tokens: &mut TokenStream)904         fn to_tokens(&self, tokens: &mut TokenStream) {
905             self.repr.token.to_tokens(tokens);
906         }
907     }
908 
909     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
910     impl ToTokens for LitFloat {
to_tokens(&self, tokens: &mut TokenStream)911         fn to_tokens(&self, tokens: &mut TokenStream) {
912             self.repr.token.to_tokens(tokens);
913         }
914     }
915 
916     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
917     impl ToTokens for LitBool {
to_tokens(&self, tokens: &mut TokenStream)918         fn to_tokens(&self, tokens: &mut TokenStream) {
919             let s = if self.value { "true" } else { "false" };
920             tokens.append(Ident::new(s, self.span));
921         }
922     }
923 }
924 
925 mod value {
926     use super::*;
927     use crate::bigint::BigInt;
928     use proc_macro2::TokenStream;
929     use std::char;
930     use std::ops::{Index, RangeFrom};
931 
932     impl Lit {
933         /// Interpret a Syn literal from a proc-macro2 literal.
new(token: Literal) -> Self934         pub fn new(token: Literal) -> Self {
935             let repr = token.to_string();
936 
937             match byte(&repr, 0) {
938                 b'"' | b'r' => {
939                     let (_, suffix) = parse_lit_str(&repr);
940                     return Lit::Str(LitStr {
941                         repr: Box::new(LitRepr { token, suffix }),
942                     });
943                 }
944                 b'b' => match byte(&repr, 1) {
945                     b'"' | b'r' => {
946                         let (_, suffix) = parse_lit_byte_str(&repr);
947                         return Lit::ByteStr(LitByteStr {
948                             repr: Box::new(LitRepr { token, suffix }),
949                         });
950                     }
951                     b'\'' => {
952                         let (_, suffix) = parse_lit_byte(&repr);
953                         return Lit::Byte(LitByte {
954                             repr: Box::new(LitRepr { token, suffix }),
955                         });
956                     }
957                     _ => {}
958                 },
959                 b'\'' => {
960                     let (_, suffix) = parse_lit_char(&repr);
961                     return Lit::Char(LitChar {
962                         repr: Box::new(LitRepr { token, suffix }),
963                     });
964                 }
965                 b'0'..=b'9' | b'-' => {
966                     if let Some((digits, suffix)) = parse_lit_int(&repr) {
967                         return Lit::Int(LitInt {
968                             repr: Box::new(LitIntRepr {
969                                 token,
970                                 digits,
971                                 suffix,
972                             }),
973                         });
974                     }
975                     if let Some((digits, suffix)) = parse_lit_float(&repr) {
976                         return Lit::Float(LitFloat {
977                             repr: Box::new(LitFloatRepr {
978                                 token,
979                                 digits,
980                                 suffix,
981                             }),
982                         });
983                     }
984                 }
985                 b't' | b'f' => {
986                     if repr == "true" || repr == "false" {
987                         return Lit::Bool(LitBool {
988                             value: repr == "true",
989                             span: token.span(),
990                         });
991                     }
992                 }
993                 _ => {}
994             }
995 
996             panic!("Unrecognized literal: `{}`", repr);
997         }
998 
suffix(&self) -> &str999         pub fn suffix(&self) -> &str {
1000             match self {
1001                 Lit::Str(lit) => lit.suffix(),
1002                 Lit::ByteStr(lit) => lit.suffix(),
1003                 Lit::Byte(lit) => lit.suffix(),
1004                 Lit::Char(lit) => lit.suffix(),
1005                 Lit::Int(lit) => lit.suffix(),
1006                 Lit::Float(lit) => lit.suffix(),
1007                 Lit::Bool(_) | Lit::Verbatim(_) => "",
1008             }
1009         }
1010 
span(&self) -> Span1011         pub fn span(&self) -> Span {
1012             match self {
1013                 Lit::Str(lit) => lit.span(),
1014                 Lit::ByteStr(lit) => lit.span(),
1015                 Lit::Byte(lit) => lit.span(),
1016                 Lit::Char(lit) => lit.span(),
1017                 Lit::Int(lit) => lit.span(),
1018                 Lit::Float(lit) => lit.span(),
1019                 Lit::Bool(lit) => lit.span,
1020                 Lit::Verbatim(lit) => lit.span(),
1021             }
1022         }
1023 
set_span(&mut self, span: Span)1024         pub fn set_span(&mut self, span: Span) {
1025             match self {
1026                 Lit::Str(lit) => lit.set_span(span),
1027                 Lit::ByteStr(lit) => lit.set_span(span),
1028                 Lit::Byte(lit) => lit.set_span(span),
1029                 Lit::Char(lit) => lit.set_span(span),
1030                 Lit::Int(lit) => lit.set_span(span),
1031                 Lit::Float(lit) => lit.set_span(span),
1032                 Lit::Bool(lit) => lit.span = span,
1033                 Lit::Verbatim(lit) => lit.set_span(span),
1034             }
1035         }
1036     }
1037 
1038     /// Get the byte at offset idx, or a default of `b'\0'` if we're looking
1039     /// past the end of the input buffer.
byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u81040     pub fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 {
1041         let s = s.as_ref();
1042         if idx < s.len() {
1043             s[idx]
1044         } else {
1045             0
1046         }
1047     }
1048 
next_chr(s: &str) -> char1049     fn next_chr(s: &str) -> char {
1050         s.chars().next().unwrap_or('\0')
1051     }
1052 
1053     // Returns (content, suffix).
parse_lit_str(s: &str) -> (Box<str>, Box<str>)1054     pub fn parse_lit_str(s: &str) -> (Box<str>, Box<str>) {
1055         match byte(s, 0) {
1056             b'"' => parse_lit_str_cooked(s),
1057             b'r' => parse_lit_str_raw(s),
1058             _ => unreachable!(),
1059         }
1060     }
1061 
1062     // Clippy false positive
1063     // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
1064     #[allow(clippy::needless_continue)]
parse_lit_str_cooked(mut s: &str) -> (Box<str>, Box<str>)1065     fn parse_lit_str_cooked(mut s: &str) -> (Box<str>, Box<str>) {
1066         assert_eq!(byte(s, 0), b'"');
1067         s = &s[1..];
1068 
1069         let mut content = String::new();
1070         'outer: loop {
1071             let ch = match byte(s, 0) {
1072                 b'"' => break,
1073                 b'\\' => {
1074                     let b = byte(s, 1);
1075                     s = &s[2..];
1076                     match b {
1077                         b'x' => {
1078                             let (byte, rest) = backslash_x(s);
1079                             s = rest;
1080                             assert!(byte <= 0x80, "Invalid \\x byte in string literal");
1081                             char::from_u32(u32::from(byte)).unwrap()
1082                         }
1083                         b'u' => {
1084                             let (chr, rest) = backslash_u(s);
1085                             s = rest;
1086                             chr
1087                         }
1088                         b'n' => '\n',
1089                         b'r' => '\r',
1090                         b't' => '\t',
1091                         b'\\' => '\\',
1092                         b'0' => '\0',
1093                         b'\'' => '\'',
1094                         b'"' => '"',
1095                         b'\r' | b'\n' => loop {
1096                             let ch = next_chr(s);
1097                             if ch.is_whitespace() {
1098                                 s = &s[ch.len_utf8()..];
1099                             } else {
1100                                 continue 'outer;
1101                             }
1102                         },
1103                         b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
1104                     }
1105                 }
1106                 b'\r' => {
1107                     assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
1108                     s = &s[2..];
1109                     '\n'
1110                 }
1111                 _ => {
1112                     let ch = next_chr(s);
1113                     s = &s[ch.len_utf8()..];
1114                     ch
1115                 }
1116             };
1117             content.push(ch);
1118         }
1119 
1120         assert!(s.starts_with('"'));
1121         let content = content.into_boxed_str();
1122         let suffix = s[1..].to_owned().into_boxed_str();
1123         (content, suffix)
1124     }
1125 
parse_lit_str_raw(mut s: &str) -> (Box<str>, Box<str>)1126     fn parse_lit_str_raw(mut s: &str) -> (Box<str>, Box<str>) {
1127         assert_eq!(byte(s, 0), b'r');
1128         s = &s[1..];
1129 
1130         let mut pounds = 0;
1131         while byte(s, pounds) == b'#' {
1132             pounds += 1;
1133         }
1134         assert_eq!(byte(s, pounds), b'"');
1135         let close = s.rfind('"').unwrap();
1136         for end in s[close + 1..close + 1 + pounds].bytes() {
1137             assert_eq!(end, b'#');
1138         }
1139 
1140         let content = s[pounds + 1..close].to_owned().into_boxed_str();
1141         let suffix = s[close + 1 + pounds..].to_owned().into_boxed_str();
1142         (content, suffix)
1143     }
1144 
1145     // Returns (content, suffix).
parse_lit_byte_str(s: &str) -> (Vec<u8>, Box<str>)1146     pub fn parse_lit_byte_str(s: &str) -> (Vec<u8>, Box<str>) {
1147         assert_eq!(byte(s, 0), b'b');
1148         match byte(s, 1) {
1149             b'"' => parse_lit_byte_str_cooked(s),
1150             b'r' => parse_lit_byte_str_raw(s),
1151             _ => unreachable!(),
1152         }
1153     }
1154 
1155     // Clippy false positive
1156     // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
1157     #[allow(clippy::needless_continue)]
parse_lit_byte_str_cooked(mut s: &str) -> (Vec<u8>, Box<str>)1158     fn parse_lit_byte_str_cooked(mut s: &str) -> (Vec<u8>, Box<str>) {
1159         assert_eq!(byte(s, 0), b'b');
1160         assert_eq!(byte(s, 1), b'"');
1161         s = &s[2..];
1162 
1163         // We're going to want to have slices which don't respect codepoint boundaries.
1164         let mut v = s.as_bytes();
1165 
1166         let mut out = Vec::new();
1167         'outer: loop {
1168             let byte = match byte(v, 0) {
1169                 b'"' => break,
1170                 b'\\' => {
1171                     let b = byte(v, 1);
1172                     v = &v[2..];
1173                     match b {
1174                         b'x' => {
1175                             let (b, rest) = backslash_x(v);
1176                             v = rest;
1177                             b
1178                         }
1179                         b'n' => b'\n',
1180                         b'r' => b'\r',
1181                         b't' => b'\t',
1182                         b'\\' => b'\\',
1183                         b'0' => b'\0',
1184                         b'\'' => b'\'',
1185                         b'"' => b'"',
1186                         b'\r' | b'\n' => loop {
1187                             let byte = byte(v, 0);
1188                             let ch = char::from_u32(u32::from(byte)).unwrap();
1189                             if ch.is_whitespace() {
1190                                 v = &v[1..];
1191                             } else {
1192                                 continue 'outer;
1193                             }
1194                         },
1195                         b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
1196                     }
1197                 }
1198                 b'\r' => {
1199                     assert_eq!(byte(v, 1), b'\n', "Bare CR not allowed in string");
1200                     v = &v[2..];
1201                     b'\n'
1202                 }
1203                 b => {
1204                     v = &v[1..];
1205                     b
1206                 }
1207             };
1208             out.push(byte);
1209         }
1210 
1211         assert_eq!(byte(v, 0), b'"');
1212         let suffix = s[s.len() - v.len() + 1..].to_owned().into_boxed_str();
1213         (out, suffix)
1214     }
1215 
parse_lit_byte_str_raw(s: &str) -> (Vec<u8>, Box<str>)1216     fn parse_lit_byte_str_raw(s: &str) -> (Vec<u8>, Box<str>) {
1217         assert_eq!(byte(s, 0), b'b');
1218         let (value, suffix) = parse_lit_str_raw(&s[1..]);
1219         (String::from(value).into_bytes(), suffix)
1220     }
1221 
1222     // Returns (value, suffix).
parse_lit_byte(s: &str) -> (u8, Box<str>)1223     pub fn parse_lit_byte(s: &str) -> (u8, Box<str>) {
1224         assert_eq!(byte(s, 0), b'b');
1225         assert_eq!(byte(s, 1), b'\'');
1226 
1227         // We're going to want to have slices which don't respect codepoint boundaries.
1228         let mut v = s[2..].as_bytes();
1229 
1230         let b = match byte(v, 0) {
1231             b'\\' => {
1232                 let b = byte(v, 1);
1233                 v = &v[2..];
1234                 match b {
1235                     b'x' => {
1236                         let (b, rest) = backslash_x(v);
1237                         v = rest;
1238                         b
1239                     }
1240                     b'n' => b'\n',
1241                     b'r' => b'\r',
1242                     b't' => b'\t',
1243                     b'\\' => b'\\',
1244                     b'0' => b'\0',
1245                     b'\'' => b'\'',
1246                     b'"' => b'"',
1247                     b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
1248                 }
1249             }
1250             b => {
1251                 v = &v[1..];
1252                 b
1253             }
1254         };
1255 
1256         assert_eq!(byte(v, 0), b'\'');
1257         let suffix = s[s.len() - v.len() + 1..].to_owned().into_boxed_str();
1258         (b, suffix)
1259     }
1260 
1261     // Returns (value, suffix).
parse_lit_char(mut s: &str) -> (char, Box<str>)1262     pub fn parse_lit_char(mut s: &str) -> (char, Box<str>) {
1263         assert_eq!(byte(s, 0), b'\'');
1264         s = &s[1..];
1265 
1266         let ch = match byte(s, 0) {
1267             b'\\' => {
1268                 let b = byte(s, 1);
1269                 s = &s[2..];
1270                 match b {
1271                     b'x' => {
1272                         let (byte, rest) = backslash_x(s);
1273                         s = rest;
1274                         assert!(byte <= 0x80, "Invalid \\x byte in string literal");
1275                         char::from_u32(u32::from(byte)).unwrap()
1276                     }
1277                     b'u' => {
1278                         let (chr, rest) = backslash_u(s);
1279                         s = rest;
1280                         chr
1281                     }
1282                     b'n' => '\n',
1283                     b'r' => '\r',
1284                     b't' => '\t',
1285                     b'\\' => '\\',
1286                     b'0' => '\0',
1287                     b'\'' => '\'',
1288                     b'"' => '"',
1289                     b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
1290                 }
1291             }
1292             _ => {
1293                 let ch = next_chr(s);
1294                 s = &s[ch.len_utf8()..];
1295                 ch
1296             }
1297         };
1298         assert_eq!(byte(s, 0), b'\'');
1299         let suffix = s[1..].to_owned().into_boxed_str();
1300         (ch, suffix)
1301     }
1302 
backslash_x<S>(s: &S) -> (u8, &S) where S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,1303     fn backslash_x<S>(s: &S) -> (u8, &S)
1304     where
1305         S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
1306     {
1307         let mut ch = 0;
1308         let b0 = byte(s, 0);
1309         let b1 = byte(s, 1);
1310         ch += 0x10
1311             * match b0 {
1312                 b'0'..=b'9' => b0 - b'0',
1313                 b'a'..=b'f' => 10 + (b0 - b'a'),
1314                 b'A'..=b'F' => 10 + (b0 - b'A'),
1315                 _ => panic!("unexpected non-hex character after \\x"),
1316             };
1317         ch += match b1 {
1318             b'0'..=b'9' => b1 - b'0',
1319             b'a'..=b'f' => 10 + (b1 - b'a'),
1320             b'A'..=b'F' => 10 + (b1 - b'A'),
1321             _ => panic!("unexpected non-hex character after \\x"),
1322         };
1323         (ch, &s[2..])
1324     }
1325 
backslash_u(mut s: &str) -> (char, &str)1326     fn backslash_u(mut s: &str) -> (char, &str) {
1327         if byte(s, 0) != b'{' {
1328             panic!("{}", "expected { after \\u");
1329         }
1330         s = &s[1..];
1331 
1332         let mut ch = 0;
1333         let mut digits = 0;
1334         loop {
1335             let b = byte(s, 0);
1336             let digit = match b {
1337                 b'0'..=b'9' => b - b'0',
1338                 b'a'..=b'f' => 10 + b - b'a',
1339                 b'A'..=b'F' => 10 + b - b'A',
1340                 b'_' if digits > 0 => {
1341                     s = &s[1..];
1342                     continue;
1343                 }
1344                 b'}' if digits == 0 => panic!("invalid empty unicode escape"),
1345                 b'}' => break,
1346                 _ => panic!("unexpected non-hex character after \\u"),
1347             };
1348             if digits == 6 {
1349                 panic!("overlong unicode escape (must have at most 6 hex digits)");
1350             }
1351             ch *= 0x10;
1352             ch += u32::from(digit);
1353             digits += 1;
1354             s = &s[1..];
1355         }
1356         assert!(byte(s, 0) == b'}');
1357         s = &s[1..];
1358 
1359         if let Some(ch) = char::from_u32(ch) {
1360             (ch, s)
1361         } else {
1362             panic!("character code {:x} is not a valid unicode character", ch);
1363         }
1364     }
1365 
1366     // Returns base 10 digits and suffix.
parse_lit_int(mut s: &str) -> Option<(Box<str>, Box<str>)>1367     pub fn parse_lit_int(mut s: &str) -> Option<(Box<str>, Box<str>)> {
1368         let negative = byte(s, 0) == b'-';
1369         if negative {
1370             s = &s[1..];
1371         }
1372 
1373         let base = match (byte(s, 0), byte(s, 1)) {
1374             (b'0', b'x') => {
1375                 s = &s[2..];
1376                 16
1377             }
1378             (b'0', b'o') => {
1379                 s = &s[2..];
1380                 8
1381             }
1382             (b'0', b'b') => {
1383                 s = &s[2..];
1384                 2
1385             }
1386             (b'0'..=b'9', _) => 10,
1387             _ => return None,
1388         };
1389 
1390         let mut value = BigInt::new();
1391         'outer: loop {
1392             let b = byte(s, 0);
1393             let digit = match b {
1394                 b'0'..=b'9' => b - b'0',
1395                 b'a'..=b'f' if base > 10 => b - b'a' + 10,
1396                 b'A'..=b'F' if base > 10 => b - b'A' + 10,
1397                 b'_' => {
1398                     s = &s[1..];
1399                     continue;
1400                 }
1401                 // If looking at a floating point literal, we don't want to
1402                 // consider it an integer.
1403                 b'.' if base == 10 => return None,
1404                 b'e' | b'E' if base == 10 => {
1405                     let mut has_exp = false;
1406                     for (i, b) in s[1..].bytes().enumerate() {
1407                         match b {
1408                             b'_' => {}
1409                             b'-' | b'+' => return None,
1410                             b'0'..=b'9' => has_exp = true,
1411                             _ => {
1412                                 let suffix = &s[1 + i..];
1413                                 if has_exp && crate::ident::xid_ok(suffix) {
1414                                     return None;
1415                                 } else {
1416                                     break 'outer;
1417                                 }
1418                             }
1419                         }
1420                     }
1421                     if has_exp {
1422                         return None;
1423                     } else {
1424                         break;
1425                     }
1426                 }
1427                 _ => break,
1428             };
1429 
1430             if digit >= base {
1431                 return None;
1432             }
1433 
1434             value *= base;
1435             value += digit;
1436             s = &s[1..];
1437         }
1438 
1439         let suffix = s;
1440         if suffix.is_empty() || crate::ident::xid_ok(suffix) {
1441             let mut repr = value.to_string();
1442             if negative {
1443                 repr.insert(0, '-');
1444             }
1445             Some((repr.into_boxed_str(), suffix.to_owned().into_boxed_str()))
1446         } else {
1447             None
1448         }
1449     }
1450 
1451     // Returns base 10 digits and suffix.
parse_lit_float(input: &str) -> Option<(Box<str>, Box<str>)>1452     pub fn parse_lit_float(input: &str) -> Option<(Box<str>, Box<str>)> {
1453         // Rust's floating point literals are very similar to the ones parsed by
1454         // the standard library, except that rust's literals can contain
1455         // ignorable underscores. Let's remove those underscores.
1456 
1457         let mut bytes = input.to_owned().into_bytes();
1458 
1459         let start = (*bytes.get(0)? == b'-') as usize;
1460         match bytes.get(start)? {
1461             b'0'..=b'9' => {}
1462             _ => return None,
1463         }
1464 
1465         let mut read = start;
1466         let mut write = start;
1467         let mut has_dot = false;
1468         let mut has_e = false;
1469         let mut has_sign = false;
1470         let mut has_exponent = false;
1471         while read < bytes.len() {
1472             match bytes[read] {
1473                 b'_' => {
1474                     // Don't increase write
1475                     read += 1;
1476                     continue;
1477                 }
1478                 b'0'..=b'9' => {
1479                     if has_e {
1480                         has_exponent = true;
1481                     }
1482                     bytes[write] = bytes[read];
1483                 }
1484                 b'.' => {
1485                     if has_e || has_dot {
1486                         return None;
1487                     }
1488                     has_dot = true;
1489                     bytes[write] = b'.';
1490                 }
1491                 b'e' | b'E' => {
1492                     match bytes[read + 1..]
1493                         .iter()
1494                         .find(|b| **b != b'_')
1495                         .unwrap_or(&b'\0')
1496                     {
1497                         b'-' | b'+' | b'0'..=b'9' => {}
1498                         _ => break,
1499                     }
1500                     if has_e {
1501                         if has_exponent {
1502                             break;
1503                         } else {
1504                             return None;
1505                         }
1506                     }
1507                     has_e = true;
1508                     bytes[write] = b'e';
1509                 }
1510                 b'-' | b'+' => {
1511                     if has_sign || has_exponent || !has_e {
1512                         return None;
1513                     }
1514                     has_sign = true;
1515                     if bytes[read] == b'-' {
1516                         bytes[write] = bytes[read];
1517                     } else {
1518                         // Omit '+'
1519                         read += 1;
1520                         continue;
1521                     }
1522                 }
1523                 _ => break,
1524             }
1525             read += 1;
1526             write += 1;
1527         }
1528 
1529         if has_e && !has_exponent {
1530             return None;
1531         }
1532 
1533         let mut digits = String::from_utf8(bytes).unwrap();
1534         let suffix = digits.split_off(read);
1535         digits.truncate(write);
1536         if suffix.is_empty() || crate::ident::xid_ok(&suffix) {
1537             Some((digits.into_boxed_str(), suffix.into_boxed_str()))
1538         } else {
1539             None
1540         }
1541     }
1542 
to_literal(repr: &str, digits: &str, suffix: &str) -> Option<Literal>1543     pub fn to_literal(repr: &str, digits: &str, suffix: &str) -> Option<Literal> {
1544         if repr.starts_with('-') {
1545             let f64_parse_finite = || digits.parse().ok().filter(|x: &f64| x.is_finite());
1546             let f32_parse_finite = || digits.parse().ok().filter(|x: &f32| x.is_finite());
1547             if suffix == "f64" {
1548                 f64_parse_finite().map(Literal::f64_suffixed)
1549             } else if suffix == "f32" {
1550                 f32_parse_finite().map(Literal::f32_suffixed)
1551             } else if suffix == "i64" {
1552                 digits.parse().ok().map(Literal::i64_suffixed)
1553             } else if suffix == "i32" {
1554                 digits.parse().ok().map(Literal::i32_suffixed)
1555             } else if suffix == "i16" {
1556                 digits.parse().ok().map(Literal::i16_suffixed)
1557             } else if suffix == "i8" {
1558                 digits.parse().ok().map(Literal::i8_suffixed)
1559             } else if !suffix.is_empty() {
1560                 None
1561             } else if digits.contains('.') {
1562                 f64_parse_finite().map(Literal::f64_unsuffixed)
1563             } else {
1564                 digits.parse().ok().map(Literal::i64_unsuffixed)
1565             }
1566         } else {
1567             let stream = repr.parse::<TokenStream>().unwrap();
1568             match stream.into_iter().next().unwrap() {
1569                 TokenTree::Literal(l) => Some(l),
1570                 _ => unreachable!(),
1571             }
1572         }
1573     }
1574 }
1575