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