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