syn/
lit.rs

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