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