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