syn/
lit.rs

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