syn/
lit.rs

1use proc_macro2::{Literal, Span};
2use std::fmt::{self, Display};
3use std::str::{self, FromStr};
4
5#[cfg(feature = "printing")]
6use proc_macro2::Ident;
7
8#[cfg(feature = "parsing")]
9use proc_macro2::TokenStream;
10
11use proc_macro2::TokenTree;
12
13#[cfg(feature = "extra-traits")]
14use std::hash::{Hash, Hasher};
15
16#[cfg(feature = "parsing")]
17use crate::lookahead;
18#[cfg(feature = "parsing")]
19use crate::parse::{Parse, Parser};
20use crate::{Error, Result};
21
22ast_enum_of_structs! {
23    /// A Rust literal such as a string or integer or boolean.
24    ///
25    /// *This type is available if Syn is built with the `"derive"` or `"full"`
26    /// feature.*
27    ///
28    /// # Syntax tree enum
29    ///
30    /// This type is a [syntax tree enum].
31    ///
32    /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
33    //
34    // TODO: change syntax-tree-enum link to an intra rustdoc link, currently
35    // blocked on https://github.com/rust-lang/rust/issues/62833
36    pub enum Lit #manual_extra_traits {
37        /// A UTF-8 string literal: `"foo"`.
38        Str(LitStr),
39
40        /// A byte string literal: `b"foo"`.
41        ByteStr(LitByteStr),
42
43        /// A byte literal: `b'f'`.
44        Byte(LitByte),
45
46        /// A character literal: `'a'`.
47        Char(LitChar),
48
49        /// An integer literal: `1` or `1u16`.
50        Int(LitInt),
51
52        /// A floating point literal: `1f64` or `1.0e10f64`.
53        ///
54        /// Must be finite. May not be infinte or NaN.
55        Float(LitFloat),
56
57        /// A boolean literal: `true` or `false`.
58        Bool(LitBool),
59
60        /// A raw token literal not interpreted by Syn.
61        Verbatim(Literal),
62    }
63}
64
65ast_struct! {
66    /// A UTF-8 string literal: `"foo"`.
67    ///
68    /// *This type is available if Syn is built with the `"derive"` or
69    /// `"full"` feature.*
70    pub struct LitStr #manual_extra_traits_debug {
71        repr: Box<LitStrRepr>,
72    }
73}
74
75#[cfg_attr(feature = "clone-impls", derive(Clone))]
76struct LitStrRepr {
77    token: Literal,
78    suffix: Box<str>,
79}
80
81ast_struct! {
82    /// A byte string literal: `b"foo"`.
83    ///
84    /// *This type is available if Syn is built with the `"derive"` or
85    /// `"full"` feature.*
86    pub struct LitByteStr #manual_extra_traits_debug {
87        token: Literal,
88    }
89}
90
91ast_struct! {
92    /// A byte literal: `b'f'`.
93    ///
94    /// *This type is available if Syn is built with the `"derive"` or
95    /// `"full"` feature.*
96    pub struct LitByte #manual_extra_traits_debug {
97        token: Literal,
98    }
99}
100
101ast_struct! {
102    /// A character literal: `'a'`.
103    ///
104    /// *This type is available if Syn is built with the `"derive"` or
105    /// `"full"` feature.*
106    pub struct LitChar #manual_extra_traits_debug {
107        token: Literal,
108    }
109}
110
111ast_struct! {
112    /// An integer literal: `1` or `1u16`.
113    ///
114    /// *This type is available if Syn is built with the `"derive"` or
115    /// `"full"` feature.*
116    pub struct LitInt #manual_extra_traits_debug {
117        repr: Box<LitIntRepr>,
118    }
119}
120
121#[cfg_attr(feature = "clone-impls", derive(Clone))]
122struct LitIntRepr {
123    token: Literal,
124    digits: Box<str>,
125    suffix: Box<str>,
126}
127
128ast_struct! {
129    /// A floating point literal: `1f64` or `1.0e10f64`.
130    ///
131    /// Must be finite. May not be infinte or NaN.
132    ///
133    /// *This type is available if Syn is built with the `"derive"` or
134    /// `"full"` feature.*
135    pub struct LitFloat #manual_extra_traits_debug {
136        repr: Box<LitFloatRepr>,
137    }
138}
139
140#[cfg_attr(feature = "clone-impls", derive(Clone))]
141struct LitFloatRepr {
142    token: Literal,
143    digits: Box<str>,
144    suffix: Box<str>,
145}
146
147ast_struct! {
148    /// A boolean literal: `true` or `false`.
149    ///
150    /// *This type is available if Syn is built with the `"derive"` or
151    /// `"full"` feature.*
152    pub struct LitBool #manual_extra_traits_debug {
153        pub value: bool,
154        pub span: Span,
155    }
156}
157
158#[cfg(feature = "extra-traits")]
159impl Eq for Lit {}
160
161#[cfg(feature = "extra-traits")]
162impl PartialEq for Lit {
163    fn eq(&self, other: &Self) -> bool {
164        match (self, other) {
165            (Lit::Str(this), Lit::Str(other)) => this == other,
166            (Lit::ByteStr(this), Lit::ByteStr(other)) => this == other,
167            (Lit::Byte(this), Lit::Byte(other)) => this == other,
168            (Lit::Char(this), Lit::Char(other)) => this == other,
169            (Lit::Int(this), Lit::Int(other)) => this == other,
170            (Lit::Float(this), Lit::Float(other)) => this == other,
171            (Lit::Bool(this), Lit::Bool(other)) => this == other,
172            (Lit::Verbatim(this), Lit::Verbatim(other)) => this.to_string() == other.to_string(),
173            _ => false,
174        }
175    }
176}
177
178#[cfg(feature = "extra-traits")]
179impl Hash for Lit {
180    fn hash<H>(&self, hash: &mut H)
181    where
182        H: Hasher,
183    {
184        match self {
185            Lit::Str(lit) => {
186                hash.write_u8(0);
187                lit.hash(hash);
188            }
189            Lit::ByteStr(lit) => {
190                hash.write_u8(1);
191                lit.hash(hash);
192            }
193            Lit::Byte(lit) => {
194                hash.write_u8(2);
195                lit.hash(hash);
196            }
197            Lit::Char(lit) => {
198                hash.write_u8(3);
199                lit.hash(hash);
200            }
201            Lit::Int(lit) => {
202                hash.write_u8(4);
203                lit.hash(hash);
204            }
205            Lit::Float(lit) => {
206                hash.write_u8(5);
207                lit.hash(hash);
208            }
209            Lit::Bool(lit) => {
210                hash.write_u8(6);
211                lit.hash(hash);
212            }
213            Lit::Verbatim(lit) => {
214                hash.write_u8(7);
215                lit.to_string().hash(hash);
216            }
217        }
218    }
219}
220
221impl LitStr {
222    pub fn new(value: &str, span: Span) -> Self {
223        let mut lit = Literal::string(value);
224        lit.set_span(span);
225        LitStr {
226            repr: Box::new(LitStrRepr {
227                token: lit,
228                suffix: Box::<str>::default(),
229            }),
230        }
231    }
232
233    pub fn value(&self) -> String {
234        let (value, _) = value::parse_lit_str(&self.repr.token.to_string());
235        String::from(value)
236    }
237
238    /// Parse a syntax tree node from the content of this string literal.
239    ///
240    /// All spans in the syntax tree will point to the span of this `LitStr`.
241    ///
242    /// # Example
243    ///
244    /// ```
245    /// use proc_macro2::Span;
246    /// use syn::{Attribute, Error, Ident, Lit, Meta, MetaNameValue, Path, Result};
247    ///
248    /// // Parses the path from an attribute that looks like:
249    /// //
250    /// //     #[path = "a::b::c"]
251    /// //
252    /// // or returns `None` if the input is some other attribute.
253    /// fn get_path(attr: &Attribute) -> Result<Option<Path>> {
254    ///     if !attr.path.is_ident("path") {
255    ///         return Ok(None);
256    ///     }
257    ///
258    ///     match attr.parse_meta()? {
259    ///         Meta::NameValue(MetaNameValue { lit: Lit::Str(lit_str), .. }) => {
260    ///             lit_str.parse().map(Some)
261    ///         }
262    ///         _ => {
263    ///             let message = "expected #[path = \"...\"]";
264    ///             Err(Error::new_spanned(attr, message))
265    ///         }
266    ///     }
267    /// }
268    /// ```
269    #[cfg(feature = "parsing")]
270    pub fn parse<T: Parse>(&self) -> Result<T> {
271        self.parse_with(T::parse)
272    }
273
274    /// Invoke parser on the content of this string literal.
275    ///
276    /// All spans in the syntax tree will point to the span of this `LitStr`.
277    ///
278    /// # Example
279    ///
280    /// ```
281    /// # use proc_macro2::Span;
282    /// # use syn::{LitStr, Result};
283    /// #
284    /// # fn main() -> Result<()> {
285    /// #     let lit_str = LitStr::new("a::b::c", Span::call_site());
286    /// #
287    /// #     const IGNORE: &str = stringify! {
288    /// let lit_str: LitStr = /* ... */;
289    /// #     };
290    ///
291    /// // Parse a string literal like "a::b::c" into a Path, not allowing
292    /// // generic arguments on any of the path segments.
293    /// let basic_path = lit_str.parse_with(syn::Path::parse_mod_style)?;
294    /// #
295    /// #     Ok(())
296    /// # }
297    /// ```
298    #[cfg(feature = "parsing")]
299    pub fn parse_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
300        use proc_macro2::Group;
301
302        // Token stream with every span replaced by the given one.
303        fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
304            stream
305                .into_iter()
306                .map(|token| respan_token_tree(token, span))
307                .collect()
308        }
309
310        // Token tree with every span replaced by the given one.
311        fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
312            match &mut token {
313                TokenTree::Group(g) => {
314                    let stream = respan_token_stream(g.stream(), span);
315                    *g = Group::new(g.delimiter(), stream);
316                    g.set_span(span);
317                }
318                other => other.set_span(span),
319            }
320            token
321        }
322
323        // Parse string literal into a token stream with every span equal to the
324        // original literal's span.
325        let mut tokens = crate::parse_str(&self.value())?;
326        tokens = respan_token_stream(tokens, self.span());
327
328        parser.parse2(tokens)
329    }
330
331    pub fn span(&self) -> Span {
332        self.repr.token.span()
333    }
334
335    pub fn set_span(&mut self, span: Span) {
336        self.repr.token.set_span(span)
337    }
338
339    pub fn suffix(&self) -> &str {
340        &self.repr.suffix
341    }
342}
343
344impl LitByteStr {
345    pub fn new(value: &[u8], span: Span) -> Self {
346        let mut token = Literal::byte_string(value);
347        token.set_span(span);
348        LitByteStr { token }
349    }
350
351    pub fn value(&self) -> Vec<u8> {
352        value::parse_lit_byte_str(&self.token.to_string())
353    }
354
355    pub fn span(&self) -> Span {
356        self.token.span()
357    }
358
359    pub fn set_span(&mut self, span: Span) {
360        self.token.set_span(span)
361    }
362}
363
364impl LitByte {
365    pub fn new(value: u8, span: Span) -> Self {
366        let mut token = Literal::u8_suffixed(value);
367        token.set_span(span);
368        LitByte { token }
369    }
370
371    pub fn value(&self) -> u8 {
372        value::parse_lit_byte(&self.token.to_string())
373    }
374
375    pub fn span(&self) -> Span {
376        self.token.span()
377    }
378
379    pub fn set_span(&mut self, span: Span) {
380        self.token.set_span(span)
381    }
382}
383
384impl LitChar {
385    pub fn new(value: char, span: Span) -> Self {
386        let mut token = Literal::character(value);
387        token.set_span(span);
388        LitChar { token }
389    }
390
391    pub fn value(&self) -> char {
392        value::parse_lit_char(&self.token.to_string())
393    }
394
395    pub fn span(&self) -> Span {
396        self.token.span()
397    }
398
399    pub fn set_span(&mut self, span: Span) {
400        self.token.set_span(span)
401    }
402}
403
404impl LitInt {
405    pub fn new(repr: &str, span: Span) -> Self {
406        if let Some((digits, suffix)) = value::parse_lit_int(repr) {
407            let mut token = value::to_literal(repr);
408            token.set_span(span);
409            LitInt {
410                repr: Box::new(LitIntRepr {
411                    token,
412                    digits,
413                    suffix,
414                }),
415            }
416        } else {
417            panic!("Not an integer literal: `{}`", repr);
418        }
419    }
420
421    pub fn base10_digits(&self) -> &str {
422        &self.repr.digits
423    }
424
425    /// Parses the literal into a selected number type.
426    ///
427    /// This is equivalent to `lit.base10_digits().parse()` except that the
428    /// resulting errors will be correctly spanned to point to the literal token
429    /// in the macro input.
430    ///
431    /// ```
432    /// use syn::LitInt;
433    /// use syn::parse::{Parse, ParseStream, Result};
434    ///
435    /// struct Port {
436    ///     value: u16,
437    /// }
438    ///
439    /// impl Parse for Port {
440    ///     fn parse(input: ParseStream) -> Result<Self> {
441    ///         let lit: LitInt = input.parse()?;
442    ///         let value = lit.base10_parse::<u16>()?;
443    ///         Ok(Port { value })
444    ///     }
445    /// }
446    /// ```
447    pub fn base10_parse<N>(&self) -> Result<N>
448    where
449        N: FromStr,
450        N::Err: Display,
451    {
452        self.base10_digits()
453            .parse()
454            .map_err(|err| Error::new(self.span(), err))
455    }
456
457    pub fn suffix(&self) -> &str {
458        &self.repr.suffix
459    }
460
461    pub fn span(&self) -> Span {
462        self.repr.token.span()
463    }
464
465    pub fn set_span(&mut self, span: Span) {
466        self.repr.token.set_span(span)
467    }
468}
469
470impl From<Literal> for LitInt {
471    fn from(token: Literal) -> Self {
472        let repr = token.to_string();
473        if let Some((digits, suffix)) = value::parse_lit_int(&repr) {
474            LitInt {
475                repr: Box::new(LitIntRepr {
476                    token,
477                    digits,
478                    suffix,
479                }),
480            }
481        } else {
482            panic!("Not an integer literal: `{}`", repr);
483        }
484    }
485}
486
487impl Display for LitInt {
488    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
489        self.repr.token.fmt(formatter)
490    }
491}
492
493impl LitFloat {
494    pub fn new(repr: &str, span: Span) -> Self {
495        if let Some((digits, suffix)) = value::parse_lit_float(repr) {
496            let mut token = value::to_literal(repr);
497            token.set_span(span);
498            LitFloat {
499                repr: Box::new(LitFloatRepr {
500                    token,
501                    digits,
502                    suffix,
503                }),
504            }
505        } else {
506            panic!("Not a float literal: `{}`", repr);
507        }
508    }
509
510    pub fn base10_digits(&self) -> &str {
511        &self.repr.digits
512    }
513
514    pub fn base10_parse<N>(&self) -> Result<N>
515    where
516        N: FromStr,
517        N::Err: Display,
518    {
519        self.base10_digits()
520            .parse()
521            .map_err(|err| Error::new(self.span(), err))
522    }
523
524    pub fn suffix(&self) -> &str {
525        &self.repr.suffix
526    }
527
528    pub fn span(&self) -> Span {
529        self.repr.token.span()
530    }
531
532    pub fn set_span(&mut self, span: Span) {
533        self.repr.token.set_span(span)
534    }
535}
536
537impl From<Literal> for LitFloat {
538    fn from(token: Literal) -> Self {
539        let repr = token.to_string();
540        if let Some((digits, suffix)) = value::parse_lit_float(&repr) {
541            LitFloat {
542                repr: Box::new(LitFloatRepr {
543                    token,
544                    digits,
545                    suffix,
546                }),
547            }
548        } else {
549            panic!("Not a float literal: `{}`", repr);
550        }
551    }
552}
553
554impl Display for LitFloat {
555    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
556        self.repr.token.fmt(formatter)
557    }
558}
559
560#[cfg(feature = "extra-traits")]
561mod debug_impls {
562    use super::*;
563    use std::fmt::{self, Debug};
564
565    impl Debug for LitStr {
566        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
567            formatter
568                .debug_struct("LitStr")
569                .field("token", &format_args!("{}", self.repr.token))
570                .finish()
571        }
572    }
573
574    impl Debug for LitByteStr {
575        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
576            formatter
577                .debug_struct("LitByteStr")
578                .field("token", &format_args!("{}", self.token))
579                .finish()
580        }
581    }
582
583    impl Debug for LitByte {
584        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
585            formatter
586                .debug_struct("LitByte")
587                .field("token", &format_args!("{}", self.token))
588                .finish()
589        }
590    }
591
592    impl Debug for LitChar {
593        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
594            formatter
595                .debug_struct("LitChar")
596                .field("token", &format_args!("{}", self.token))
597                .finish()
598        }
599    }
600
601    impl Debug for LitInt {
602        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
603            formatter
604                .debug_struct("LitInt")
605                .field("token", &format_args!("{}", self.repr.token))
606                .finish()
607        }
608    }
609
610    impl Debug for LitFloat {
611        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
612            formatter
613                .debug_struct("LitFloat")
614                .field("token", &format_args!("{}", self.repr.token))
615                .finish()
616        }
617    }
618
619    impl Debug for LitBool {
620        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
621            formatter
622                .debug_struct("LitBool")
623                .field("value", &self.value)
624                .finish()
625        }
626    }
627}
628
629macro_rules! lit_extra_traits {
630    ($ty:ident, $($field:ident).+) => {
631        #[cfg(feature = "extra-traits")]
632        impl Eq for $ty {}
633
634        #[cfg(feature = "extra-traits")]
635        impl PartialEq for $ty {
636            fn eq(&self, other: &Self) -> bool {
637                self.$($field).+.to_string() == other.$($field).+.to_string()
638            }
639        }
640
641        #[cfg(feature = "extra-traits")]
642        impl Hash for $ty {
643            fn hash<H>(&self, state: &mut H)
644            where
645                H: Hasher,
646            {
647                self.$($field).+.to_string().hash(state);
648            }
649        }
650
651        #[cfg(feature = "parsing")]
652        #[doc(hidden)]
653        #[allow(non_snake_case)]
654        pub fn $ty(marker: lookahead::TokenMarker) -> $ty {
655            match marker {}
656        }
657    };
658}
659
660lit_extra_traits!(LitStr, repr.token);
661lit_extra_traits!(LitByteStr, token);
662lit_extra_traits!(LitByte, token);
663lit_extra_traits!(LitChar, token);
664lit_extra_traits!(LitInt, repr.token);
665lit_extra_traits!(LitFloat, repr.token);
666lit_extra_traits!(LitBool, value);
667
668ast_enum! {
669    /// The style of a string literal, either plain quoted or a raw string like
670    /// `r##"data"##`.
671    ///
672    /// *This type is available if Syn is built with the `"derive"` or `"full"`
673    /// feature.*
674    pub enum StrStyle #no_visit {
675        /// An ordinary string like `"data"`.
676        Cooked,
677        /// A raw string like `r##"data"##`.
678        ///
679        /// The unsigned integer is the number of `#` symbols used.
680        Raw(usize),
681    }
682}
683
684#[cfg(feature = "parsing")]
685#[doc(hidden)]
686#[allow(non_snake_case)]
687pub fn Lit(marker: lookahead::TokenMarker) -> Lit {
688    match marker {}
689}
690
691#[cfg(feature = "parsing")]
692pub mod parsing {
693    use super::*;
694    use crate::parse::{Parse, ParseStream, Result};
695
696    impl Parse for Lit {
697        fn parse(input: ParseStream) -> Result<Self> {
698            input.step(|cursor| {
699                if let Some((lit, rest)) = cursor.literal() {
700                    return Ok((Lit::new(lit), rest));
701                }
702                while let Some((ident, rest)) = cursor.ident() {
703                    let value = if ident == "true" {
704                        true
705                    } else if ident == "false" {
706                        false
707                    } else {
708                        break;
709                    };
710                    let lit_bool = LitBool {
711                        value,
712                        span: ident.span(),
713                    };
714                    return Ok((Lit::Bool(lit_bool), rest));
715                }
716                Err(cursor.error("expected literal"))
717            })
718        }
719    }
720
721    impl Parse for LitStr {
722        fn parse(input: ParseStream) -> Result<Self> {
723            let head = input.fork();
724            match input.parse()? {
725                Lit::Str(lit) => Ok(lit),
726                _ => Err(head.error("expected string literal")),
727            }
728        }
729    }
730
731    impl Parse for LitByteStr {
732        fn parse(input: ParseStream) -> Result<Self> {
733            let head = input.fork();
734            match input.parse()? {
735                Lit::ByteStr(lit) => Ok(lit),
736                _ => Err(head.error("expected byte string literal")),
737            }
738        }
739    }
740
741    impl Parse for LitByte {
742        fn parse(input: ParseStream) -> Result<Self> {
743            let head = input.fork();
744            match input.parse()? {
745                Lit::Byte(lit) => Ok(lit),
746                _ => Err(head.error("expected byte literal")),
747            }
748        }
749    }
750
751    impl Parse for LitChar {
752        fn parse(input: ParseStream) -> Result<Self> {
753            let head = input.fork();
754            match input.parse()? {
755                Lit::Char(lit) => Ok(lit),
756                _ => Err(head.error("expected character literal")),
757            }
758        }
759    }
760
761    impl Parse for LitInt {
762        fn parse(input: ParseStream) -> Result<Self> {
763            let head = input.fork();
764            match input.parse()? {
765                Lit::Int(lit) => Ok(lit),
766                _ => Err(head.error("expected integer literal")),
767            }
768        }
769    }
770
771    impl Parse for LitFloat {
772        fn parse(input: ParseStream) -> Result<Self> {
773            let head = input.fork();
774            match input.parse()? {
775                Lit::Float(lit) => Ok(lit),
776                _ => Err(head.error("expected floating point literal")),
777            }
778        }
779    }
780
781    impl Parse for LitBool {
782        fn parse(input: ParseStream) -> Result<Self> {
783            let head = input.fork();
784            match input.parse()? {
785                Lit::Bool(lit) => Ok(lit),
786                _ => Err(head.error("expected boolean literal")),
787            }
788        }
789    }
790}
791
792#[cfg(feature = "printing")]
793mod printing {
794    use super::*;
795    use proc_macro2::TokenStream;
796    use quote::{ToTokens, TokenStreamExt};
797
798    impl ToTokens for LitStr {
799        fn to_tokens(&self, tokens: &mut TokenStream) {
800            self.repr.token.to_tokens(tokens);
801        }
802    }
803
804    impl ToTokens for LitByteStr {
805        fn to_tokens(&self, tokens: &mut TokenStream) {
806            self.token.to_tokens(tokens);
807        }
808    }
809
810    impl ToTokens for LitByte {
811        fn to_tokens(&self, tokens: &mut TokenStream) {
812            self.token.to_tokens(tokens);
813        }
814    }
815
816    impl ToTokens for LitChar {
817        fn to_tokens(&self, tokens: &mut TokenStream) {
818            self.token.to_tokens(tokens);
819        }
820    }
821
822    impl ToTokens for LitInt {
823        fn to_tokens(&self, tokens: &mut TokenStream) {
824            self.repr.token.to_tokens(tokens);
825        }
826    }
827
828    impl ToTokens for LitFloat {
829        fn to_tokens(&self, tokens: &mut TokenStream) {
830            self.repr.token.to_tokens(tokens);
831        }
832    }
833
834    impl ToTokens for LitBool {
835        fn to_tokens(&self, tokens: &mut TokenStream) {
836            let s = if self.value { "true" } else { "false" };
837            tokens.append(Ident::new(s, self.span));
838        }
839    }
840}
841
842mod value {
843    use super::*;
844    use crate::bigint::BigInt;
845    use proc_macro2::TokenStream;
846    use std::char;
847    use std::ops::{Index, RangeFrom};
848
849    impl Lit {
850        /// Interpret a Syn literal from a proc-macro2 literal.
851        pub fn new(token: Literal) -> Self {
852            let repr = token.to_string();
853
854            match byte(&repr, 0) {
855                b'"' | b'r' => {
856                    let (_, suffix) = parse_lit_str(&repr);
857                    return Lit::Str(LitStr {
858                        repr: Box::new(LitStrRepr { token, suffix }),
859                    });
860                }
861                b'b' => match byte(&repr, 1) {
862                    b'"' | b'r' => {
863                        return Lit::ByteStr(LitByteStr { token });
864                    }
865                    b'\'' => {
866                        return Lit::Byte(LitByte { token });
867                    }
868                    _ => {}
869                },
870                b'\'' => {
871                    return Lit::Char(LitChar { token });
872                }
873                b'0'..=b'9' | b'-' => {
874                    if !(repr.ends_with("f32") || repr.ends_with("f64")) {
875                        if let Some((digits, suffix)) = parse_lit_int(&repr) {
876                            return Lit::Int(LitInt {
877                                repr: Box::new(LitIntRepr {
878                                    token,
879                                    digits,
880                                    suffix,
881                                }),
882                            });
883                        }
884                    }
885                    if let Some((digits, suffix)) = parse_lit_float(&repr) {
886                        return Lit::Float(LitFloat {
887                            repr: Box::new(LitFloatRepr {
888                                token,
889                                digits,
890                                suffix,
891                            }),
892                        });
893                    }
894                }
895                b't' | b'f' => {
896                    if repr == "true" || repr == "false" {
897                        return Lit::Bool(LitBool {
898                            value: repr == "true",
899                            span: token.span(),
900                        });
901                    }
902                }
903                _ => {}
904            }
905
906            panic!("Unrecognized literal: `{}`", repr);
907        }
908    }
909
910    /// Get the byte at offset idx, or a default of `b'\0'` if we're looking
911    /// past the end of the input buffer.
912    pub fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 {
913        let s = s.as_ref();
914        if idx < s.len() {
915            s[idx]
916        } else {
917            0
918        }
919    }
920
921    fn next_chr(s: &str) -> char {
922        s.chars().next().unwrap_or('\0')
923    }
924
925    // Returns (content, suffix).
926    pub fn parse_lit_str(s: &str) -> (Box<str>, Box<str>) {
927        match byte(s, 0) {
928            b'"' => parse_lit_str_cooked(s),
929            b'r' => parse_lit_str_raw(s),
930            _ => unreachable!(),
931        }
932    }
933
934    // Clippy false positive
935    // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
936    #[allow(clippy::needless_continue)]
937    fn parse_lit_str_cooked(mut s: &str) -> (Box<str>, Box<str>) {
938        assert_eq!(byte(s, 0), b'"');
939        s = &s[1..];
940
941        let mut content = String::new();
942        'outer: loop {
943            let ch = match byte(s, 0) {
944                b'"' => break,
945                b'\\' => {
946                    let b = byte(s, 1);
947                    s = &s[2..];
948                    match b {
949                        b'x' => {
950                            let (byte, rest) = backslash_x(s);
951                            s = rest;
952                            assert!(byte <= 0x80, "Invalid \\x byte in string literal");
953                            char::from_u32(u32::from(byte)).unwrap()
954                        }
955                        b'u' => {
956                            let (chr, rest) = backslash_u(s);
957                            s = rest;
958                            chr
959                        }
960                        b'n' => '\n',
961                        b'r' => '\r',
962                        b't' => '\t',
963                        b'\\' => '\\',
964                        b'0' => '\0',
965                        b'\'' => '\'',
966                        b'"' => '"',
967                        b'\r' | b'\n' => loop {
968                            let ch = next_chr(s);
969                            if ch.is_whitespace() {
970                                s = &s[ch.len_utf8()..];
971                            } else {
972                                continue 'outer;
973                            }
974                        },
975                        b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
976                    }
977                }
978                b'\r' => {
979                    assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
980                    s = &s[2..];
981                    '\n'
982                }
983                _ => {
984                    let ch = next_chr(s);
985                    s = &s[ch.len_utf8()..];
986                    ch
987                }
988            };
989            content.push(ch);
990        }
991
992        assert!(s.starts_with('"'));
993        let content = content.into_boxed_str();
994        let suffix = s[1..].to_owned().into_boxed_str();
995        (content, suffix)
996    }
997
998    fn parse_lit_str_raw(mut s: &str) -> (Box<str>, Box<str>) {
999        assert_eq!(byte(s, 0), b'r');
1000        s = &s[1..];
1001
1002        let mut pounds = 0;
1003        while byte(s, pounds) == b'#' {
1004            pounds += 1;
1005        }
1006        assert_eq!(byte(s, pounds), b'"');
1007        assert_eq!(byte(s, s.len() - pounds - 1), b'"');
1008        for end in s[s.len() - pounds..].bytes() {
1009            assert_eq!(end, b'#');
1010        }
1011
1012        let content = s[pounds + 1..s.len() - pounds - 1]
1013            .to_owned()
1014            .into_boxed_str();
1015        let suffix = Box::<str>::default(); // todo
1016        (content, suffix)
1017    }
1018
1019    pub fn parse_lit_byte_str(s: &str) -> Vec<u8> {
1020        assert_eq!(byte(s, 0), b'b');
1021        match byte(s, 1) {
1022            b'"' => parse_lit_byte_str_cooked(s),
1023            b'r' => parse_lit_byte_str_raw(s),
1024            _ => unreachable!(),
1025        }
1026    }
1027
1028    // Clippy false positive
1029    // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
1030    #[allow(clippy::needless_continue)]
1031    fn parse_lit_byte_str_cooked(mut s: &str) -> Vec<u8> {
1032        assert_eq!(byte(s, 0), b'b');
1033        assert_eq!(byte(s, 1), b'"');
1034        s = &s[2..];
1035
1036        // We're going to want to have slices which don't respect codepoint boundaries.
1037        let mut s = s.as_bytes();
1038
1039        let mut out = Vec::new();
1040        'outer: loop {
1041            let byte = match byte(s, 0) {
1042                b'"' => break,
1043                b'\\' => {
1044                    let b = byte(s, 1);
1045                    s = &s[2..];
1046                    match b {
1047                        b'x' => {
1048                            let (b, rest) = backslash_x(s);
1049                            s = rest;
1050                            b
1051                        }
1052                        b'n' => b'\n',
1053                        b'r' => b'\r',
1054                        b't' => b'\t',
1055                        b'\\' => b'\\',
1056                        b'0' => b'\0',
1057                        b'\'' => b'\'',
1058                        b'"' => b'"',
1059                        b'\r' | b'\n' => loop {
1060                            let byte = byte(s, 0);
1061                            let ch = char::from_u32(u32::from(byte)).unwrap();
1062                            if ch.is_whitespace() {
1063                                s = &s[1..];
1064                            } else {
1065                                continue 'outer;
1066                            }
1067                        },
1068                        b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
1069                    }
1070                }
1071                b'\r' => {
1072                    assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
1073                    s = &s[2..];
1074                    b'\n'
1075                }
1076                b => {
1077                    s = &s[1..];
1078                    b
1079                }
1080            };
1081            out.push(byte);
1082        }
1083
1084        assert_eq!(s, b"\"");
1085        out
1086    }
1087
1088    fn parse_lit_byte_str_raw(s: &str) -> Vec<u8> {
1089        assert_eq!(byte(s, 0), b'b');
1090        String::from(parse_lit_str_raw(&s[1..]).0).into_bytes()
1091    }
1092
1093    pub fn parse_lit_byte(s: &str) -> u8 {
1094        assert_eq!(byte(s, 0), b'b');
1095        assert_eq!(byte(s, 1), b'\'');
1096
1097        // We're going to want to have slices which don't respect codepoint boundaries.
1098        let mut s = s[2..].as_bytes();
1099
1100        let b = match byte(s, 0) {
1101            b'\\' => {
1102                let b = byte(s, 1);
1103                s = &s[2..];
1104                match b {
1105                    b'x' => {
1106                        let (b, rest) = backslash_x(s);
1107                        s = rest;
1108                        b
1109                    }
1110                    b'n' => b'\n',
1111                    b'r' => b'\r',
1112                    b't' => b'\t',
1113                    b'\\' => b'\\',
1114                    b'0' => b'\0',
1115                    b'\'' => b'\'',
1116                    b'"' => b'"',
1117                    b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
1118                }
1119            }
1120            b => {
1121                s = &s[1..];
1122                b
1123            }
1124        };
1125
1126        assert_eq!(byte(s, 0), b'\'');
1127        b
1128    }
1129
1130    pub fn parse_lit_char(mut s: &str) -> char {
1131        assert_eq!(byte(s, 0), b'\'');
1132        s = &s[1..];
1133
1134        let ch = match byte(s, 0) {
1135            b'\\' => {
1136                let b = byte(s, 1);
1137                s = &s[2..];
1138                match b {
1139                    b'x' => {
1140                        let (byte, rest) = backslash_x(s);
1141                        s = rest;
1142                        assert!(byte <= 0x80, "Invalid \\x byte in string literal");
1143                        char::from_u32(u32::from(byte)).unwrap()
1144                    }
1145                    b'u' => {
1146                        let (chr, rest) = backslash_u(s);
1147                        s = rest;
1148                        chr
1149                    }
1150                    b'n' => '\n',
1151                    b'r' => '\r',
1152                    b't' => '\t',
1153                    b'\\' => '\\',
1154                    b'0' => '\0',
1155                    b'\'' => '\'',
1156                    b'"' => '"',
1157                    b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
1158                }
1159            }
1160            _ => {
1161                let ch = next_chr(s);
1162                s = &s[ch.len_utf8()..];
1163                ch
1164            }
1165        };
1166        assert_eq!(s, "\'", "Expected end of char literal");
1167        ch
1168    }
1169
1170    fn backslash_x<S>(s: &S) -> (u8, &S)
1171    where
1172        S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
1173    {
1174        let mut ch = 0;
1175        let b0 = byte(s, 0);
1176        let b1 = byte(s, 1);
1177        ch += 0x10
1178            * match b0 {
1179                b'0'..=b'9' => b0 - b'0',
1180                b'a'..=b'f' => 10 + (b0 - b'a'),
1181                b'A'..=b'F' => 10 + (b0 - b'A'),
1182                _ => panic!("unexpected non-hex character after \\x"),
1183            };
1184        ch += match b1 {
1185            b'0'..=b'9' => b1 - b'0',
1186            b'a'..=b'f' => 10 + (b1 - b'a'),
1187            b'A'..=b'F' => 10 + (b1 - b'A'),
1188            _ => panic!("unexpected non-hex character after \\x"),
1189        };
1190        (ch, &s[2..])
1191    }
1192
1193    fn backslash_u(mut s: &str) -> (char, &str) {
1194        if byte(s, 0) != b'{' {
1195            panic!("expected {{ after \\u");
1196        }
1197        s = &s[1..];
1198
1199        let mut ch = 0;
1200        for _ in 0..6 {
1201            let b = byte(s, 0);
1202            match b {
1203                b'0'..=b'9' => {
1204                    ch *= 0x10;
1205                    ch += u32::from(b - b'0');
1206                    s = &s[1..];
1207                }
1208                b'a'..=b'f' => {
1209                    ch *= 0x10;
1210                    ch += u32::from(10 + b - b'a');
1211                    s = &s[1..];
1212                }
1213                b'A'..=b'F' => {
1214                    ch *= 0x10;
1215                    ch += u32::from(10 + b - b'A');
1216                    s = &s[1..];
1217                }
1218                b'}' => break,
1219                _ => panic!("unexpected non-hex character after \\u"),
1220            }
1221        }
1222        assert!(byte(s, 0) == b'}');
1223        s = &s[1..];
1224
1225        if let Some(ch) = char::from_u32(ch) {
1226            (ch, s)
1227        } else {
1228            panic!("character code {:x} is not a valid unicode character", ch);
1229        }
1230    }
1231
1232    // Returns base 10 digits and suffix.
1233    pub fn parse_lit_int(mut s: &str) -> Option<(Box<str>, Box<str>)> {
1234        let negative = byte(s, 0) == b'-';
1235        if negative {
1236            s = &s[1..];
1237        }
1238
1239        let base = match (byte(s, 0), byte(s, 1)) {
1240            (b'0', b'x') => {
1241                s = &s[2..];
1242                16
1243            }
1244            (b'0', b'o') => {
1245                s = &s[2..];
1246                8
1247            }
1248            (b'0', b'b') => {
1249                s = &s[2..];
1250                2
1251            }
1252            (b'0'..=b'9', _) => 10,
1253            _ => return None,
1254        };
1255
1256        let mut value = BigInt::new();
1257        loop {
1258            let b = byte(s, 0);
1259            let digit = match b {
1260                b'0'..=b'9' => b - b'0',
1261                b'a'..=b'f' if base > 10 => b - b'a' + 10,
1262                b'A'..=b'F' if base > 10 => b - b'A' + 10,
1263                b'_' => {
1264                    s = &s[1..];
1265                    continue;
1266                }
1267                // NOTE: Looking at a floating point literal, we don't want to
1268                // consider these integers.
1269                b'.' if base == 10 => return None,
1270                b'e' | b'E' if base == 10 => return None,
1271                _ => break,
1272            };
1273
1274            if digit >= base {
1275                return None;
1276            }
1277
1278            value *= base;
1279            value += digit;
1280            s = &s[1..];
1281        }
1282
1283        let suffix = s;
1284        if suffix.is_empty() || crate::ident::xid_ok(&suffix) {
1285            let mut repr = value.to_string();
1286            if negative {
1287                repr.insert(0, '-');
1288            }
1289            Some((repr.into_boxed_str(), suffix.to_owned().into_boxed_str()))
1290        } else {
1291            None
1292        }
1293    }
1294
1295    // Returns base 10 digits and suffix.
1296    pub fn parse_lit_float(input: &str) -> Option<(Box<str>, Box<str>)> {
1297        // Rust's floating point literals are very similar to the ones parsed by
1298        // the standard library, except that rust's literals can contain
1299        // ignorable underscores. Let's remove those underscores.
1300
1301        let mut bytes = input.to_owned().into_bytes();
1302
1303        let start = (*bytes.get(0)? == b'-') as usize;
1304        match bytes.get(start)? {
1305            b'0'..=b'9' => {}
1306            _ => return None,
1307        }
1308
1309        let mut read = start;
1310        let mut write = start;
1311        let mut has_dot = false;
1312        let mut has_e = false;
1313        let mut has_sign = false;
1314        let mut has_exponent = false;
1315        while read < bytes.len() {
1316            match bytes[read] {
1317                b'_' => {
1318                    // Don't increase write
1319                    read += 1;
1320                    continue;
1321                }
1322                b'0'..=b'9' => {
1323                    if has_e {
1324                        has_exponent = true;
1325                    }
1326                    bytes[write] = bytes[read];
1327                }
1328                b'.' => {
1329                    if has_e || has_dot {
1330                        return None;
1331                    }
1332                    has_dot = true;
1333                    bytes[write] = b'.';
1334                }
1335                b'e' | b'E' => {
1336                    if has_e {
1337                        return None;
1338                    }
1339                    has_e = true;
1340                    bytes[write] = b'e';
1341                }
1342                b'-' | b'+' => {
1343                    if has_sign || has_exponent || !has_e {
1344                        return None;
1345                    }
1346                    has_sign = true;
1347                    if bytes[read] == b'-' {
1348                        bytes[write] = bytes[read];
1349                    } else {
1350                        // Omit '+'
1351                        read += 1;
1352                        continue;
1353                    }
1354                }
1355                _ => break,
1356            }
1357            read += 1;
1358            write += 1;
1359        }
1360
1361        if has_e && !has_exponent {
1362            return None;
1363        }
1364
1365        let mut digits = String::from_utf8(bytes).unwrap();
1366        let suffix = digits.split_off(read);
1367        digits.truncate(write);
1368        if suffix.is_empty() || crate::ident::xid_ok(&suffix) {
1369            Some((digits.into_boxed_str(), suffix.into_boxed_str()))
1370        } else {
1371            None
1372        }
1373    }
1374
1375    pub fn to_literal(s: &str) -> Literal {
1376        let stream = s.parse::<TokenStream>().unwrap();
1377        match stream.into_iter().next().unwrap() {
1378            TokenTree::Literal(l) => l,
1379            _ => unreachable!(),
1380        }
1381    }
1382}