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::ffi::{CStr, CString};
10use std::fmt::{self, Display};
11#[cfg(feature = "extra-traits")]
12use std::hash::{Hash, Hasher};
13use std::str::{self, FromStr};
14
15#[doc = r" A Rust literal such as a string or integer or boolean."]
#[doc = r""]
#[doc = r" # Syntax tree enum"]
#[doc = r""]
#[doc = r" This type is a [syntax tree enum]."]
#[doc = r""]
#[doc = r" [syntax tree enum]: crate::expr::Expr#syntax-tree-enums"]
#[non_exhaustive]
pub enum Lit {

    #[doc = r#" A UTF-8 string literal: `"foo"`."#]
    Str(LitStr),

    #[doc = r#" A byte string literal: `b"foo"`."#]
    ByteStr(LitByteStr),

    #[doc = r#" A nul-terminated C-string literal: `c"foo"`."#]
    CStr(LitCStr),

    #[doc = r" A byte literal: `b'f'`."]
    Byte(LitByte),

    #[doc = r" A character literal: `'a'`."]
    Char(LitChar),

    #[doc = r" An integer literal: `1` or `1u16`."]
    Int(LitInt),

    #[doc = r" A floating point literal: `1f64` or `1.0e10f64`."]
    #[doc = r""]
    #[doc = r" Must be finite. May not be infinite or NaN."]
    Float(LitFloat),

    #[doc = r" A boolean literal: `true` or `false`."]
    Bool(LitBool),

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