1 use proc_macro2
::{Literal, Span}
;
2 use std
::fmt
::{self, Display}
;
3 use std
::str::{self, FromStr}
;
5 #[cfg(feature = "printing")]
6 use proc_macro2
::Ident
;
8 #[cfg(feature = "parsing")]
9 use proc_macro2
::TokenStream
;
11 use proc_macro2
::TokenTree
;
13 #[cfg(feature = "extra-traits")]
14 use std
::hash
::{Hash, Hasher}
;
16 #[cfg(feature = "parsing")]
18 #[cfg(feature = "parsing")]
19 use crate::parse
::{Parse, Parser}
;
20 use crate::{Error, Result}
;
22 ast_enum_of_structs
! {
23 /// A Rust literal such as a string or integer or boolean.
25 /// *This type is available if Syn is built with the `"derive"` or `"full"`
28 /// # Syntax tree enum
30 /// This type is a [syntax tree enum].
32 /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
34 // TODO: change syntax-tree-enum link to an intra rustdoc link, currently
35 // blocked on https://github.com/rust-lang/rust/issues/62833
36 pub enum Lit
#manual_extra_traits {
37 /// A UTF-8 string literal: `"foo"`.
40 /// A byte string literal: `b"foo"`.
43 /// A byte literal: `b'f'`.
46 /// A character literal: `'a'`.
49 /// An integer literal: `1` or `1u16`.
52 /// A floating point literal: `1f64` or `1.0e10f64`.
54 /// Must be finite. May not be infinte or NaN.
57 /// A boolean literal: `true` or `false`.
60 /// A raw token literal not interpreted by Syn.
66 /// A UTF-8 string literal: `"foo"`.
68 /// *This type is available if Syn is built with the `"derive"` or
69 /// `"full"` feature.*
70 pub struct LitStr
#manual_extra_traits_debug {
71 repr
: Box
<LitStrRepr
>,
75 #[cfg_attr(feature = "clone-impls", derive(Clone))]
82 /// A byte string literal: `b"foo"`.
84 /// *This type is available if Syn is built with the `"derive"` or
85 /// `"full"` feature.*
86 pub struct LitByteStr
#manual_extra_traits_debug {
92 /// A byte literal: `b'f'`.
94 /// *This type is available if Syn is built with the `"derive"` or
95 /// `"full"` feature.*
96 pub struct LitByte
#manual_extra_traits_debug {
102 /// A character literal: `'a'`.
104 /// *This type is available if Syn is built with the `"derive"` or
105 /// `"full"` feature.*
106 pub struct LitChar
#manual_extra_traits_debug {
112 /// An integer literal: `1` or `1u16`.
114 /// *This type is available if Syn is built with the `"derive"` or
115 /// `"full"` feature.*
116 pub struct LitInt
#manual_extra_traits_debug {
117 repr
: Box
<LitIntRepr
>,
121 #[cfg_attr(feature = "clone-impls", derive(Clone))]
129 /// A floating point literal: `1f64` or `1.0e10f64`.
131 /// Must be finite. May not be infinte or NaN.
133 /// *This type is available if Syn is built with the `"derive"` or
134 /// `"full"` feature.*
135 pub struct LitFloat
#manual_extra_traits_debug {
136 repr
: Box
<LitFloatRepr
>,
140 #[cfg_attr(feature = "clone-impls", derive(Clone))]
141 struct LitFloatRepr
{
148 /// A boolean literal: `true` or `false`.
150 /// *This type is available if Syn is built with the `"derive"` or
151 /// `"full"` feature.*
152 pub struct LitBool
#manual_extra_traits_debug {
158 #[cfg(feature = "extra-traits")]
161 #[cfg(feature = "extra-traits")]
162 impl PartialEq
for Lit
{
163 fn eq(&self, other
: &Self) -> bool
{
164 match (self, other
) {
165 (Lit
::Str(this
), Lit
::Str(other
)) => this
== other
,
166 (Lit
::ByteStr(this
), Lit
::ByteStr(other
)) => this
== other
,
167 (Lit
::Byte(this
), Lit
::Byte(other
)) => this
== other
,
168 (Lit
::Char(this
), Lit
::Char(other
)) => this
== other
,
169 (Lit
::Int(this
), Lit
::Int(other
)) => this
== other
,
170 (Lit
::Float(this
), Lit
::Float(other
)) => this
== other
,
171 (Lit
::Bool(this
), Lit
::Bool(other
)) => this
== other
,
172 (Lit
::Verbatim(this
), Lit
::Verbatim(other
)) => this
.to_string() == other
.to_string(),
178 #[cfg(feature = "extra-traits")]
180 fn hash
<H
>(&self, hash
: &mut H
)
189 Lit
::ByteStr(lit
) => {
213 Lit
::Verbatim(lit
) => {
215 lit
.to_string().hash(hash
);
222 pub fn new(value
: &str, span
: Span
) -> Self {
223 let mut lit
= Literal
::string(value
);
226 repr
: Box
::new(LitStrRepr
{
228 suffix
: Box
::<str>::default(),
233 pub fn value(&self) -> String
{
234 let (value
, _
) = value
::parse_lit_str(&self.repr
.token
.to_string());
238 /// Parse a syntax tree node from the content of this string literal.
240 /// All spans in the syntax tree will point to the span of this `LitStr`.
245 /// use proc_macro2::Span;
246 /// use syn::{Attribute, Error, Ident, Lit, Meta, MetaNameValue, Path, Result};
248 /// // Parses the path from an attribute that looks like:
250 /// // #[path = "a::b::c"]
252 /// // or returns `None` if the input is some other attribute.
253 /// fn get_path(attr: &Attribute) -> Result<Option<Path>> {
254 /// if !attr.path.is_ident("path") {
258 /// match attr.parse_meta()? {
259 /// Meta::NameValue(MetaNameValue { lit: Lit::Str(lit_str), .. }) => {
260 /// lit_str.parse().map(Some)
263 /// let message = "expected #[path = \"...\"]";
264 /// Err(Error::new_spanned(attr, message))
269 #[cfg(feature = "parsing")]
270 pub fn parse
<T
: Parse
>(&self) -> Result
<T
> {
271 self.parse_with(T
::parse
)
274 /// Invoke parser on the content of this string literal.
276 /// All spans in the syntax tree will point to the span of this `LitStr`.
281 /// # use proc_macro2::Span;
282 /// # use syn::{LitStr, Result};
284 /// # fn main() -> Result<()> {
285 /// # let lit_str = LitStr::new("a::b::c", Span::call_site());
287 /// # const IGNORE: &str = stringify! {
288 /// let lit_str: LitStr = /* ... */;
291 /// // Parse a string literal like "a::b::c" into a Path, not allowing
292 /// // generic arguments on any of the path segments.
293 /// let basic_path = lit_str.parse_with(syn::Path::parse_mod_style)?;
298 #[cfg(feature = "parsing")]
299 pub fn parse_with
<F
: Parser
>(&self, parser
: F
) -> Result
<F
::Output
> {
300 use proc_macro2
::Group
;
302 // Token stream with every span replaced by the given one.
303 fn respan_token_stream(stream
: TokenStream
, span
: Span
) -> TokenStream
{
306 .map(|token
| respan_token_tree(token
, span
))
310 // Token tree with every span replaced by the given one.
311 fn respan_token_tree(mut token
: TokenTree
, span
: Span
) -> TokenTree
{
313 TokenTree
::Group(g
) => {
314 let stream
= respan_token_stream(g
.stream(), span
);
315 *g
= Group
::new(g
.delimiter(), stream
);
318 other
=> other
.set_span(span
),
323 // Parse string literal into a token stream with every span equal to the
324 // original literal's span.
325 let mut tokens
= crate::parse_str(&self.value())?
;
326 tokens
= respan_token_stream(tokens
, self.span());
328 parser
.parse2(tokens
)
331 pub fn span(&self) -> Span
{
332 self.repr
.token
.span()
335 pub fn set_span(&mut self, span
: Span
) {
336 self.repr
.token
.set_span(span
)
339 pub fn suffix(&self) -> &str {
345 pub fn new(value
: &[u8], span
: Span
) -> Self {
346 let mut token
= Literal
::byte_string(value
);
347 token
.set_span(span
);
351 pub fn value(&self) -> Vec
<u8> {
352 value
::parse_lit_byte_str(&self.token
.to_string())
355 pub fn span(&self) -> Span
{
359 pub fn set_span(&mut self, span
: Span
) {
360 self.token
.set_span(span
)
365 pub fn new(value
: u8, span
: Span
) -> Self {
366 let mut token
= Literal
::u8_suffixed(value
);
367 token
.set_span(span
);
371 pub fn value(&self) -> u8 {
372 value
::parse_lit_byte(&self.token
.to_string())
375 pub fn span(&self) -> Span
{
379 pub fn set_span(&mut self, span
: Span
) {
380 self.token
.set_span(span
)
385 pub fn new(value
: char, span
: Span
) -> Self {
386 let mut token
= Literal
::character(value
);
387 token
.set_span(span
);
391 pub fn value(&self) -> char {
392 value
::parse_lit_char(&self.token
.to_string())
395 pub fn span(&self) -> Span
{
399 pub fn set_span(&mut self, span
: Span
) {
400 self.token
.set_span(span
)
405 pub fn new(repr
: &str, span
: Span
) -> Self {
406 if let Some((digits
, suffix
)) = value
::parse_lit_int(repr
) {
407 let mut token
= value
::to_literal(repr
);
408 token
.set_span(span
);
410 repr
: Box
::new(LitIntRepr
{
417 panic
!("Not an integer literal: `{}`", repr
);
421 pub fn base10_digits(&self) -> &str {
425 /// Parses the literal into a selected number type.
427 /// This is equivalent to `lit.base10_digits().parse()` except that the
428 /// resulting errors will be correctly spanned to point to the literal token
429 /// in the macro input.
433 /// use syn::parse::{Parse, ParseStream, Result};
439 /// impl Parse for Port {
440 /// fn parse(input: ParseStream) -> Result<Self> {
441 /// let lit: LitInt = input.parse()?;
442 /// let value = lit.base10_parse::<u16>()?;
443 /// Ok(Port { value })
447 pub fn base10_parse
<N
>(&self) -> Result
<N
>
454 .map_err(|err
| Error
::new(self.span(), err
))
457 pub fn suffix(&self) -> &str {
461 pub fn span(&self) -> Span
{
462 self.repr
.token
.span()
465 pub fn set_span(&mut self, span
: Span
) {
466 self.repr
.token
.set_span(span
)
470 impl From
<Literal
> for LitInt
{
471 fn from(token
: Literal
) -> Self {
472 let repr
= token
.to_string();
473 if let Some((digits
, suffix
)) = value
::parse_lit_int(&repr
) {
475 repr
: Box
::new(LitIntRepr
{
482 panic
!("Not an integer literal: `{}`", repr
);
487 impl Display
for LitInt
{
488 fn fmt(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
{
489 self.repr
.token
.fmt(formatter
)
494 pub fn new(repr
: &str, span
: Span
) -> Self {
495 if let Some((digits
, suffix
)) = value
::parse_lit_float(repr
) {
496 let mut token
= value
::to_literal(repr
);
497 token
.set_span(span
);
499 repr
: Box
::new(LitFloatRepr
{
506 panic
!("Not a float literal: `{}`", repr
);
510 pub fn base10_digits(&self) -> &str {
514 pub fn base10_parse
<N
>(&self) -> Result
<N
>
521 .map_err(|err
| Error
::new(self.span(), err
))
524 pub fn suffix(&self) -> &str {
528 pub fn span(&self) -> Span
{
529 self.repr
.token
.span()
532 pub fn set_span(&mut self, span
: Span
) {
533 self.repr
.token
.set_span(span
)
537 impl From
<Literal
> for LitFloat
{
538 fn from(token
: Literal
) -> Self {
539 let repr
= token
.to_string();
540 if let Some((digits
, suffix
)) = value
::parse_lit_float(&repr
) {
542 repr
: Box
::new(LitFloatRepr
{
549 panic
!("Not a float literal: `{}`", repr
);
554 impl Display
for LitFloat
{
555 fn fmt(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
{
556 self.repr
.token
.fmt(formatter
)
560 #[cfg(feature = "extra-traits")]
563 use std
::fmt
::{self, Debug}
;
565 impl Debug
for LitStr
{
566 fn fmt(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
{
568 .debug_struct("LitStr")
569 .field("token", &format_args
!("{}", self.repr
.token
))
574 impl Debug
for LitByteStr
{
575 fn fmt(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
{
577 .debug_struct("LitByteStr")
578 .field("token", &format_args
!("{}", self.token
))
583 impl Debug
for LitByte
{
584 fn fmt(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
{
586 .debug_struct("LitByte")
587 .field("token", &format_args
!("{}", self.token
))
592 impl Debug
for LitChar
{
593 fn fmt(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
{
595 .debug_struct("LitChar")
596 .field("token", &format_args
!("{}", self.token
))
601 impl Debug
for LitInt
{
602 fn fmt(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
{
604 .debug_struct("LitInt")
605 .field("token", &format_args
!("{}", self.repr
.token
))
610 impl Debug
for LitFloat
{
611 fn fmt(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
{
613 .debug_struct("LitFloat")
614 .field("token", &format_args
!("{}", self.repr
.token
))
619 impl Debug
for LitBool
{
620 fn fmt(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
{
622 .debug_struct("LitBool")
623 .field("value", &self.value
)
629 macro_rules
! lit_extra_traits
{
630 ($ty
:ident
, $
($field
:ident
).+) => {
631 #[cfg(feature = "extra-traits")]
634 #[cfg(feature = "extra-traits")]
635 impl PartialEq
for $ty
{
636 fn eq(&self, other
: &Self) -> bool
{
637 self.$
($field
).+.to_string() == other
.$
($field
).+.to_string()
641 #[cfg(feature = "extra-traits")]
643 fn hash
<H
>(&self, state
: &mut H
)
647 self.$
($field
).+.to_string().hash(state
);
651 #[cfg(feature = "parsing")]
653 #[allow(non_snake_case)]
654 pub fn $
ty(marker
: lookahead
::TokenMarker
) -> $ty
{
660 lit_extra_traits
!(LitStr
, repr
.token
);
661 lit_extra_traits
!(LitByteStr
, token
);
662 lit_extra_traits
!(LitByte
, token
);
663 lit_extra_traits
!(LitChar
, token
);
664 lit_extra_traits
!(LitInt
, repr
.token
);
665 lit_extra_traits
!(LitFloat
, repr
.token
);
666 lit_extra_traits
!(LitBool
, value
);
669 /// The style of a string literal, either plain quoted or a raw string like
672 /// *This type is available if Syn is built with the `"derive"` or `"full"`
674 pub enum StrStyle
#no_visit {
675 /// An ordinary string like `"data"`.
677 /// A raw string like `r##"data"##`.
679 /// The unsigned integer is the number of `#` symbols used.
684 #[cfg(feature = "parsing")]
686 #[allow(non_snake_case)]
687 pub fn Lit(marker
: lookahead
::TokenMarker
) -> Lit
{
691 #[cfg(feature = "parsing")]
694 use crate::parse
::{Parse, ParseStream, Result}
;
697 fn parse(input
: ParseStream
) -> Result
<Self> {
698 input
.step(|cursor
| {
699 if let Some((lit
, rest
)) = cursor
.literal() {
700 return Ok((Lit
::new(lit
), rest
));
702 while let Some((ident
, rest
)) = cursor
.ident() {
703 let value
= if ident
== "true" {
705 } else if ident
== "false" {
710 let lit_bool
= LitBool
{
714 return Ok((Lit
::Bool(lit_bool
), rest
));
716 Err(cursor
.error("expected literal"))
721 impl Parse
for LitStr
{
722 fn parse(input
: ParseStream
) -> Result
<Self> {
723 let head
= input
.fork();
724 match input
.parse()?
{
725 Lit
::Str(lit
) => Ok(lit
),
726 _
=> Err(head
.error("expected string literal")),
731 impl Parse
for LitByteStr
{
732 fn parse(input
: ParseStream
) -> Result
<Self> {
733 let head
= input
.fork();
734 match input
.parse()?
{
735 Lit
::ByteStr(lit
) => Ok(lit
),
736 _
=> Err(head
.error("expected byte string literal")),
741 impl Parse
for LitByte
{
742 fn parse(input
: ParseStream
) -> Result
<Self> {
743 let head
= input
.fork();
744 match input
.parse()?
{
745 Lit
::Byte(lit
) => Ok(lit
),
746 _
=> Err(head
.error("expected byte literal")),
751 impl Parse
for LitChar
{
752 fn parse(input
: ParseStream
) -> Result
<Self> {
753 let head
= input
.fork();
754 match input
.parse()?
{
755 Lit
::Char(lit
) => Ok(lit
),
756 _
=> Err(head
.error("expected character literal")),
761 impl Parse
for LitInt
{
762 fn parse(input
: ParseStream
) -> Result
<Self> {
763 let head
= input
.fork();
764 match input
.parse()?
{
765 Lit
::Int(lit
) => Ok(lit
),
766 _
=> Err(head
.error("expected integer literal")),
771 impl Parse
for LitFloat
{
772 fn parse(input
: ParseStream
) -> Result
<Self> {
773 let head
= input
.fork();
774 match input
.parse()?
{
775 Lit
::Float(lit
) => Ok(lit
),
776 _
=> Err(head
.error("expected floating point literal")),
781 impl Parse
for LitBool
{
782 fn parse(input
: ParseStream
) -> Result
<Self> {
783 let head
= input
.fork();
784 match input
.parse()?
{
785 Lit
::Bool(lit
) => Ok(lit
),
786 _
=> Err(head
.error("expected boolean literal")),
792 #[cfg(feature = "printing")]
795 use proc_macro2
::TokenStream
;
796 use quote
::{ToTokens, TokenStreamExt}
;
798 impl ToTokens
for LitStr
{
799 fn to_tokens(&self, tokens
: &mut TokenStream
) {
800 self.repr
.token
.to_tokens(tokens
);
804 impl ToTokens
for LitByteStr
{
805 fn to_tokens(&self, tokens
: &mut TokenStream
) {
806 self.token
.to_tokens(tokens
);
810 impl ToTokens
for LitByte
{
811 fn to_tokens(&self, tokens
: &mut TokenStream
) {
812 self.token
.to_tokens(tokens
);
816 impl ToTokens
for LitChar
{
817 fn to_tokens(&self, tokens
: &mut TokenStream
) {
818 self.token
.to_tokens(tokens
);
822 impl ToTokens
for LitInt
{
823 fn to_tokens(&self, tokens
: &mut TokenStream
) {
824 self.repr
.token
.to_tokens(tokens
);
828 impl ToTokens
for LitFloat
{
829 fn to_tokens(&self, tokens
: &mut TokenStream
) {
830 self.repr
.token
.to_tokens(tokens
);
834 impl ToTokens
for LitBool
{
835 fn to_tokens(&self, tokens
: &mut TokenStream
) {
836 let s
= if self.value { "true" }
else { "false" }
;
837 tokens
.append(Ident
::new(s
, self.span
));
844 use crate::bigint
::BigInt
;
845 use proc_macro2
::TokenStream
;
847 use std
::ops
::{Index, RangeFrom}
;
850 /// Interpret a Syn literal from a proc-macro2 literal.
851 pub fn new(token
: Literal
) -> Self {
852 let repr
= token
.to_string();
854 match byte(&repr
, 0) {
856 let (_, suffix) = parse_lit_str(&repr);
857 return Lit::Str(LitStr {
858 repr: Box::new(LitStrRepr { token, suffix }),
861 b'b' => match byte(&repr, 1) {
863 return Lit
::ByteStr(LitByteStr { token }
);
866 return Lit
::Byte(LitByte { token }
);
871 return Lit
::Char(LitChar { token }
);
873 b'
0'
..=b'
9'
| b'
-'
=> {
874 if !(repr
.ends_with("f32") || repr
.ends_with("f64")) {
875 if let Some((digits
, suffix
)) = parse_lit_int(&repr
) {
876 return Lit
::Int(LitInt
{
877 repr
: Box
::new(LitIntRepr
{
885 if let Some((digits
, suffix
)) = parse_lit_float(&repr
) {
886 return Lit
::Float(LitFloat
{
887 repr
: Box
::new(LitFloatRepr
{
896 if repr
== "true" || repr
== "false" {
897 return Lit
::Bool(LitBool
{
898 value
: repr
== "true",
906 panic
!("Unrecognized literal: `{}`", repr
);
910 /// Get the byte at offset idx, or a default of `b'\0'` if we're looking
911 /// past the end of the input buffer.
912 pub fn byte
<S
: AsRef
<[u8]> + ?Sized
>(s
: &S
, idx
: usize) -> u8 {
921 fn next_chr(s
: &str) -> char {
922 s
.chars().next().unwrap_or('
\0'
)
925 // Returns (content, suffix).
926 pub fn parse_lit_str(s
: &str) -> (Box
<str>, Box
<str>) {
928 b'
"' => parse_lit_str_cooked(s),
929 b'r' => parse_lit_str_raw(s),
934 // Clippy false positive
935 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
936 #[allow(clippy::needless_continue)]
937 fn parse_lit_str_cooked(mut s: &str) -> (Box<str>, Box<str>) {
938 assert_eq!(byte(s, 0), b'"'
);
941 let mut content
= String
::new();
943 let ch
= match byte(s
, 0) {
950 let (byte, rest) = backslash_x(s);
952 assert!(byte <= 0x80, "Invalid
\\x byte
in string literal
");
953 char::from_u32(u32::from(byte)).unwrap()
956 let (chr, rest) = backslash_u(s);
967 b'\r' | b'\n' => loop {
968 let ch = next_chr(s);
969 if ch.is_whitespace() {
970 s = &s[ch.len_utf8()..];
975 b => panic!("unexpected byte {:?} after
\\ character
in byte literal
", b),
979 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed
in string
");
984 let ch = next_chr(s);
985 s = &s[ch.len_utf8()..];
992 assert!(s.starts_with('"'
));
993 let content
= content
.into_boxed_str();
994 let suffix
= s
[1..].to_owned().into_boxed_str();
998 fn parse_lit_str_raw(mut s
: &str) -> (Box
<str>, Box
<str>) {
999 assert_eq
!(byte(s
, 0), b'r'
);
1003 while byte(s
, pounds
) == b'
#' {
1006 assert_eq
!(byte(s
, pounds
), b'
"');
1007 assert_eq!(byte(s, s.len() - pounds - 1), b'"'
);
1008 for end
in s
[s
.len() - pounds
..].bytes() {
1009 assert_eq
!(end
, b'
#');
1012 let content
= s
[pounds
+ 1..s
.len() - pounds
- 1]
1015 let suffix
= Box
::<str>::default(); // todo
1019 pub fn parse_lit_byte_str(s
: &str) -> Vec
<u8> {
1020 assert_eq
!(byte(s
, 0), b'b'
);
1022 b'
"' => parse_lit_byte_str_cooked(s),
1023 b'r' => parse_lit_byte_str_raw(s),
1024 _ => unreachable!(),
1028 // Clippy false positive
1029 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
1030 #[allow(clippy::needless_continue)]
1031 fn parse_lit_byte_str_cooked(mut s: &str) -> Vec<u8> {
1032 assert_eq!(byte(s, 0), b'b');
1033 assert_eq!(byte(s, 1), b'"'
);
1036 // We're going to want to have slices which don't respect codepoint boundaries.
1037 let mut s
= s
.as_bytes();
1039 let mut out
= Vec
::new();
1041 let byte
= match byte(s
, 0) {
1048 let (b, rest) = backslash_x(s);
1059 b'\r' | b'\n' => loop {
1060 let byte = byte(s, 0);
1061 let ch = char::from_u32(u32::from(byte)).unwrap();
1062 if ch.is_whitespace() {
1068 b => panic!("unexpected byte {:?} after
\\ character
in byte literal
", b),
1072 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed
in string
");
1084 assert_eq!(s, b"\"");
1088 fn parse_lit_byte_str_raw(s: &str) -> Vec<u8> {
1089 assert_eq!(byte(s, 0), b'b');
1090 String::from(parse_lit_str_raw(&s[1..]).0).into_bytes()
1093 pub fn parse_lit_byte(s: &str) -> u8 {
1094 assert_eq!(byte(s, 0), b'b');
1095 assert_eq!(byte(s, 1), b'\'');
1097 // We're going to want to have slices which don't respect codepoint boundaries.
1098 let mut s = s[2..].as_bytes();
1100 let b = match byte(s, 0) {
1106 let (b, rest) = backslash_x(s);
1117 b => panic!("unexpected byte {:?} after
\\ character
in byte literal
", b),
1126 assert_eq!(byte(s, 0), b'\'');
1130 pub fn parse_lit_char(mut s: &str) -> char {
1131 assert_eq!(byte(s, 0), b'\'');
1134 let ch = match byte(s, 0) {
1140 let (byte, rest) = backslash_x(s);
1142 assert!(byte <= 0x80, "Invalid
\\x byte
in string literal
");
1143 char::from_u32(u32::from(byte)).unwrap()
1146 let (chr, rest) = backslash_u(s);
1157 b => panic!("unexpected byte {:?} after
\\ character
in byte literal
", b),
1161 let ch = next_chr(s);
1162 s = &s[ch.len_utf8()..];
1166 assert_eq!(s, "\'", "Expected end of
char literal
");
1170 fn backslash_x<S>(s: &S) -> (u8, &S)
1172 S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
1175 let b0 = byte(s, 0);
1176 let b1 = byte(s, 1);
1179 b'0'..=b'9' => b0 - b'0',
1180 b'a'..=b'f' => 10 + (b0 - b'a'),
1181 b'A'..=b'F' => 10 + (b0 - b'A'),
1182 _ => panic!("unexpected non
-hex character after
\\x
"),
1185 b'0'..=b'9' => b1 - b'0',
1186 b'a'..=b'f' => 10 + (b1 - b'a'),
1187 b'A'..=b'F' => 10 + (b1 - b'A'),
1188 _ => panic!("unexpected non
-hex character after
\\x
"),
1193 fn backslash_u(mut s: &str) -> (char, &str) {
1194 if byte(s, 0) != b'{' {
1195 panic!("expected
{{ after
\\u
");
1205 ch += u32::from(b - b'0');
1210 ch += u32::from(10 + b - b'a');
1215 ch += u32::from(10 + b - b'A');
1219 _ => panic!("unexpected non
-hex character after
\\u
"),
1222 assert!(byte(s, 0) == b'}');
1225 if let Some(ch) = char::from_u32(ch) {
1228 panic!("character code {:x} is not a valid unicode character
", ch);
1232 // Returns base 10 digits and suffix.
1233 pub fn parse_lit_int(mut s: &str) -> Option<(Box<str>, Box<str>)> {
1234 let negative = byte(s, 0) == b'-';
1239 let base = match (byte(s, 0), byte(s, 1)) {
1252 (b'0'..=b'9', _) => 10,
1256 let mut value = BigInt::new();
1259 let digit = match b {
1260 b'0'..=b'9' => b - b'0',
1261 b'a'..=b'f' if base > 10 => b - b'a' + 10,
1262 b'A'..=b'F' if base > 10 => b - b'A' + 10,
1267 // NOTE: Looking at a floating point literal, we don't want to
1268 // consider these integers.
1269 b'.' if base == 10 => return None,
1270 b'e' | b'E' if base == 10 => return None,
1284 if suffix.is_empty() || crate::ident::xid_ok(&suffix) {
1285 let mut repr = value.to_string();
1287 repr.insert(0, '-');
1289 Some((repr.into_boxed_str(), suffix.to_owned().into_boxed_str()))
1295 // Returns base 10 digits and suffix.
1296 pub fn parse_lit_float(input: &str) -> Option<(Box<str>, Box<str>)> {
1297 // Rust's floating point literals are very similar to the ones parsed by
1298 // the standard library, except that rust's literals can contain
1299 // ignorable underscores. Let's remove those underscores.
1301 let mut bytes = input.to_owned().into_bytes();
1303 let start = (*bytes.get(0)? == b'-') as usize;
1304 match bytes.get(start)? {
1309 let mut read = start;
1310 let mut write = start;
1311 let mut has_dot = false;
1312 let mut has_e = false;
1313 let mut has_sign = false;
1314 let mut has_exponent = false;
1315 while read < bytes.len() {
1318 // Don't increase write
1324 has_exponent = true;
1326 bytes[write] = bytes[read];
1329 if has_e || has_dot {
1333 bytes[write] = b'.';
1340 bytes[write] = b'e';
1343 if has_sign || has_exponent || !has_e {
1347 if bytes[read] == b'-' {
1348 bytes[write] = bytes[read];
1361 if has_e && !has_exponent {
1365 let mut digits = String::from_utf8(bytes).unwrap();
1366 let suffix = digits.split_off(read);
1367 digits.truncate(write);
1368 if suffix.is_empty() || crate::ident::xid_ok(&suffix) {
1369 Some((digits.into_boxed_str(), suffix.into_boxed_str()))
1375 pub fn to_literal(s: &str) -> Literal {
1376 let stream = s.parse::<TokenStream>().unwrap();
1377 match stream.into_iter().next().unwrap() {
1378 TokenTree::Literal(l) => l,
1379 _ => unreachable!(),