syn/
lit.rs

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