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