Skip to main content

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),
}
#[doc(cfg(feature = "printing"))]
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 Display for LitInt {
495    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
496        self.repr.token.fmt(formatter)
497    }
498}
499
500impl LitFloat {
501    #[track_caller]
502    pub fn new(repr: &str, span: Span) -> Self {
503        let (digits, suffix) = match value::parse_lit_float(repr) {
504            Some(parse) => parse,
505            None => {
    ::core::panicking::panic_fmt(format_args!("not a float literal: `{0}`",
            repr));
}panic!("not a float literal: `{}`", repr),
506        };
507
508        let mut token: Literal = repr.parse().unwrap();
509        token.set_span(span);
510        LitFloat {
511            repr: Box::new(LitFloatRepr {
512                token,
513                digits,
514                suffix,
515            }),
516        }
517    }
518
519    pub fn base10_digits(&self) -> &str {
520        &self.repr.digits
521    }
522
523    pub fn base10_parse<N>(&self) -> Result<N>
524    where
525        N: FromStr,
526        N::Err: Display,
527    {
528        self.base10_digits()
529            .parse()
530            .map_err(|err| Error::new(self.span(), err))
531    }
532
533    pub fn suffix(&self) -> &str {
534        &self.repr.suffix
535    }
536
537    pub fn span(&self) -> Span {
538        self.repr.token.span()
539    }
540
541    pub fn set_span(&mut self, span: Span) {
542        self.repr.token.set_span(span);
543    }
544
545    pub fn token(&self) -> Literal {
546        self.repr.token.clone()
547    }
548}
549
550impl Display for LitFloat {
551    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
552        self.repr.token.fmt(formatter)
553    }
554}
555
556impl LitBool {
557    pub fn new(value: bool, span: Span) -> Self {
558        LitBool { value, span }
559    }
560
561    pub fn value(&self) -> bool {
562        self.value
563    }
564
565    pub fn span(&self) -> Span {
566        self.span
567    }
568
569    pub fn set_span(&mut self, span: Span) {
570        self.span = span;
571    }
572
573    pub fn token(&self) -> Ident {
574        let s = if self.value { "true" } else { "false" };
575        Ident::new(s, self.span)
576    }
577}
578
579#[cfg(feature = "extra-traits")]
580mod debug_impls {
581    use crate::lit::{LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitInt, LitStr};
582    use core::fmt::{self, Debug};
583
584    #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
585    impl Debug for LitStr {
586        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
587            self.debug(formatter, "LitStr")
588        }
589    }
590
591    impl LitStr {
592        pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
593            formatter
594                .debug_struct(name)
595                .field("token", &format_args!("{0}", self.repr.token)format_args!("{}", self.repr.token))
596                .finish()
597        }
598    }
599
600    #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
601    impl Debug for LitByteStr {
602        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
603            self.debug(formatter, "LitByteStr")
604        }
605    }
606
607    impl LitByteStr {
608        pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
609            formatter
610                .debug_struct(name)
611                .field("token", &format_args!("{0}", self.repr.token)format_args!("{}", self.repr.token))
612                .finish()
613        }
614    }
615
616    #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
617    impl Debug for LitCStr {
618        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
619            self.debug(formatter, "LitCStr")
620        }
621    }
622
623    impl LitCStr {
624        pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
625            formatter
626                .debug_struct(name)
627                .field("token", &format_args!("{0}", self.repr.token)format_args!("{}", self.repr.token))
628                .finish()
629        }
630    }
631
632    #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
633    impl Debug for LitByte {
634        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
635            self.debug(formatter, "LitByte")
636        }
637    }
638
639    impl LitByte {
640        pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
641            formatter
642                .debug_struct(name)
643                .field("token", &format_args!("{0}", self.repr.token)format_args!("{}", self.repr.token))
644                .finish()
645        }
646    }
647
648    #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
649    impl Debug for LitChar {
650        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
651            self.debug(formatter, "LitChar")
652        }
653    }
654
655    impl LitChar {
656        pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
657            formatter
658                .debug_struct(name)
659                .field("token", &format_args!("{0}", self.repr.token)format_args!("{}", self.repr.token))
660                .finish()
661        }
662    }
663
664    #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
665    impl Debug for LitInt {
666        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
667            self.debug(formatter, "LitInt")
668        }
669    }
670
671    impl LitInt {
672        pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
673            formatter
674                .debug_struct(name)
675                .field("token", &format_args!("{0}", self.repr.token)format_args!("{}", self.repr.token))
676                .finish()
677        }
678    }
679
680    #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
681    impl Debug for LitFloat {
682        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
683            self.debug(formatter, "LitFloat")
684        }
685    }
686
687    impl LitFloat {
688        pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
689            formatter
690                .debug_struct(name)
691                .field("token", &format_args!("{0}", self.repr.token)format_args!("{}", self.repr.token))
692                .finish()
693        }
694    }
695
696    #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
697    impl Debug for LitBool {
698        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
699            self.debug(formatter, "LitBool")
700        }
701    }
702
703    impl LitBool {
704        pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
705            formatter
706                .debug_struct(name)
707                .field("value", &self.value)
708                .finish()
709        }
710    }
711}
712
713#[cfg(feature = "clone-impls")]
714#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
715impl Clone for LitRepr {
716    fn clone(&self) -> Self {
717        LitRepr {
718            token: self.token.clone(),
719            suffix: self.suffix.clone(),
720        }
721    }
722}
723
724#[cfg(feature = "clone-impls")]
725#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
726impl Clone for LitIntRepr {
727    fn clone(&self) -> Self {
728        LitIntRepr {
729            token: self.token.clone(),
730            digits: self.digits.clone(),
731            suffix: self.suffix.clone(),
732        }
733    }
734}
735
736#[cfg(feature = "clone-impls")]
737#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
738impl Clone for LitFloatRepr {
739    fn clone(&self) -> Self {
740        LitFloatRepr {
741            token: self.token.clone(),
742            digits: self.digits.clone(),
743            suffix: self.suffix.clone(),
744        }
745    }
746}
747
748macro_rules! lit_extra_traits {
749    ($ty:ident) => {
750        #[cfg(feature = "clone-impls")]
751        #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
752        impl Clone for $ty {
753            fn clone(&self) -> Self {
754                $ty {
755                    repr: self.repr.clone(),
756                }
757            }
758        }
759
760        #[cfg(feature = "extra-traits")]
761        #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
762        impl PartialEq for $ty {
763            fn eq(&self, other: &Self) -> bool {
764                self.repr.token.to_string() == other.repr.token.to_string()
765            }
766        }
767
768        #[cfg(feature = "extra-traits")]
769        #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
770        impl Hash for $ty {
771            fn hash<H>(&self, state: &mut H)
772            where
773                H: Hasher,
774            {
775                self.repr.token.to_string().hash(state);
776            }
777        }
778
779        #[cfg(feature = "parsing")]
780        pub_if_not_doc! {
781            #[doc(hidden)]
782            #[allow(non_snake_case)]
783            pub fn $ty(marker: lookahead::TokenMarker) -> $ty {
784                match marker {}
785            }
786        }
787    };
788}
789
790#[doc(cfg(feature = "clone-impls"))]
impl Clone for LitStr {
    fn clone(&self) -> Self { LitStr { repr: self.repr.clone() } }
}
#[doc(cfg(feature = "extra-traits"))]
impl PartialEq for LitStr {
    fn eq(&self, other: &Self) -> bool {
        self.repr.token.to_string() == other.repr.token.to_string()
    }
}
#[doc(cfg(feature = "extra-traits"))]
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);
791#[doc(cfg(feature = "clone-impls"))]
impl Clone for LitByteStr {
    fn clone(&self) -> Self { LitByteStr { repr: self.repr.clone() } }
}
#[doc(cfg(feature = "extra-traits"))]
impl PartialEq for LitByteStr {
    fn eq(&self, other: &Self) -> bool {
        self.repr.token.to_string() == other.repr.token.to_string()
    }
}
#[doc(cfg(feature = "extra-traits"))]
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);
792#[doc(cfg(feature = "clone-impls"))]
impl Clone for LitCStr {
    fn clone(&self) -> Self { LitCStr { repr: self.repr.clone() } }
}
#[doc(cfg(feature = "extra-traits"))]
impl PartialEq for LitCStr {
    fn eq(&self, other: &Self) -> bool {
        self.repr.token.to_string() == other.repr.token.to_string()
    }
}
#[doc(cfg(feature = "extra-traits"))]
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);
793#[doc(cfg(feature = "clone-impls"))]
impl Clone for LitByte {
    fn clone(&self) -> Self { LitByte { repr: self.repr.clone() } }
}
#[doc(cfg(feature = "extra-traits"))]
impl PartialEq for LitByte {
    fn eq(&self, other: &Self) -> bool {
        self.repr.token.to_string() == other.repr.token.to_string()
    }
}
#[doc(cfg(feature = "extra-traits"))]
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);
794#[doc(cfg(feature = "clone-impls"))]
impl Clone for LitChar {
    fn clone(&self) -> Self { LitChar { repr: self.repr.clone() } }
}
#[doc(cfg(feature = "extra-traits"))]
impl PartialEq for LitChar {
    fn eq(&self, other: &Self) -> bool {
        self.repr.token.to_string() == other.repr.token.to_string()
    }
}
#[doc(cfg(feature = "extra-traits"))]
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);
795#[doc(cfg(feature = "clone-impls"))]
impl Clone for LitInt {
    fn clone(&self) -> Self { LitInt { repr: self.repr.clone() } }
}
#[doc(cfg(feature = "extra-traits"))]
impl PartialEq for LitInt {
    fn eq(&self, other: &Self) -> bool {
        self.repr.token.to_string() == other.repr.token.to_string()
    }
}
#[doc(cfg(feature = "extra-traits"))]
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);
796#[doc(cfg(feature = "clone-impls"))]
impl Clone for LitFloat {
    fn clone(&self) -> Self { LitFloat { repr: self.repr.clone() } }
}
#[doc(cfg(feature = "extra-traits"))]
impl PartialEq for LitFloat {
    fn eq(&self, other: &Self) -> bool {
        self.repr.token.to_string() == other.repr.token.to_string()
    }
}
#[doc(cfg(feature = "extra-traits"))]
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);
797
798#[cfg(feature = "parsing")]
799#[doc(hidden)]
#[allow(non_snake_case)]
pub(crate) fn LitBool(marker: lookahead::TokenMarker) -> LitBool {
    match marker {}
}pub_if_not_doc! {
800    #[doc(hidden)]
801    #[allow(non_snake_case)]
802    pub fn LitBool(marker: lookahead::TokenMarker) -> LitBool {
803        match marker {}
804    }
805}
806
807#[cfg(feature = "parsing")]
808#[doc(hidden)]
#[allow(non_snake_case)]
pub(crate) fn Lit(marker: lookahead::TokenMarker) -> Lit { match marker {} }pub_if_not_doc! {
809    #[doc(hidden)]
810    #[allow(non_snake_case)]
811    pub fn Lit(marker: lookahead::TokenMarker) -> Lit {
812        match marker {}
813    }
814}
815
816#[cfg(feature = "parsing")]
817pub(crate) mod parsing {
818    use crate::buffer::Cursor;
819    use crate::error::Result;
820    use crate::lit::{
821        value, Lit, LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitFloatRepr, LitInt,
822        LitIntRepr, LitStr,
823    };
824    use crate::parse::{Parse, ParseStream, Unexpected};
825    use crate::token::{self, Token};
826    use alloc::boxed::Box;
827    use alloc::rc::Rc;
828    use alloc::string::ToString;
829    use core::cell::Cell;
830    use proc_macro2::{Literal, Punct, Span};
831
832    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
833    impl Parse for Lit {
834        fn parse(input: ParseStream) -> Result<Self> {
835            input.step(|cursor| {
836                if let Some((lit, rest)) = cursor.literal() {
837                    return Ok((Lit::new(lit), rest));
838                }
839
840                if let Some((ident, rest)) = cursor.ident() {
841                    let value = ident == "true";
842                    if value || ident == "false" {
843                        let lit_bool = LitBool {
844                            value,
845                            span: ident.span(),
846                        };
847                        return Ok((Lit::Bool(lit_bool), rest));
848                    }
849                }
850
851                if let Some((punct, rest)) = cursor.punct() {
852                    if punct.as_char() == '-' {
853                        if let Some((lit, rest)) = parse_negative_lit(punct, rest) {
854                            return Ok((lit, rest));
855                        }
856                    }
857                }
858
859                Err(cursor.error("expected literal"))
860            })
861        }
862    }
863
864    fn parse_negative_lit(neg: Punct, cursor: Cursor) -> Option<(Lit, Cursor)> {
865        let (lit, rest) = cursor.literal()?;
866
867        let mut span = neg.span();
868        span = span.join(lit.span()).unwrap_or(span);
869
870        let mut repr = lit.to_string();
871        repr.insert(0, '-');
872
873        if let Some((digits, suffix)) = value::parse_lit_int(&repr) {
874            let mut token: Literal = repr.parse().unwrap();
875            token.set_span(span);
876            return Some((
877                Lit::Int(LitInt {
878                    repr: Box::new(LitIntRepr {
879                        token,
880                        digits,
881                        suffix,
882                    }),
883                }),
884                rest,
885            ));
886        }
887
888        let (digits, suffix) = value::parse_lit_float(&repr)?;
889        let mut token: Literal = repr.parse().unwrap();
890        token.set_span(span);
891        Some((
892            Lit::Float(LitFloat {
893                repr: Box::new(LitFloatRepr {
894                    token,
895                    digits,
896                    suffix,
897                }),
898            }),
899            rest,
900        ))
901    }
902
903    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
904    impl Parse for LitStr {
905        fn parse(input: ParseStream) -> Result<Self> {
906            let head = input.fork();
907            match input.parse() {
908                Ok(Lit::Str(lit)) => Ok(lit),
909                _ => Err(head.error("expected string literal")),
910            }
911        }
912    }
913
914    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
915    impl Parse for LitByteStr {
916        fn parse(input: ParseStream) -> Result<Self> {
917            let head = input.fork();
918            match input.parse() {
919                Ok(Lit::ByteStr(lit)) => Ok(lit),
920                _ => Err(head.error("expected byte string literal")),
921            }
922        }
923    }
924
925    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
926    impl Parse for LitCStr {
927        fn parse(input: ParseStream) -> Result<Self> {
928            let head = input.fork();
929            match input.parse() {
930                Ok(Lit::CStr(lit)) => Ok(lit),
931                _ => Err(head.error("expected C string literal")),
932            }
933        }
934    }
935
936    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
937    impl Parse for LitByte {
938        fn parse(input: ParseStream) -> Result<Self> {
939            let head = input.fork();
940            match input.parse() {
941                Ok(Lit::Byte(lit)) => Ok(lit),
942                _ => Err(head.error("expected byte literal")),
943            }
944        }
945    }
946
947    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
948    impl Parse for LitChar {
949        fn parse(input: ParseStream) -> Result<Self> {
950            let head = input.fork();
951            match input.parse() {
952                Ok(Lit::Char(lit)) => Ok(lit),
953                _ => Err(head.error("expected character literal")),
954            }
955        }
956    }
957
958    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
959    impl Parse for LitInt {
960        fn parse(input: ParseStream) -> Result<Self> {
961            let head = input.fork();
962            match input.parse() {
963                Ok(Lit::Int(lit)) => Ok(lit),
964                _ => Err(head.error("expected integer literal")),
965            }
966        }
967    }
968
969    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
970    impl Parse for LitFloat {
971        fn parse(input: ParseStream) -> Result<Self> {
972            let head = input.fork();
973            match input.parse() {
974                Ok(Lit::Float(lit)) => Ok(lit),
975                _ => Err(head.error("expected floating point literal")),
976            }
977        }
978    }
979
980    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
981    impl Parse for LitBool {
982        fn parse(input: ParseStream) -> Result<Self> {
983            let head = input.fork();
984            match input.parse() {
985                Ok(Lit::Bool(lit)) => Ok(lit),
986                _ => Err(head.error("expected boolean literal")),
987            }
988        }
989    }
990
991    fn peek_impl(cursor: Cursor, peek: fn(ParseStream) -> bool) -> bool {
992        let scope = Span::call_site();
993        let unexpected = Rc::new(Cell::new(Unexpected::None));
994        let buffer = crate::parse::new_parse_buffer(scope, cursor, unexpected);
995        peek(&buffer)
996    }
997
998    macro_rules! impl_token {
999        ($display:literal $name:ty) => {
1000            impl Token for $name {
1001                fn peek(cursor: Cursor) -> bool {
1002                    fn peek(input: ParseStream) -> bool {
1003                        <$name as Parse>::parse(input).is_ok()
1004                    }
1005                    peek_impl(cursor, peek)
1006                }
1007
1008                fn display() -> &'static str {
1009                    $display
1010                }
1011            }
1012
1013            impl token::private::Sealed for $name {}
1014        };
1015    }
1016
1017    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);
1018    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);
1019    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);
1020    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);
1021    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);
1022    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);
1023    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);
1024    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);
1025    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);
1026}
1027
1028#[cfg(feature = "printing")]
1029mod printing {
1030    use crate::lit::{LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitInt, LitStr};
1031    use proc_macro2::TokenStream;
1032    use quote::{ToTokens, TokenStreamExt as _};
1033
1034    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
1035    impl ToTokens for LitStr {
1036        fn to_tokens(&self, tokens: &mut TokenStream) {
1037            self.repr.token.to_tokens(tokens);
1038        }
1039    }
1040
1041    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
1042    impl ToTokens for LitByteStr {
1043        fn to_tokens(&self, tokens: &mut TokenStream) {
1044            self.repr.token.to_tokens(tokens);
1045        }
1046    }
1047
1048    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
1049    impl ToTokens for LitCStr {
1050        fn to_tokens(&self, tokens: &mut TokenStream) {
1051            self.repr.token.to_tokens(tokens);
1052        }
1053    }
1054
1055    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
1056    impl ToTokens for LitByte {
1057        fn to_tokens(&self, tokens: &mut TokenStream) {
1058            self.repr.token.to_tokens(tokens);
1059        }
1060    }
1061
1062    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
1063    impl ToTokens for LitChar {
1064        fn to_tokens(&self, tokens: &mut TokenStream) {
1065            self.repr.token.to_tokens(tokens);
1066        }
1067    }
1068
1069    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
1070    impl ToTokens for LitInt {
1071        fn to_tokens(&self, tokens: &mut TokenStream) {
1072            self.repr.token.to_tokens(tokens);
1073        }
1074    }
1075
1076    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
1077    impl ToTokens for LitFloat {
1078        fn to_tokens(&self, tokens: &mut TokenStream) {
1079            self.repr.token.to_tokens(tokens);
1080        }
1081    }
1082
1083    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
1084    impl ToTokens for LitBool {
1085        fn to_tokens(&self, tokens: &mut TokenStream) {
1086            tokens.append(self.token());
1087        }
1088    }
1089}
1090
1091mod value {
1092    use crate::bigint::BigInt;
1093    use crate::lit::{
1094        Lit, LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitFloatRepr, LitInt,
1095        LitIntRepr, LitRepr, LitStr,
1096    };
1097    use alloc::borrow::ToOwned;
1098    use alloc::boxed::Box;
1099    use alloc::ffi::CString;
1100    use alloc::string::{String, ToString};
1101    use alloc::vec::Vec;
1102    use core::char;
1103    use core::ops::{Index, RangeFrom};
1104    use proc_macro2::{Literal, Span};
1105
1106    impl Lit {
1107        /// Interpret a Syn literal from a proc-macro2 literal.
1108        pub fn new(token: Literal) -> Self {
1109            let repr = token.to_string();
1110            Lit::from_str(token, &repr)
1111        }
1112
1113        #[cfg(fuzzing)]
1114        #[doc(hidden)]
1115        pub fn from_str_for_fuzzing(repr: &str) -> Self {
1116            let token = Literal::u8_unsuffixed(0);
1117            Lit::from_str(token, repr)
1118        }
1119
1120        fn from_str(token: Literal, repr: &str) -> Self {
1121            match byte(repr, 0) {
1122                // "...", r"...", r#"..."#
1123                b'"' | b'r' => {
1124                    if let Some((_, suffix)) = parse_lit_str(repr) {
1125                        return Lit::Str(LitStr {
1126                            repr: Box::new(LitRepr { token, suffix }),
1127                        });
1128                    }
1129                }
1130                b'b' => match byte(repr, 1) {
1131                    // b"...", br"...", br#"...#"
1132                    b'"' | b'r' => {
1133                        if let Some((_, suffix)) = parse_lit_byte_str(repr) {
1134                            return Lit::ByteStr(LitByteStr {
1135                                repr: Box::new(LitRepr { token, suffix }),
1136                            });
1137                        }
1138                    }
1139                    // b'...'
1140                    b'\'' => {
1141                        if let Some((_, suffix)) = parse_lit_byte(repr) {
1142                            return Lit::Byte(LitByte {
1143                                repr: Box::new(LitRepr { token, suffix }),
1144                            });
1145                        }
1146                    }
1147                    _ => {}
1148                },
1149                b'c' => match byte(repr, 1) {
1150                    // c"...", cr"...", cr#"..."#
1151                    b'"' | b'r' => {
1152                        if let Some((_, suffix)) = parse_lit_c_str(repr) {
1153                            return Lit::CStr(LitCStr {
1154                                repr: Box::new(LitRepr { token, suffix }),
1155                            });
1156                        }
1157                    }
1158                    _ => {}
1159                },
1160                // '...'
1161                b'\'' => {
1162                    if let Some((_, suffix)) = parse_lit_char(repr) {
1163                        return Lit::Char(LitChar {
1164                            repr: Box::new(LitRepr { token, suffix }),
1165                        });
1166                    }
1167                }
1168                b'0'..=b'9' | b'-' => {
1169                    // 0, 123, 0xFF, 0o77, 0b11
1170                    if let Some((digits, suffix)) = parse_lit_int(repr) {
1171                        return Lit::Int(LitInt {
1172                            repr: Box::new(LitIntRepr {
1173                                token,
1174                                digits,
1175                                suffix,
1176                            }),
1177                        });
1178                    }
1179                    // 1.0, 1e-1, 1e+1
1180                    if let Some((digits, suffix)) = parse_lit_float(repr) {
1181                        return Lit::Float(LitFloat {
1182                            repr: Box::new(LitFloatRepr {
1183                                token,
1184                                digits,
1185                                suffix,
1186                            }),
1187                        });
1188                    }
1189                }
1190                // true, false
1191                b't' | b'f' if repr == "true" || repr == "false" => {
1192                    return Lit::Bool(LitBool {
1193                        value: repr == "true",
1194                        span: token.span(),
1195                    });
1196                }
1197                b'(' if repr == "(/*ERROR*/)" => return Lit::Verbatim(token),
1198                _ => {}
1199            }
1200
1201            Lit::Verbatim(token)
1202        }
1203
1204        pub fn suffix(&self) -> &str {
1205            match self {
1206                Lit::Str(lit) => lit.suffix(),
1207                Lit::ByteStr(lit) => lit.suffix(),
1208                Lit::CStr(lit) => lit.suffix(),
1209                Lit::Byte(lit) => lit.suffix(),
1210                Lit::Char(lit) => lit.suffix(),
1211                Lit::Int(lit) => lit.suffix(),
1212                Lit::Float(lit) => lit.suffix(),
1213                Lit::Bool(_) | Lit::Verbatim(_) => "",
1214            }
1215        }
1216
1217        pub fn span(&self) -> Span {
1218            match self {
1219                Lit::Str(lit) => lit.span(),
1220                Lit::ByteStr(lit) => lit.span(),
1221                Lit::CStr(lit) => lit.span(),
1222                Lit::Byte(lit) => lit.span(),
1223                Lit::Char(lit) => lit.span(),
1224                Lit::Int(lit) => lit.span(),
1225                Lit::Float(lit) => lit.span(),
1226                Lit::Bool(lit) => lit.span,
1227                Lit::Verbatim(lit) => lit.span(),
1228            }
1229        }
1230
1231        pub fn set_span(&mut self, span: Span) {
1232            match self {
1233                Lit::Str(lit) => lit.set_span(span),
1234                Lit::ByteStr(lit) => lit.set_span(span),
1235                Lit::CStr(lit) => lit.set_span(span),
1236                Lit::Byte(lit) => lit.set_span(span),
1237                Lit::Char(lit) => lit.set_span(span),
1238                Lit::Int(lit) => lit.set_span(span),
1239                Lit::Float(lit) => lit.set_span(span),
1240                Lit::Bool(lit) => lit.span = span,
1241                Lit::Verbatim(lit) => lit.set_span(span),
1242            }
1243        }
1244    }
1245
1246    /// Get the byte at offset idx, or a default of `b'\0'` if we're looking
1247    /// past the end of the input buffer.
1248    pub(crate) fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 {
1249        let s = s.as_ref();
1250        if idx < s.len() {
1251            s[idx]
1252        } else {
1253            0
1254        }
1255    }
1256
1257    fn next_chr(s: &str) -> char {
1258        s.chars().next().unwrap_or('\0')
1259    }
1260
1261    // Returns (content, suffix).
1262    pub(crate) fn parse_lit_str(s: &str) -> Option<(Box<str>, Box<str>)> {
1263        match byte(s, 0) {
1264            b'"' => parse_lit_str_cooked(s),
1265            b'r' => parse_lit_str_raw(s),
1266            _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
1267        }
1268    }
1269
1270    fn parse_lit_str_cooked(mut s: &str) -> Option<(Box<str>, Box<str>)> {
1271        {
    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'"');
1272        s = &s[1..];
1273
1274        let mut content = String::new();
1275        'outer: loop {
1276            let ch = match byte(s, 0) {
1277                b'"' => break,
1278                b'\\' => {
1279                    let b = byte(s, 1);
1280                    s = s.get(2..)?;
1281                    match b {
1282                        b'x' => {
1283                            let (byte, rest) = backslash_x(s)?;
1284                            s = rest;
1285                            if byte > 0x7F {
1286                                // invalid \x byte in string literal
1287                                return None;
1288                            }
1289                            char::from(byte)
1290                        }
1291                        b'u' => {
1292                            let (ch, rest) = backslash_u(s)?;
1293                            s = rest;
1294                            ch
1295                        }
1296                        b'n' => '\n',
1297                        b'r' => '\r',
1298                        b't' => '\t',
1299                        b'\\' => '\\',
1300                        b'0' => '\0',
1301                        b'\'' => '\'',
1302                        b'"' => '"',
1303                        b'\r' | b'\n' => loop {
1304                            let b = byte(s, 0);
1305                            match b {
1306                                b' ' | b'\t' | b'\n' | b'\r' => s = &s[1..],
1307                                _ => continue 'outer,
1308                            }
1309                        },
1310                        _ => {
1311                            // unexpected byte after backslash
1312                            return None;
1313                        }
1314                    }
1315                }
1316                b'\r' => {
1317                    if byte(s, 1) != b'\n' {
1318                        // bare carriage return not allowed in string
1319                        return None;
1320                    }
1321                    s = &s[2..];
1322                    '\n'
1323                }
1324                _ => {
1325                    let ch = next_chr(s);
1326                    s = s.get(ch.len_utf8()..)?;
1327                    ch
1328                }
1329            };
1330            content.push(ch);
1331        }
1332
1333        if !s.starts_with('"') {
    ::core::panicking::panic("assertion failed: s.starts_with(\'\"\')")
};assert!(s.starts_with('"'));
1334        let content = content.into_boxed_str();
1335        let suffix = s[1..].to_owned().into_boxed_str();
1336        Some((content, suffix))
1337    }
1338
1339    fn parse_lit_str_raw(mut s: &str) -> Option<(Box<str>, Box<str>)> {
1340        {
    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');
1341        s = &s[1..];
1342
1343        let mut pounds = 0;
1344        loop {
1345            match byte(s, pounds) {
1346                b'#' => pounds += 1,
1347                b'"' => break,
1348                _ => return None,
1349            }
1350        }
1351        let close = s.rfind('"').unwrap();
1352        for end in s.get(close + 1..close + 1 + pounds)?.bytes() {
1353            if end != b'#' {
1354                return None;
1355            }
1356        }
1357
1358        let content = s.get(pounds + 1..close)?.to_owned().into_boxed_str();
1359        let suffix = s[close + 1 + pounds..].to_owned().into_boxed_str();
1360        Some((content, suffix))
1361    }
1362
1363    // Returns (content, suffix).
1364    pub(crate) fn parse_lit_byte_str(s: &str) -> Option<(Vec<u8>, Box<str>)> {
1365        {
    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');
1366        match byte(s, 1) {
1367            b'"' => parse_lit_byte_str_cooked(s),
1368            b'r' => parse_lit_byte_str_raw(s),
1369            _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
1370        }
1371    }
1372
1373    fn parse_lit_byte_str_cooked(mut s: &str) -> Option<(Vec<u8>, Box<str>)> {
1374        {
    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');
1375        {
    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'"');
1376        s = &s[2..];
1377
1378        // We're going to want to have slices which don't respect codepoint boundaries.
1379        let mut v = s.as_bytes();
1380
1381        let mut out = Vec::new();
1382        'outer: loop {
1383            let byte = match byte(v, 0) {
1384                b'"' => break,
1385                b'\\' => {
1386                    let b = byte(v, 1);
1387                    v = v.get(2..)?;
1388                    match b {
1389                        b'x' => {
1390                            let (b, rest) = backslash_x(v)?;
1391                            v = rest;
1392                            b
1393                        }
1394                        b'n' => b'\n',
1395                        b'r' => b'\r',
1396                        b't' => b'\t',
1397                        b'\\' => b'\\',
1398                        b'0' => b'\0',
1399                        b'\'' => b'\'',
1400                        b'"' => b'"',
1401                        b'\r' | b'\n' => loop {
1402                            let byte = byte(v, 0);
1403                            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') {
1404                                v = &v[1..];
1405                            } else {
1406                                continue 'outer;
1407                            }
1408                        },
1409                        _ => {
1410                            // unexpected byte after backslash
1411                            return None;
1412                        }
1413                    }
1414                }
1415                b'\r' => {
1416                    if byte(v, 1) != b'\n' {
1417                        // bare carriage return not allowed in string
1418                        return None;
1419                    }
1420                    v = &v[2..];
1421                    b'\n'
1422                }
1423                b => {
1424                    v = v.get(1..)?;
1425                    b
1426                }
1427            };
1428            out.push(byte);
1429        }
1430
1431        {
    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'"');
1432        let suffix = s[s.len() - v.len() + 1..].to_owned().into_boxed_str();
1433        Some((out, suffix))
1434    }
1435
1436    fn parse_lit_byte_str_raw(s: &str) -> Option<(Vec<u8>, Box<str>)> {
1437        {
    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');
1438        let (value, suffix) = parse_lit_str_raw(&s[1..])?;
1439        Some((String::from(value).into_bytes(), suffix))
1440    }
1441
1442    // Returns (content, suffix).
1443    pub(crate) fn parse_lit_c_str(s: &str) -> Option<(CString, Box<str>)> {
1444        {
    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');
1445        match byte(s, 1) {
1446            b'"' => parse_lit_c_str_cooked(s),
1447            b'r' => parse_lit_c_str_raw(s),
1448            _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
1449        }
1450    }
1451
1452    fn parse_lit_c_str_cooked(mut s: &str) -> Option<(CString, Box<str>)> {
1453        {
    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');
1454        {
    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'"');
1455        s = &s[2..];
1456
1457        // We're going to want to have slices which don't respect codepoint boundaries.
1458        let mut v = s.as_bytes();
1459
1460        let mut out = Vec::new();
1461        'outer: loop {
1462            let byte = match byte(v, 0) {
1463                b'"' => break,
1464                b'\\' => {
1465                    let b = byte(v, 1);
1466                    v = v.get(2..)?;
1467                    match b {
1468                        b'x' => {
1469                            let (b, rest) = backslash_x(v)?;
1470                            if b == 0 {
1471                                // \x00 is not allowed in C-string literal
1472                                return None;
1473                            }
1474                            v = rest;
1475                            b
1476                        }
1477                        b'u' => {
1478                            let (ch, rest) = backslash_u(v)?;
1479                            if ch == '\0' {
1480                                // \u{0} is not allowed in C-string literal
1481                                return None;
1482                            }
1483                            v = rest;
1484                            out.extend_from_slice(ch.encode_utf8(&mut [0u8; 4]).as_bytes());
1485                            continue 'outer;
1486                        }
1487                        b'n' => b'\n',
1488                        b'r' => b'\r',
1489                        b't' => b'\t',
1490                        b'\\' => b'\\',
1491                        b'\'' => b'\'',
1492                        b'"' => b'"',
1493                        b'\r' | b'\n' => loop {
1494                            let byte = byte(v, 0);
1495                            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') {
1496                                v = &v[1..];
1497                            } else {
1498                                continue 'outer;
1499                            }
1500                        },
1501                        _ => {
1502                            // unexpected byte after backslash
1503                            return None;
1504                        }
1505                    }
1506                }
1507                b'\r' => {
1508                    if byte(v, 1) != b'\n' {
1509                        // bare carriage return not allowed in string
1510                        return None;
1511                    }
1512                    v = &v[2..];
1513                    b'\n'
1514                }
1515                b => {
1516                    v = v.get(1..)?;
1517                    b
1518                }
1519            };
1520            out.push(byte);
1521        }
1522
1523        {
    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'"');
1524        let suffix = s[s.len() - v.len() + 1..].to_owned().into_boxed_str();
1525        let cstring = CString::new(out).ok()?;
1526        Some((cstring, suffix))
1527    }
1528
1529    fn parse_lit_c_str_raw(s: &str) -> Option<(CString, Box<str>)> {
1530        {
    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');
1531        let (value, suffix) = parse_lit_str_raw(&s[1..])?;
1532        let cstring = CString::new(String::from(value)).ok()?;
1533        Some((cstring, suffix))
1534    }
1535
1536    // Returns (value, suffix).
1537    pub(crate) fn parse_lit_byte(s: &str) -> Option<(u8, Box<str>)> {
1538        {
    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');
1539        {
    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'\'');
1540
1541        // We're going to want to have slices which don't respect codepoint boundaries.
1542        let mut v = &s.as_bytes()[2..];
1543
1544        let b = match byte(v, 0) {
1545            b'\\' => {
1546                let b = byte(v, 1);
1547                v = v.get(2..)?;
1548                match b {
1549                    b'x' => {
1550                        let (b, rest) = backslash_x(v)?;
1551                        v = rest;
1552                        b
1553                    }
1554                    b'n' => b'\n',
1555                    b'r' => b'\r',
1556                    b't' => b'\t',
1557                    b'\\' => b'\\',
1558                    b'0' => b'\0',
1559                    b'\'' => b'\'',
1560                    b'"' => b'"',
1561                    _ => {
1562                        // unexpected byte after backslash
1563                        return None;
1564                    }
1565                }
1566            }
1567            b => {
1568                v = v.get(1..)?;
1569                b
1570            }
1571        };
1572
1573        if byte(v, 0) != b'\'' {
1574            return None;
1575        }
1576
1577        let suffix = s[s.len() - v.len() + 1..].to_owned().into_boxed_str();
1578        Some((b, suffix))
1579    }
1580
1581    // Returns (value, suffix).
1582    pub(crate) fn parse_lit_char(mut s: &str) -> Option<(char, Box<str>)> {
1583        {
    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'\'');
1584        s = &s[1..];
1585
1586        let ch = match byte(s, 0) {
1587            b'\\' => {
1588                let b = byte(s, 1);
1589                s = s.get(2..)?;
1590                match b {
1591                    b'x' => {
1592                        let (byte, rest) = backslash_x(s)?;
1593                        s = rest;
1594                        if byte > 0x7F {
1595                            // invalid \x byte in character literal
1596                            return None;
1597                        }
1598                        char::from(byte)
1599                    }
1600                    b'u' => {
1601                        let (ch, rest) = backslash_u(s)?;
1602                        s = rest;
1603                        ch
1604                    }
1605                    b'n' => '\n',
1606                    b'r' => '\r',
1607                    b't' => '\t',
1608                    b'\\' => '\\',
1609                    b'0' => '\0',
1610                    b'\'' => '\'',
1611                    b'"' => '"',
1612                    _ => {
1613                        // unexpected byte after backslash
1614                        return None;
1615                    }
1616                }
1617            }
1618            _ => {
1619                let ch = next_chr(s);
1620                s = s.get(ch.len_utf8()..)?;
1621                ch
1622            }
1623        };
1624
1625        if byte(s, 0) != b'\'' {
1626            return None;
1627        }
1628
1629        let suffix = s[1..].to_owned().into_boxed_str();
1630        Some((ch, suffix))
1631    }
1632
1633    fn backslash_x<S>(s: &S) -> Option<(u8, &S)>
1634    where
1635        S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
1636    {
1637        let mut ch = 0;
1638        let b0 = byte(s, 0);
1639        let b1 = byte(s, 1);
1640        ch += 0x10
1641            * match b0 {
1642                b'0'..=b'9' => b0 - b'0',
1643                b'a'..=b'f' => 10 + (b0 - b'a'),
1644                b'A'..=b'F' => 10 + (b0 - b'A'),
1645                _ => return None,
1646            };
1647        ch += match b1 {
1648            b'0'..=b'9' => b1 - b'0',
1649            b'a'..=b'f' => 10 + (b1 - b'a'),
1650            b'A'..=b'F' => 10 + (b1 - b'A'),
1651            _ => return None,
1652        };
1653        Some((ch, &s[2..]))
1654    }
1655
1656    fn backslash_u<S>(mut s: &S) -> Option<(char, &S)>
1657    where
1658        S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
1659    {
1660        if byte(s, 0) != b'{' {
1661            return None;
1662        }
1663        s = &s[1..];
1664
1665        let mut ch = 0;
1666        let mut digits = 0;
1667        loop {
1668            let b = byte(s, 0);
1669            let digit = match b {
1670                b'0'..=b'9' => b - b'0',
1671                b'a'..=b'f' => 10 + b - b'a',
1672                b'A'..=b'F' => 10 + b - b'A',
1673                b'_' if digits > 0 => {
1674                    s = &s[1..];
1675                    continue;
1676                }
1677                b'}' if digits == 0 => return None,
1678                b'}' => break,
1679                _ => return None,
1680            };
1681            if digits == 6 {
1682                return None;
1683            }
1684            ch *= 0x10;
1685            ch += u32::from(digit);
1686            digits += 1;
1687            s = &s[1..];
1688        }
1689        if byte(s, 0) != b'}' {
1690            return None;
1691        }
1692        s = &s[1..];
1693
1694        let ch = char::from_u32(ch)?;
1695        Some((ch, s))
1696    }
1697
1698    // Returns base 10 digits and suffix.
1699    pub(crate) fn parse_lit_int(mut s: &str) -> Option<(Box<str>, Box<str>)> {
1700        let negative = byte(s, 0) == b'-';
1701        if negative {
1702            s = &s[1..];
1703        }
1704
1705        let base = match (byte(s, 0), byte(s, 1)) {
1706            (b'0', b'x') => {
1707                s = &s[2..];
1708                16
1709            }
1710            (b'0', b'o') => {
1711                s = &s[2..];
1712                8
1713            }
1714            (b'0', b'b') => {
1715                s = &s[2..];
1716                2
1717            }
1718            (b'0'..=b'9', _) => 10,
1719            _ => return None,
1720        };
1721
1722        let mut value = BigInt::new();
1723        let mut has_digit = false;
1724        'outer: loop {
1725            let b = byte(s, 0);
1726            let digit = match b {
1727                b'0'..=b'9' => b - b'0',
1728                b'a'..=b'f' if base > 10 => b - b'a' + 10,
1729                b'A'..=b'F' if base > 10 => b - b'A' + 10,
1730                b'_' => {
1731                    s = &s[1..];
1732                    continue;
1733                }
1734                // If looking at a floating point literal, we don't want to
1735                // consider it an integer.
1736                b'.' if base == 10 => return None,
1737                b'e' | b'E' if base == 10 => {
1738                    let mut has_exp = false;
1739                    for (i, b) in s[1..].bytes().enumerate() {
1740                        match b {
1741                            b'_' => {}
1742                            b'-' | b'+' => return None,
1743                            b'0'..=b'9' => has_exp = true,
1744                            _ => {
1745                                let suffix = &s[1 + i..];
1746                                if has_exp && crate::ident::xid_ok(suffix) {
1747                                    return None;
1748                                } else {
1749                                    break 'outer;
1750                                }
1751                            }
1752                        }
1753                    }
1754                    if has_exp {
1755                        return None;
1756                    } else {
1757                        break;
1758                    }
1759                }
1760                _ => break,
1761            };
1762
1763            if digit >= base {
1764                return None;
1765            }
1766
1767            has_digit = true;
1768            value *= base;
1769            value += digit;
1770            s = &s[1..];
1771        }
1772
1773        if !has_digit {
1774            return None;
1775        }
1776
1777        let suffix = s;
1778        if suffix.is_empty() || crate::ident::xid_ok(suffix) {
1779            let mut repr = value.to_string();
1780            if negative {
1781                repr.insert(0, '-');
1782            }
1783            Some((repr.into_boxed_str(), suffix.to_owned().into_boxed_str()))
1784        } else {
1785            None
1786        }
1787    }
1788
1789    // Returns base 10 digits and suffix.
1790    pub(crate) fn parse_lit_float(input: &str) -> Option<(Box<str>, Box<str>)> {
1791        // Rust's floating point literals are very similar to the ones parsed by
1792        // the standard library, except that rust's literals can contain
1793        // ignorable underscores. Let's remove those underscores.
1794
1795        let mut bytes = input.to_owned().into_bytes();
1796
1797        let start = (*bytes.first()? == b'-') as usize;
1798        match bytes.get(start)? {
1799            b'0'..=b'9' => {}
1800            _ => return None,
1801        }
1802
1803        let mut read = start;
1804        let mut write = start;
1805        let mut has_dot = false;
1806        let mut has_e = false;
1807        let mut has_sign = false;
1808        let mut has_exponent = false;
1809        while read < bytes.len() {
1810            match bytes[read] {
1811                b'_' => {
1812                    // Don't increase write
1813                    read += 1;
1814                    continue;
1815                }
1816                b'0'..=b'9' => {
1817                    if has_e {
1818                        has_exponent = true;
1819                    }
1820                    bytes[write] = bytes[read];
1821                }
1822                b'.' => {
1823                    if has_e || has_dot {
1824                        return None;
1825                    }
1826                    has_dot = true;
1827                    bytes[write] = b'.';
1828                }
1829                b'e' | b'E' => {
1830                    match bytes[read + 1..]
1831                        .iter()
1832                        .find(|b| **b != b'_')
1833                        .unwrap_or(&b'\0')
1834                    {
1835                        b'-' | b'+' | b'0'..=b'9' => {}
1836                        _ => break,
1837                    }
1838                    if has_e {
1839                        if has_exponent {
1840                            break;
1841                        } else {
1842                            return None;
1843                        }
1844                    }
1845                    has_e = true;
1846                    bytes[write] = b'e';
1847                }
1848                b'-' | b'+' => {
1849                    if has_sign || has_exponent || !has_e {
1850                        return None;
1851                    }
1852                    has_sign = true;
1853                    if bytes[read] == b'-' {
1854                        bytes[write] = bytes[read];
1855                    } else {
1856                        // Omit '+'
1857                        read += 1;
1858                        continue;
1859                    }
1860                }
1861                _ => break,
1862            }
1863            read += 1;
1864            write += 1;
1865        }
1866
1867        if has_e && !has_exponent {
1868            return None;
1869        }
1870
1871        let mut digits = String::from_utf8(bytes).unwrap();
1872        let suffix = digits.split_off(read);
1873        digits.truncate(write);
1874        if suffix.is_empty() || crate::ident::xid_ok(&suffix) {
1875            Some((digits.into_boxed_str(), suffix.into_boxed_str()))
1876        } else {
1877            None
1878        }
1879    }
1880}