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