• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
new(value: &str, span: Span) -> Self122     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 
value(&self) -> String133     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")))]
parse<T: Parse>(&self) -> Result<T>172     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_with<F: Parser>(&self, parser: F) -> Result<F::Output>202     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 
span(&self) -> Span244     pub fn span(&self) -> Span {
245         self.repr.token.span()
246     }
247 
set_span(&mut self, span: Span)248     pub fn set_span(&mut self, span: Span) {
249         self.repr.token.set_span(span);
250     }
251 
suffix(&self) -> &str252     pub fn suffix(&self) -> &str {
253         &self.repr.suffix
254     }
255 
token(&self) -> Literal256     pub fn token(&self) -> Literal {
257         self.repr.token.clone()
258     }
259 }
260 
261 impl LitByteStr {
new(value: &[u8], span: Span) -> Self262     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 
value(&self) -> Vec<u8>273     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 
span(&self) -> Span279     pub fn span(&self) -> Span {
280         self.repr.token.span()
281     }
282 
set_span(&mut self, span: Span)283     pub fn set_span(&mut self, span: Span) {
284         self.repr.token.set_span(span);
285     }
286 
suffix(&self) -> &str287     pub fn suffix(&self) -> &str {
288         &self.repr.suffix
289     }
290 
token(&self) -> Literal291     pub fn token(&self) -> Literal {
292         self.repr.token.clone()
293     }
294 }
295 
296 impl LitByte {
new(value: u8, span: Span) -> Self297     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 
value(&self) -> u8308     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 
span(&self) -> Span314     pub fn span(&self) -> Span {
315         self.repr.token.span()
316     }
317 
set_span(&mut self, span: Span)318     pub fn set_span(&mut self, span: Span) {
319         self.repr.token.set_span(span);
320     }
321 
suffix(&self) -> &str322     pub fn suffix(&self) -> &str {
323         &self.repr.suffix
324     }
325 
token(&self) -> Literal326     pub fn token(&self) -> Literal {
327         self.repr.token.clone()
328     }
329 }
330 
331 impl LitChar {
new(value: char, span: Span) -> Self332     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 
value(&self) -> char343     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 
span(&self) -> Span349     pub fn span(&self) -> Span {
350         self.repr.token.span()
351     }
352 
set_span(&mut self, span: Span)353     pub fn set_span(&mut self, span: Span) {
354         self.repr.token.set_span(span);
355     }
356 
suffix(&self) -> &str357     pub fn suffix(&self) -> &str {
358         &self.repr.suffix
359     }
360 
token(&self) -> Literal361     pub fn token(&self) -> Literal {
362         self.repr.token.clone()
363     }
364 }
365 
366 impl LitInt {
new(repr: &str, span: Span) -> Self367     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_digits(&self) -> &str384     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_parse<N>(&self) -> Result<N> where N: FromStr, N::Err: Display,410     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 
suffix(&self) -> &str420     pub fn suffix(&self) -> &str {
421         &self.repr.suffix
422     }
423 
span(&self) -> Span424     pub fn span(&self) -> Span {
425         self.repr.token.span()
426     }
427 
set_span(&mut self, span: Span)428     pub fn set_span(&mut self, span: Span) {
429         self.repr.token.set_span(span);
430     }
431 
token(&self) -> Literal432     pub fn token(&self) -> Literal {
433         self.repr.token.clone()
434     }
435 }
436 
437 impl From<Literal> for LitInt {
from(token: Literal) -> Self438     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 {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result455     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
456         self.repr.token.fmt(formatter)
457     }
458 }
459 
460 impl LitFloat {
new(repr: &str, span: Span) -> Self461     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_digits(&self) -> &str478     pub fn base10_digits(&self) -> &str {
479         &self.repr.digits
480     }
481 
base10_parse<N>(&self) -> Result<N> where N: FromStr, N::Err: Display,482     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 
suffix(&self) -> &str492     pub fn suffix(&self) -> &str {
493         &self.repr.suffix
494     }
495 
span(&self) -> Span496     pub fn span(&self) -> Span {
497         self.repr.token.span()
498     }
499 
set_span(&mut self, span: Span)500     pub fn set_span(&mut self, span: Span) {
501         self.repr.token.set_span(span);
502     }
503 
token(&self) -> Literal504     pub fn token(&self) -> Literal {
505         self.repr.token.clone()
506     }
507 }
508 
509 impl From<Literal> for LitFloat {
from(token: Literal) -> Self510     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 {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result527     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
528         self.repr.token.fmt(formatter)
529     }
530 }
531 
532 impl LitBool {
new(value: bool, span: Span) -> Self533     pub fn new(value: bool, span: Span) -> Self {
534         LitBool { value, span }
535     }
536 
value(&self) -> bool537     pub fn value(&self) -> bool {
538         self.value
539     }
540 
span(&self) -> Span541     pub fn span(&self) -> Span {
542         self.span
543     }
544 
set_span(&mut self, span: Span)545     pub fn set_span(&mut self, span: Span) {
546         self.span = span;
547     }
548 
token(&self) -> Ident549     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 {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result562         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 {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result581         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 {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result600         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 {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result619         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 {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result638         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 {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result657         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 {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result676         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 {
clone(&self) -> Self697     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 {
clone(&self) -> Self708     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 {
clone(&self) -> Self720     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 {
734             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 {
744             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 {
752             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)]
782     pub fn LitBool(marker: lookahead::TokenMarker) -> LitBool {
783         match marker {}
784     }
785 }
786 
787 ast_enum! {
788     /// The style of a string literal, either plain quoted or a raw string like
789     /// `r##"data"##`.
790     pub enum StrStyle #no_visit {
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 
800 #[cfg(feature = "parsing")]
801 pub_if_not_doc! {
802     #[doc(hidden)]
803     #[allow(non_snake_case)]
804     pub fn Lit(marker: lookahead::TokenMarker) -> Lit {
805         match marker {}
806     }
807 }
808 
809 #[cfg(feature = "parsing")]
810 pub(crate) mod parsing {
811     use super::*;
812     use crate::buffer::Cursor;
813     use crate::parse::{Parse, ParseStream, Result};
814     use proc_macro2::Punct;
815 
816     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
817     impl Parse for Lit {
parse(input: ParseStream) -> Result<Self>818         fn parse(input: ParseStream) -> Result<Self> {
819             input.step(|cursor| {
820                 if let Some((lit, rest)) = cursor.literal() {
821                     return Ok((Lit::new(lit), rest));
822                 }
823 
824                 if let Some((ident, rest)) = cursor.ident() {
825                     let value = ident == "true";
826                     if value || ident == "false" {
827                         let lit_bool = LitBool {
828                             value,
829                             span: ident.span(),
830                         };
831                         return Ok((Lit::Bool(lit_bool), rest));
832                     }
833                 }
834 
835                 if let Some((punct, rest)) = cursor.punct() {
836                     if punct.as_char() == '-' {
837                         if let Some((lit, rest)) = parse_negative_lit(punct, rest) {
838                             return Ok((lit, rest));
839                         }
840                     }
841                 }
842 
843                 Err(cursor.error("expected literal"))
844             })
845         }
846     }
847 
parse_negative_lit(neg: Punct, cursor: Cursor) -> Option<(Lit, Cursor)>848     fn parse_negative_lit(neg: Punct, cursor: Cursor) -> Option<(Lit, Cursor)> {
849         let (lit, rest) = cursor.literal()?;
850 
851         let mut span = neg.span();
852         span = span.join(lit.span()).unwrap_or(span);
853 
854         let mut repr = lit.to_string();
855         repr.insert(0, '-');
856 
857         if let Some((digits, suffix)) = value::parse_lit_int(&repr) {
858             let mut token: Literal = repr.parse().unwrap();
859             token.set_span(span);
860             return Some((
861                 Lit::Int(LitInt {
862                     repr: Box::new(LitIntRepr {
863                         token,
864                         digits,
865                         suffix,
866                     }),
867                 }),
868                 rest,
869             ));
870         }
871 
872         let (digits, suffix) = value::parse_lit_float(&repr)?;
873         let mut token: Literal = repr.parse().unwrap();
874         token.set_span(span);
875         Some((
876             Lit::Float(LitFloat {
877                 repr: Box::new(LitFloatRepr {
878                     token,
879                     digits,
880                     suffix,
881                 }),
882             }),
883             rest,
884         ))
885     }
886 
887     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
888     impl Parse for LitStr {
parse(input: ParseStream) -> Result<Self>889         fn parse(input: ParseStream) -> Result<Self> {
890             let head = input.fork();
891             match input.parse() {
892                 Ok(Lit::Str(lit)) => Ok(lit),
893                 _ => Err(head.error("expected string literal")),
894             }
895         }
896     }
897 
898     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
899     impl Parse for LitByteStr {
parse(input: ParseStream) -> Result<Self>900         fn parse(input: ParseStream) -> Result<Self> {
901             let head = input.fork();
902             match input.parse() {
903                 Ok(Lit::ByteStr(lit)) => Ok(lit),
904                 _ => Err(head.error("expected byte string literal")),
905             }
906         }
907     }
908 
909     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
910     impl Parse for LitByte {
parse(input: ParseStream) -> Result<Self>911         fn parse(input: ParseStream) -> Result<Self> {
912             let head = input.fork();
913             match input.parse() {
914                 Ok(Lit::Byte(lit)) => Ok(lit),
915                 _ => Err(head.error("expected byte literal")),
916             }
917         }
918     }
919 
920     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
921     impl Parse for LitChar {
parse(input: ParseStream) -> Result<Self>922         fn parse(input: ParseStream) -> Result<Self> {
923             let head = input.fork();
924             match input.parse() {
925                 Ok(Lit::Char(lit)) => Ok(lit),
926                 _ => Err(head.error("expected character literal")),
927             }
928         }
929     }
930 
931     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
932     impl Parse for LitInt {
parse(input: ParseStream) -> Result<Self>933         fn parse(input: ParseStream) -> Result<Self> {
934             let head = input.fork();
935             match input.parse() {
936                 Ok(Lit::Int(lit)) => Ok(lit),
937                 _ => Err(head.error("expected integer literal")),
938             }
939         }
940     }
941 
942     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
943     impl Parse for LitFloat {
parse(input: ParseStream) -> Result<Self>944         fn parse(input: ParseStream) -> Result<Self> {
945             let head = input.fork();
946             match input.parse() {
947                 Ok(Lit::Float(lit)) => Ok(lit),
948                 _ => Err(head.error("expected floating point literal")),
949             }
950         }
951     }
952 
953     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
954     impl Parse for LitBool {
parse(input: ParseStream) -> Result<Self>955         fn parse(input: ParseStream) -> Result<Self> {
956             let head = input.fork();
957             match input.parse() {
958                 Ok(Lit::Bool(lit)) => Ok(lit),
959                 _ => Err(head.error("expected boolean literal")),
960             }
961         }
962     }
963 }
964 
965 #[cfg(feature = "printing")]
966 mod printing {
967     use super::*;
968     use proc_macro2::TokenStream;
969     use quote::{ToTokens, TokenStreamExt};
970 
971     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
972     impl ToTokens for LitStr {
to_tokens(&self, tokens: &mut TokenStream)973         fn to_tokens(&self, tokens: &mut TokenStream) {
974             self.repr.token.to_tokens(tokens);
975         }
976     }
977 
978     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
979     impl ToTokens for LitByteStr {
to_tokens(&self, tokens: &mut TokenStream)980         fn to_tokens(&self, tokens: &mut TokenStream) {
981             self.repr.token.to_tokens(tokens);
982         }
983     }
984 
985     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
986     impl ToTokens for LitByte {
to_tokens(&self, tokens: &mut TokenStream)987         fn to_tokens(&self, tokens: &mut TokenStream) {
988             self.repr.token.to_tokens(tokens);
989         }
990     }
991 
992     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
993     impl ToTokens for LitChar {
to_tokens(&self, tokens: &mut TokenStream)994         fn to_tokens(&self, tokens: &mut TokenStream) {
995             self.repr.token.to_tokens(tokens);
996         }
997     }
998 
999     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
1000     impl ToTokens for LitInt {
to_tokens(&self, tokens: &mut TokenStream)1001         fn to_tokens(&self, tokens: &mut TokenStream) {
1002             self.repr.token.to_tokens(tokens);
1003         }
1004     }
1005 
1006     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
1007     impl ToTokens for LitFloat {
to_tokens(&self, tokens: &mut TokenStream)1008         fn to_tokens(&self, tokens: &mut TokenStream) {
1009             self.repr.token.to_tokens(tokens);
1010         }
1011     }
1012 
1013     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
1014     impl ToTokens for LitBool {
to_tokens(&self, tokens: &mut TokenStream)1015         fn to_tokens(&self, tokens: &mut TokenStream) {
1016             tokens.append(self.token());
1017         }
1018     }
1019 }
1020 
1021 mod value {
1022     use super::*;
1023     use crate::bigint::BigInt;
1024     use std::char;
1025     use std::ops::{Index, RangeFrom};
1026 
1027     impl Lit {
1028         /// Interpret a Syn literal from a proc-macro2 literal.
new(token: Literal) -> Self1029         pub fn new(token: Literal) -> Self {
1030             let repr = token.to_string();
1031 
1032             match byte(&repr, 0) {
1033                 // "...", r"...", r#"..."#
1034                 b'"' | b'r' => {
1035                     let (_, suffix) = parse_lit_str(&repr);
1036                     return Lit::Str(LitStr {
1037                         repr: Box::new(LitRepr { token, suffix }),
1038                     });
1039                 }
1040                 b'b' => match byte(&repr, 1) {
1041                     // b"...", br"...", br#"...#"
1042                     b'"' | b'r' => {
1043                         let (_, suffix) = parse_lit_byte_str(&repr);
1044                         return Lit::ByteStr(LitByteStr {
1045                             repr: Box::new(LitRepr { token, suffix }),
1046                         });
1047                     }
1048                     // b'...'
1049                     b'\'' => {
1050                         let (_, suffix) = parse_lit_byte(&repr);
1051                         return Lit::Byte(LitByte {
1052                             repr: Box::new(LitRepr { token, suffix }),
1053                         });
1054                     }
1055                     _ => {}
1056                 },
1057                 // '...'
1058                 b'\'' => {
1059                     let (_, suffix) = parse_lit_char(&repr);
1060                     return Lit::Char(LitChar {
1061                         repr: Box::new(LitRepr { token, suffix }),
1062                     });
1063                 }
1064                 b'0'..=b'9' | b'-' => {
1065                     // 0, 123, 0xFF, 0o77, 0b11
1066                     if let Some((digits, suffix)) = parse_lit_int(&repr) {
1067                         return Lit::Int(LitInt {
1068                             repr: Box::new(LitIntRepr {
1069                                 token,
1070                                 digits,
1071                                 suffix,
1072                             }),
1073                         });
1074                     }
1075                     // 1.0, 1e-1, 1e+1
1076                     if let Some((digits, suffix)) = parse_lit_float(&repr) {
1077                         return Lit::Float(LitFloat {
1078                             repr: Box::new(LitFloatRepr {
1079                                 token,
1080                                 digits,
1081                                 suffix,
1082                             }),
1083                         });
1084                     }
1085                 }
1086                 // true, false
1087                 b't' | b'f' => {
1088                     if repr == "true" || repr == "false" {
1089                         return Lit::Bool(LitBool {
1090                             value: repr == "true",
1091                             span: token.span(),
1092                         });
1093                     }
1094                 }
1095                 // c"...", cr"...", cr#"..."#
1096                 // TODO: add a Lit::CStr variant?
1097                 b'c' => return Lit::Verbatim(token),
1098                 b'(' if repr == "(/*ERROR*/)" => return Lit::Verbatim(token),
1099                 _ => {}
1100             }
1101 
1102             panic!("Unrecognized literal: `{}`", repr);
1103         }
1104 
suffix(&self) -> &str1105         pub fn suffix(&self) -> &str {
1106             match self {
1107                 Lit::Str(lit) => lit.suffix(),
1108                 Lit::ByteStr(lit) => lit.suffix(),
1109                 Lit::Byte(lit) => lit.suffix(),
1110                 Lit::Char(lit) => lit.suffix(),
1111                 Lit::Int(lit) => lit.suffix(),
1112                 Lit::Float(lit) => lit.suffix(),
1113                 Lit::Bool(_) | Lit::Verbatim(_) => "",
1114             }
1115         }
1116 
span(&self) -> Span1117         pub fn span(&self) -> Span {
1118             match self {
1119                 Lit::Str(lit) => lit.span(),
1120                 Lit::ByteStr(lit) => lit.span(),
1121                 Lit::Byte(lit) => lit.span(),
1122                 Lit::Char(lit) => lit.span(),
1123                 Lit::Int(lit) => lit.span(),
1124                 Lit::Float(lit) => lit.span(),
1125                 Lit::Bool(lit) => lit.span,
1126                 Lit::Verbatim(lit) => lit.span(),
1127             }
1128         }
1129 
set_span(&mut self, span: Span)1130         pub fn set_span(&mut self, span: Span) {
1131             match self {
1132                 Lit::Str(lit) => lit.set_span(span),
1133                 Lit::ByteStr(lit) => lit.set_span(span),
1134                 Lit::Byte(lit) => lit.set_span(span),
1135                 Lit::Char(lit) => lit.set_span(span),
1136                 Lit::Int(lit) => lit.set_span(span),
1137                 Lit::Float(lit) => lit.set_span(span),
1138                 Lit::Bool(lit) => lit.span = span,
1139                 Lit::Verbatim(lit) => lit.set_span(span),
1140             }
1141         }
1142     }
1143 
1144     /// Get the byte at offset idx, or a default of `b'\0'` if we're looking
1145     /// past the end of the input buffer.
byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u81146     pub(crate) fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 {
1147         let s = s.as_ref();
1148         if idx < s.len() {
1149             s[idx]
1150         } else {
1151             0
1152         }
1153     }
1154 
next_chr(s: &str) -> char1155     fn next_chr(s: &str) -> char {
1156         s.chars().next().unwrap_or('\0')
1157     }
1158 
1159     // Returns (content, suffix).
parse_lit_str(s: &str) -> (Box<str>, Box<str>)1160     pub(crate) fn parse_lit_str(s: &str) -> (Box<str>, Box<str>) {
1161         match byte(s, 0) {
1162             b'"' => parse_lit_str_cooked(s),
1163             b'r' => parse_lit_str_raw(s),
1164             _ => unreachable!(),
1165         }
1166     }
1167 
1168     // Clippy false positive
1169     // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
1170     #[allow(clippy::needless_continue)]
parse_lit_str_cooked(mut s: &str) -> (Box<str>, Box<str>)1171     fn parse_lit_str_cooked(mut s: &str) -> (Box<str>, Box<str>) {
1172         assert_eq!(byte(s, 0), b'"');
1173         s = &s[1..];
1174 
1175         let mut content = String::new();
1176         'outer: loop {
1177             let ch = match byte(s, 0) {
1178                 b'"' => break,
1179                 b'\\' => {
1180                     let b = byte(s, 1);
1181                     s = &s[2..];
1182                     match b {
1183                         b'x' => {
1184                             let (byte, rest) = backslash_x(s);
1185                             s = rest;
1186                             assert!(byte <= 0x7F, "Invalid \\x byte in string literal");
1187                             char::from_u32(u32::from(byte)).unwrap()
1188                         }
1189                         b'u' => {
1190                             let (chr, rest) = backslash_u(s);
1191                             s = rest;
1192                             chr
1193                         }
1194                         b'n' => '\n',
1195                         b'r' => '\r',
1196                         b't' => '\t',
1197                         b'\\' => '\\',
1198                         b'0' => '\0',
1199                         b'\'' => '\'',
1200                         b'"' => '"',
1201                         b'\r' | b'\n' => loop {
1202                             let b = byte(s, 0);
1203                             match b {
1204                                 b' ' | b'\t' | b'\n' | b'\r' => s = &s[1..],
1205                                 _ => continue 'outer,
1206                             }
1207                         },
1208                         b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
1209                     }
1210                 }
1211                 b'\r' => {
1212                     assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
1213                     s = &s[2..];
1214                     '\n'
1215                 }
1216                 _ => {
1217                     let ch = next_chr(s);
1218                     s = &s[ch.len_utf8()..];
1219                     ch
1220                 }
1221             };
1222             content.push(ch);
1223         }
1224 
1225         assert!(s.starts_with('"'));
1226         let content = content.into_boxed_str();
1227         let suffix = s[1..].to_owned().into_boxed_str();
1228         (content, suffix)
1229     }
1230 
parse_lit_str_raw(mut s: &str) -> (Box<str>, Box<str>)1231     fn parse_lit_str_raw(mut s: &str) -> (Box<str>, Box<str>) {
1232         assert_eq!(byte(s, 0), b'r');
1233         s = &s[1..];
1234 
1235         let mut pounds = 0;
1236         while byte(s, pounds) == b'#' {
1237             pounds += 1;
1238         }
1239         assert_eq!(byte(s, pounds), b'"');
1240         let close = s.rfind('"').unwrap();
1241         for end in s[close + 1..close + 1 + pounds].bytes() {
1242             assert_eq!(end, b'#');
1243         }
1244 
1245         let content = s[pounds + 1..close].to_owned().into_boxed_str();
1246         let suffix = s[close + 1 + pounds..].to_owned().into_boxed_str();
1247         (content, suffix)
1248     }
1249 
1250     // Returns (content, suffix).
parse_lit_byte_str(s: &str) -> (Vec<u8>, Box<str>)1251     pub(crate) fn parse_lit_byte_str(s: &str) -> (Vec<u8>, Box<str>) {
1252         assert_eq!(byte(s, 0), b'b');
1253         match byte(s, 1) {
1254             b'"' => parse_lit_byte_str_cooked(s),
1255             b'r' => parse_lit_byte_str_raw(s),
1256             _ => unreachable!(),
1257         }
1258     }
1259 
1260     // Clippy false positive
1261     // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
1262     #[allow(clippy::needless_continue)]
parse_lit_byte_str_cooked(mut s: &str) -> (Vec<u8>, Box<str>)1263     fn parse_lit_byte_str_cooked(mut s: &str) -> (Vec<u8>, Box<str>) {
1264         assert_eq!(byte(s, 0), b'b');
1265         assert_eq!(byte(s, 1), b'"');
1266         s = &s[2..];
1267 
1268         // We're going to want to have slices which don't respect codepoint boundaries.
1269         let mut v = s.as_bytes();
1270 
1271         let mut out = Vec::new();
1272         'outer: loop {
1273             let byte = match byte(v, 0) {
1274                 b'"' => break,
1275                 b'\\' => {
1276                     let b = byte(v, 1);
1277                     v = &v[2..];
1278                     match b {
1279                         b'x' => {
1280                             let (b, rest) = backslash_x(v);
1281                             v = rest;
1282                             b
1283                         }
1284                         b'n' => b'\n',
1285                         b'r' => b'\r',
1286                         b't' => b'\t',
1287                         b'\\' => b'\\',
1288                         b'0' => b'\0',
1289                         b'\'' => b'\'',
1290                         b'"' => b'"',
1291                         b'\r' | b'\n' => loop {
1292                             let byte = byte(v, 0);
1293                             if matches!(byte, b' ' | b'\t' | b'\n' | b'\r') {
1294                                 v = &v[1..];
1295                             } else {
1296                                 continue 'outer;
1297                             }
1298                         },
1299                         b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
1300                     }
1301                 }
1302                 b'\r' => {
1303                     assert_eq!(byte(v, 1), b'\n', "Bare CR not allowed in string");
1304                     v = &v[2..];
1305                     b'\n'
1306                 }
1307                 b => {
1308                     v = &v[1..];
1309                     b
1310                 }
1311             };
1312             out.push(byte);
1313         }
1314 
1315         assert_eq!(byte(v, 0), b'"');
1316         let suffix = s[s.len() - v.len() + 1..].to_owned().into_boxed_str();
1317         (out, suffix)
1318     }
1319 
parse_lit_byte_str_raw(s: &str) -> (Vec<u8>, Box<str>)1320     fn parse_lit_byte_str_raw(s: &str) -> (Vec<u8>, Box<str>) {
1321         assert_eq!(byte(s, 0), b'b');
1322         let (value, suffix) = parse_lit_str_raw(&s[1..]);
1323         (String::from(value).into_bytes(), suffix)
1324     }
1325 
1326     // Returns (value, suffix).
parse_lit_byte(s: &str) -> (u8, Box<str>)1327     pub(crate) fn parse_lit_byte(s: &str) -> (u8, Box<str>) {
1328         assert_eq!(byte(s, 0), b'b');
1329         assert_eq!(byte(s, 1), b'\'');
1330 
1331         // We're going to want to have slices which don't respect codepoint boundaries.
1332         let mut v = s[2..].as_bytes();
1333 
1334         let b = match byte(v, 0) {
1335             b'\\' => {
1336                 let b = byte(v, 1);
1337                 v = &v[2..];
1338                 match b {
1339                     b'x' => {
1340                         let (b, rest) = backslash_x(v);
1341                         v = rest;
1342                         b
1343                     }
1344                     b'n' => b'\n',
1345                     b'r' => b'\r',
1346                     b't' => b'\t',
1347                     b'\\' => b'\\',
1348                     b'0' => b'\0',
1349                     b'\'' => b'\'',
1350                     b'"' => b'"',
1351                     b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
1352                 }
1353             }
1354             b => {
1355                 v = &v[1..];
1356                 b
1357             }
1358         };
1359 
1360         assert_eq!(byte(v, 0), b'\'');
1361         let suffix = s[s.len() - v.len() + 1..].to_owned().into_boxed_str();
1362         (b, suffix)
1363     }
1364 
1365     // Returns (value, suffix).
parse_lit_char(mut s: &str) -> (char, Box<str>)1366     pub(crate) fn parse_lit_char(mut s: &str) -> (char, Box<str>) {
1367         assert_eq!(byte(s, 0), b'\'');
1368         s = &s[1..];
1369 
1370         let ch = match byte(s, 0) {
1371             b'\\' => {
1372                 let b = byte(s, 1);
1373                 s = &s[2..];
1374                 match b {
1375                     b'x' => {
1376                         let (byte, rest) = backslash_x(s);
1377                         s = rest;
1378                         assert!(byte <= 0x80, "Invalid \\x byte in string literal");
1379                         char::from_u32(u32::from(byte)).unwrap()
1380                     }
1381                     b'u' => {
1382                         let (chr, rest) = backslash_u(s);
1383                         s = rest;
1384                         chr
1385                     }
1386                     b'n' => '\n',
1387                     b'r' => '\r',
1388                     b't' => '\t',
1389                     b'\\' => '\\',
1390                     b'0' => '\0',
1391                     b'\'' => '\'',
1392                     b'"' => '"',
1393                     b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
1394                 }
1395             }
1396             _ => {
1397                 let ch = next_chr(s);
1398                 s = &s[ch.len_utf8()..];
1399                 ch
1400             }
1401         };
1402         assert_eq!(byte(s, 0), b'\'');
1403         let suffix = s[1..].to_owned().into_boxed_str();
1404         (ch, suffix)
1405     }
1406 
backslash_x<S>(s: &S) -> (u8, &S) where S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,1407     fn backslash_x<S>(s: &S) -> (u8, &S)
1408     where
1409         S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
1410     {
1411         let mut ch = 0;
1412         let b0 = byte(s, 0);
1413         let b1 = byte(s, 1);
1414         ch += 0x10
1415             * match b0 {
1416                 b'0'..=b'9' => b0 - b'0',
1417                 b'a'..=b'f' => 10 + (b0 - b'a'),
1418                 b'A'..=b'F' => 10 + (b0 - b'A'),
1419                 _ => panic!("unexpected non-hex character after \\x"),
1420             };
1421         ch += match b1 {
1422             b'0'..=b'9' => b1 - b'0',
1423             b'a'..=b'f' => 10 + (b1 - b'a'),
1424             b'A'..=b'F' => 10 + (b1 - b'A'),
1425             _ => panic!("unexpected non-hex character after \\x"),
1426         };
1427         (ch, &s[2..])
1428     }
1429 
backslash_u(mut s: &str) -> (char, &str)1430     fn backslash_u(mut s: &str) -> (char, &str) {
1431         if byte(s, 0) != b'{' {
1432             panic!("{}", "expected { after \\u");
1433         }
1434         s = &s[1..];
1435 
1436         let mut ch = 0;
1437         let mut digits = 0;
1438         loop {
1439             let b = byte(s, 0);
1440             let digit = match b {
1441                 b'0'..=b'9' => b - b'0',
1442                 b'a'..=b'f' => 10 + b - b'a',
1443                 b'A'..=b'F' => 10 + b - b'A',
1444                 b'_' if digits > 0 => {
1445                     s = &s[1..];
1446                     continue;
1447                 }
1448                 b'}' if digits == 0 => panic!("invalid empty unicode escape"),
1449                 b'}' => break,
1450                 _ => panic!("unexpected non-hex character after \\u"),
1451             };
1452             if digits == 6 {
1453                 panic!("overlong unicode escape (must have at most 6 hex digits)");
1454             }
1455             ch *= 0x10;
1456             ch += u32::from(digit);
1457             digits += 1;
1458             s = &s[1..];
1459         }
1460         assert!(byte(s, 0) == b'}');
1461         s = &s[1..];
1462 
1463         if let Some(ch) = char::from_u32(ch) {
1464             (ch, s)
1465         } else {
1466             panic!("character code {:x} is not a valid unicode character", ch);
1467         }
1468     }
1469 
1470     // Returns base 10 digits and suffix.
parse_lit_int(mut s: &str) -> Option<(Box<str>, Box<str>)>1471     pub(crate) fn parse_lit_int(mut s: &str) -> Option<(Box<str>, Box<str>)> {
1472         let negative = byte(s, 0) == b'-';
1473         if negative {
1474             s = &s[1..];
1475         }
1476 
1477         let base = match (byte(s, 0), byte(s, 1)) {
1478             (b'0', b'x') => {
1479                 s = &s[2..];
1480                 16
1481             }
1482             (b'0', b'o') => {
1483                 s = &s[2..];
1484                 8
1485             }
1486             (b'0', b'b') => {
1487                 s = &s[2..];
1488                 2
1489             }
1490             (b'0'..=b'9', _) => 10,
1491             _ => return None,
1492         };
1493 
1494         let mut value = BigInt::new();
1495         let mut has_digit = false;
1496         'outer: loop {
1497             let b = byte(s, 0);
1498             let digit = match b {
1499                 b'0'..=b'9' => b - b'0',
1500                 b'a'..=b'f' if base > 10 => b - b'a' + 10,
1501                 b'A'..=b'F' if base > 10 => b - b'A' + 10,
1502                 b'_' => {
1503                     s = &s[1..];
1504                     continue;
1505                 }
1506                 // If looking at a floating point literal, we don't want to
1507                 // consider it an integer.
1508                 b'.' if base == 10 => return None,
1509                 b'e' | b'E' if base == 10 => {
1510                     let mut has_exp = false;
1511                     for (i, b) in s[1..].bytes().enumerate() {
1512                         match b {
1513                             b'_' => {}
1514                             b'-' | b'+' => return None,
1515                             b'0'..=b'9' => has_exp = true,
1516                             _ => {
1517                                 let suffix = &s[1 + i..];
1518                                 if has_exp && crate::ident::xid_ok(suffix) {
1519                                     return None;
1520                                 } else {
1521                                     break 'outer;
1522                                 }
1523                             }
1524                         }
1525                     }
1526                     if has_exp {
1527                         return None;
1528                     } else {
1529                         break;
1530                     }
1531                 }
1532                 _ => break,
1533             };
1534 
1535             if digit >= base {
1536                 return None;
1537             }
1538 
1539             has_digit = true;
1540             value *= base;
1541             value += digit;
1542             s = &s[1..];
1543         }
1544 
1545         if !has_digit {
1546             return None;
1547         }
1548 
1549         let suffix = s;
1550         if suffix.is_empty() || crate::ident::xid_ok(suffix) {
1551             let mut repr = value.to_string();
1552             if negative {
1553                 repr.insert(0, '-');
1554             }
1555             Some((repr.into_boxed_str(), suffix.to_owned().into_boxed_str()))
1556         } else {
1557             None
1558         }
1559     }
1560 
1561     // Returns base 10 digits and suffix.
parse_lit_float(input: &str) -> Option<(Box<str>, Box<str>)>1562     pub(crate) fn parse_lit_float(input: &str) -> Option<(Box<str>, Box<str>)> {
1563         // Rust's floating point literals are very similar to the ones parsed by
1564         // the standard library, except that rust's literals can contain
1565         // ignorable underscores. Let's remove those underscores.
1566 
1567         let mut bytes = input.to_owned().into_bytes();
1568 
1569         let start = (*bytes.first()? == b'-') as usize;
1570         match bytes.get(start)? {
1571             b'0'..=b'9' => {}
1572             _ => return None,
1573         }
1574 
1575         let mut read = start;
1576         let mut write = start;
1577         let mut has_dot = false;
1578         let mut has_e = false;
1579         let mut has_sign = false;
1580         let mut has_exponent = false;
1581         while read < bytes.len() {
1582             match bytes[read] {
1583                 b'_' => {
1584                     // Don't increase write
1585                     read += 1;
1586                     continue;
1587                 }
1588                 b'0'..=b'9' => {
1589                     if has_e {
1590                         has_exponent = true;
1591                     }
1592                     bytes[write] = bytes[read];
1593                 }
1594                 b'.' => {
1595                     if has_e || has_dot {
1596                         return None;
1597                     }
1598                     has_dot = true;
1599                     bytes[write] = b'.';
1600                 }
1601                 b'e' | b'E' => {
1602                     match bytes[read + 1..]
1603                         .iter()
1604                         .find(|b| **b != b'_')
1605                         .unwrap_or(&b'\0')
1606                     {
1607                         b'-' | b'+' | b'0'..=b'9' => {}
1608                         _ => break,
1609                     }
1610                     if has_e {
1611                         if has_exponent {
1612                             break;
1613                         } else {
1614                             return None;
1615                         }
1616                     }
1617                     has_e = true;
1618                     bytes[write] = b'e';
1619                 }
1620                 b'-' | b'+' => {
1621                     if has_sign || has_exponent || !has_e {
1622                         return None;
1623                     }
1624                     has_sign = true;
1625                     if bytes[read] == b'-' {
1626                         bytes[write] = bytes[read];
1627                     } else {
1628                         // Omit '+'
1629                         read += 1;
1630                         continue;
1631                     }
1632                 }
1633                 _ => break,
1634             }
1635             read += 1;
1636             write += 1;
1637         }
1638 
1639         if has_e && !has_exponent {
1640             return None;
1641         }
1642 
1643         let mut digits = String::from_utf8(bytes).unwrap();
1644         let suffix = digits.split_off(read);
1645         digits.truncate(write);
1646         if suffix.is_empty() || crate::ident::xid_ok(&suffix) {
1647             Some((digits.into_boxed_str(), suffix.into_boxed_str()))
1648         } else {
1649             None
1650         }
1651     }
1652 }
1653