1#[cfg(feature = "parsing")]
2use crate::lookahead;
3#[cfg(feature = "parsing")]
4use crate::parse::{Parse, Parser};
5use crate::{Error, Result};
6use proc_macro2::{Ident, Literal, Span};
7#[cfg(feature = "parsing")]
8use proc_macro2::{TokenStream, TokenTree};
9use std::ffi::{CStr, CString};
10use std::fmt::{self, Display};
11#[cfg(feature = "extra-traits")]
12use std::hash::{Hash, Hasher};
13use std::str::{self, FromStr};
14
15ast_enum_of_structs! {
16 #[non_exhaustive]
24 pub enum Lit {
25 Str(LitStr),
27
28 ByteStr(LitByteStr),
30
31 CStr(LitCStr),
33
34 Byte(LitByte),
36
37 Char(LitChar),
39
40 Int(LitInt),
42
43 Float(LitFloat),
47
48 Bool(LitBool),
50
51 Verbatim(Literal),
53 }
54}
55
56ast_struct! {
57 pub struct LitStr {
59 repr: Box<LitRepr>,
60 }
61}
62
63ast_struct! {
64 pub struct LitByteStr {
66 repr: Box<LitRepr>,
67 }
68}
69
70ast_struct! {
71 pub struct LitCStr {
73 repr: Box<LitRepr>,
74 }
75}
76
77ast_struct! {
78 pub struct LitByte {
80 repr: Box<LitRepr>,
81 }
82}
83
84ast_struct! {
85 pub struct LitChar {
87 repr: Box<LitRepr>,
88 }
89}
90
91struct LitRepr {
92 token: Literal,
93 suffix: Box<str>,
94}
95
96ast_struct! {
97 pub struct LitInt {
99 repr: Box<LitIntRepr>,
100 }
101}
102
103struct LitIntRepr {
104 token: Literal,
105 digits: Box<str>,
106 suffix: Box<str>,
107}
108
109ast_struct! {
110 pub struct LitFloat {
114 repr: Box<LitFloatRepr>,
115 }
116}
117
118struct LitFloatRepr {
119 token: Literal,
120 digits: Box<str>,
121 suffix: Box<str>,
122}
123
124ast_struct! {
125 pub struct LitBool {
127 pub value: bool,
128 pub span: Span,
129 }
130}
131
132impl LitStr {
133 pub fn new(value: &str, span: Span) -> Self {
134 let mut token = Literal::string(value);
135 token.set_span(span);
136 LitStr {
137 repr: Box::new(LitRepr {
138 token,
139 suffix: Box::<str>::default(),
140 }),
141 }
142 }
143
144 pub fn value(&self) -> String {
145 let repr = self.repr.token.to_string();
146 let (value, _suffix) = value::parse_lit_str(&repr);
147 String::from(value)
148 }
149
150 #[cfg(feature = "parsing")]
182 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
183 pub fn parse<T: Parse>(&self) -> Result<T> {
184 self.parse_with(T::parse)
185 }
186
187 #[cfg(feature = "parsing")]
212 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
213 pub fn parse_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
214 use proc_macro2::Group;
215
216 fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
218 stream
219 .into_iter()
220 .map(|token| respan_token_tree(token, span))
221 .collect()
222 }
223
224 fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
226 match &mut token {
227 TokenTree::Group(g) => {
228 let stream = respan_token_stream(g.stream(), span);
229 *g = Group::new(g.delimiter(), stream);
230 g.set_span(span);
231 }
232 other => other.set_span(span),
233 }
234 token
235 }
236
237 let span = self.span();
240 let mut tokens = TokenStream::from_str(&self.value())?;
241 tokens = respan_token_stream(tokens, span);
242
243 let result = crate::parse::parse_scoped(parser, span, tokens)?;
244
245 let suffix = self.suffix();
246 if !suffix.is_empty() {
247 return Err(Error::new(
248 self.span(),
249 format!("unexpected suffix `{}` on string literal", suffix),
250 ));
251 }
252
253 Ok(result)
254 }
255
256 pub fn span(&self) -> Span {
257 self.repr.token.span()
258 }
259
260 pub fn set_span(&mut self, span: Span) {
261 self.repr.token.set_span(span);
262 }
263
264 pub fn suffix(&self) -> &str {
265 &self.repr.suffix
266 }
267
268 pub fn token(&self) -> Literal {
269 self.repr.token.clone()
270 }
271}
272
273impl LitByteStr {
274 pub fn new(value: &[u8], span: Span) -> Self {
275 let mut token = Literal::byte_string(value);
276 token.set_span(span);
277 LitByteStr {
278 repr: Box::new(LitRepr {
279 token,
280 suffix: Box::<str>::default(),
281 }),
282 }
283 }
284
285 pub fn value(&self) -> Vec<u8> {
286 let repr = self.repr.token.to_string();
287 let (value, _suffix) = value::parse_lit_byte_str(&repr);
288 value
289 }
290
291 pub fn span(&self) -> Span {
292 self.repr.token.span()
293 }
294
295 pub fn set_span(&mut self, span: Span) {
296 self.repr.token.set_span(span);
297 }
298
299 pub fn suffix(&self) -> &str {
300 &self.repr.suffix
301 }
302
303 pub fn token(&self) -> Literal {
304 self.repr.token.clone()
305 }
306}
307
308impl LitCStr {
309 pub fn new(value: &CStr, span: Span) -> Self {
310 let mut token = Literal::c_string(value);
311 token.set_span(span);
312 LitCStr {
313 repr: Box::new(LitRepr {
314 token,
315 suffix: Box::<str>::default(),
316 }),
317 }
318 }
319
320 pub fn value(&self) -> CString {
321 let repr = self.repr.token.to_string();
322 let (value, _suffix) = value::parse_lit_c_str(&repr);
323 value
324 }
325
326 pub fn span(&self) -> Span {
327 self.repr.token.span()
328 }
329
330 pub fn set_span(&mut self, span: Span) {
331 self.repr.token.set_span(span);
332 }
333
334 pub fn suffix(&self) -> &str {
335 &self.repr.suffix
336 }
337
338 pub fn token(&self) -> Literal {
339 self.repr.token.clone()
340 }
341}
342
343impl LitByte {
344 pub fn new(value: u8, span: Span) -> Self {
345 let mut token = Literal::u8_suffixed(value);
346 token.set_span(span);
347 LitByte {
348 repr: Box::new(LitRepr {
349 token,
350 suffix: Box::<str>::default(),
351 }),
352 }
353 }
354
355 pub fn value(&self) -> u8 {
356 let repr = self.repr.token.to_string();
357 let (value, _suffix) = value::parse_lit_byte(&repr);
358 value
359 }
360
361 pub fn span(&self) -> Span {
362 self.repr.token.span()
363 }
364
365 pub fn set_span(&mut self, span: Span) {
366 self.repr.token.set_span(span);
367 }
368
369 pub fn suffix(&self) -> &str {
370 &self.repr.suffix
371 }
372
373 pub fn token(&self) -> Literal {
374 self.repr.token.clone()
375 }
376}
377
378impl LitChar {
379 pub fn new(value: char, span: Span) -> Self {
380 let mut token = Literal::character(value);
381 token.set_span(span);
382 LitChar {
383 repr: Box::new(LitRepr {
384 token,
385 suffix: Box::<str>::default(),
386 }),
387 }
388 }
389
390 pub fn value(&self) -> char {
391 let repr = self.repr.token.to_string();
392 let (value, _suffix) = value::parse_lit_char(&repr);
393 value
394 }
395
396 pub fn span(&self) -> Span {
397 self.repr.token.span()
398 }
399
400 pub fn set_span(&mut self, span: Span) {
401 self.repr.token.set_span(span);
402 }
403
404 pub fn suffix(&self) -> &str {
405 &self.repr.suffix
406 }
407
408 pub fn token(&self) -> Literal {
409 self.repr.token.clone()
410 }
411}
412
413impl LitInt {
414 pub fn new(repr: &str, span: Span) -> Self {
415 let (digits, suffix) = match value::parse_lit_int(repr) {
416 Some(parse) => parse,
417 None => panic!("not an integer literal: `{}`", repr),
418 };
419
420 let mut token: Literal = repr.parse().unwrap();
421 token.set_span(span);
422 LitInt {
423 repr: Box::new(LitIntRepr {
424 token,
425 digits,
426 suffix,
427 }),
428 }
429 }
430
431 pub fn base10_digits(&self) -> &str {
432 &self.repr.digits
433 }
434
435 pub fn base10_parse<N>(&self) -> Result<N>
458 where
459 N: FromStr,
460 N::Err: Display,
461 {
462 self.base10_digits()
463 .parse()
464 .map_err(|err| Error::new(self.span(), err))
465 }
466
467 pub fn suffix(&self) -> &str {
468 &self.repr.suffix
469 }
470
471 pub fn span(&self) -> Span {
472 self.repr.token.span()
473 }
474
475 pub fn set_span(&mut self, span: Span) {
476 self.repr.token.set_span(span);
477 }
478
479 pub fn token(&self) -> Literal {
480 self.repr.token.clone()
481 }
482}
483
484impl From<Literal> for LitInt {
485 fn from(token: Literal) -> Self {
486 let repr = token.to_string();
487 if let Some((digits, suffix)) = value::parse_lit_int(&repr) {
488 LitInt {
489 repr: Box::new(LitIntRepr {
490 token,
491 digits,
492 suffix,
493 }),
494 }
495 } else {
496 panic!("not an integer literal: `{}`", repr);
497 }
498 }
499}
500
501impl Display for LitInt {
502 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
503 self.repr.token.fmt(formatter)
504 }
505}
506
507impl LitFloat {
508 pub fn new(repr: &str, span: Span) -> Self {
509 let (digits, suffix) = match value::parse_lit_float(repr) {
510 Some(parse) => parse,
511 None => panic!("not a float literal: `{}`", repr),
512 };
513
514 let mut token: Literal = repr.parse().unwrap();
515 token.set_span(span);
516 LitFloat {
517 repr: Box::new(LitFloatRepr {
518 token,
519 digits,
520 suffix,
521 }),
522 }
523 }
524
525 pub fn base10_digits(&self) -> &str {
526 &self.repr.digits
527 }
528
529 pub fn base10_parse<N>(&self) -> Result<N>
530 where
531 N: FromStr,
532 N::Err: Display,
533 {
534 self.base10_digits()
535 .parse()
536 .map_err(|err| Error::new(self.span(), err))
537 }
538
539 pub fn suffix(&self) -> &str {
540 &self.repr.suffix
541 }
542
543 pub fn span(&self) -> Span {
544 self.repr.token.span()
545 }
546
547 pub fn set_span(&mut self, span: Span) {
548 self.repr.token.set_span(span);
549 }
550
551 pub fn token(&self) -> Literal {
552 self.repr.token.clone()
553 }
554}
555
556impl From<Literal> for LitFloat {
557 fn from(token: Literal) -> Self {
558 let repr = token.to_string();
559 if let Some((digits, suffix)) = value::parse_lit_float(&repr) {
560 LitFloat {
561 repr: Box::new(LitFloatRepr {
562 token,
563 digits,
564 suffix,
565 }),
566 }
567 } else {
568 panic!("not a float literal: `{}`", repr);
569 }
570 }
571}
572
573impl Display for LitFloat {
574 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
575 self.repr.token.fmt(formatter)
576 }
577}
578
579impl LitBool {
580 pub fn new(value: bool, span: Span) -> Self {
581 LitBool { value, span }
582 }
583
584 pub fn value(&self) -> bool {
585 self.value
586 }
587
588 pub fn span(&self) -> Span {
589 self.span
590 }
591
592 pub fn set_span(&mut self, span: Span) {
593 self.span = span;
594 }
595
596 pub fn token(&self) -> Ident {
597 let s = if self.value { "true" } else { "false" };
598 Ident::new(s, self.span)
599 }
600}
601
602#[cfg(feature = "extra-traits")]
603mod debug_impls {
604 use crate::lit::{LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitInt, LitStr};
605 use std::fmt::{self, Debug};
606
607 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
608 impl Debug for LitStr {
609 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
610 self.debug(formatter, "LitStr")
611 }
612 }
613
614 impl LitStr {
615 pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
616 formatter
617 .debug_struct(name)
618 .field("token", &format_args!("{}", self.repr.token))
619 .finish()
620 }
621 }
622
623 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
624 impl Debug for LitByteStr {
625 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
626 self.debug(formatter, "LitByteStr")
627 }
628 }
629
630 impl LitByteStr {
631 pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
632 formatter
633 .debug_struct(name)
634 .field("token", &format_args!("{}", self.repr.token))
635 .finish()
636 }
637 }
638
639 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
640 impl Debug for LitCStr {
641 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
642 self.debug(formatter, "LitCStr")
643 }
644 }
645
646 impl LitCStr {
647 pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
648 formatter
649 .debug_struct(name)
650 .field("token", &format_args!("{}", self.repr.token))
651 .finish()
652 }
653 }
654
655 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
656 impl Debug for LitByte {
657 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
658 self.debug(formatter, "LitByte")
659 }
660 }
661
662 impl LitByte {
663 pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
664 formatter
665 .debug_struct(name)
666 .field("token", &format_args!("{}", self.repr.token))
667 .finish()
668 }
669 }
670
671 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
672 impl Debug for LitChar {
673 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
674 self.debug(formatter, "LitChar")
675 }
676 }
677
678 impl LitChar {
679 pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
680 formatter
681 .debug_struct(name)
682 .field("token", &format_args!("{}", self.repr.token))
683 .finish()
684 }
685 }
686
687 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
688 impl Debug for LitInt {
689 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
690 self.debug(formatter, "LitInt")
691 }
692 }
693
694 impl LitInt {
695 pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
696 formatter
697 .debug_struct(name)
698 .field("token", &format_args!("{}", self.repr.token))
699 .finish()
700 }
701 }
702
703 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
704 impl Debug for LitFloat {
705 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
706 self.debug(formatter, "LitFloat")
707 }
708 }
709
710 impl LitFloat {
711 pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
712 formatter
713 .debug_struct(name)
714 .field("token", &format_args!("{}", self.repr.token))
715 .finish()
716 }
717 }
718
719 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
720 impl Debug for LitBool {
721 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
722 self.debug(formatter, "LitBool")
723 }
724 }
725
726 impl LitBool {
727 pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
728 formatter
729 .debug_struct(name)
730 .field("value", &self.value)
731 .finish()
732 }
733 }
734}
735
736#[cfg(feature = "clone-impls")]
737#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
738impl Clone for LitRepr {
739 fn clone(&self) -> Self {
740 LitRepr {
741 token: self.token.clone(),
742 suffix: self.suffix.clone(),
743 }
744 }
745}
746
747#[cfg(feature = "clone-impls")]
748#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
749impl Clone for LitIntRepr {
750 fn clone(&self) -> Self {
751 LitIntRepr {
752 token: self.token.clone(),
753 digits: self.digits.clone(),
754 suffix: self.suffix.clone(),
755 }
756 }
757}
758
759#[cfg(feature = "clone-impls")]
760#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
761impl Clone for LitFloatRepr {
762 fn clone(&self) -> Self {
763 LitFloatRepr {
764 token: self.token.clone(),
765 digits: self.digits.clone(),
766 suffix: self.suffix.clone(),
767 }
768 }
769}
770
771macro_rules! lit_extra_traits {
772 ($ty:ident) => {
773 #[cfg(feature = "clone-impls")]
774 #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
775 impl Clone for $ty {
776 fn clone(&self) -> Self {
777 $ty {
778 repr: self.repr.clone(),
779 }
780 }
781 }
782
783 #[cfg(feature = "extra-traits")]
784 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
785 impl PartialEq for $ty {
786 fn eq(&self, other: &Self) -> bool {
787 self.repr.token.to_string() == other.repr.token.to_string()
788 }
789 }
790
791 #[cfg(feature = "extra-traits")]
792 #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
793 impl Hash for $ty {
794 fn hash<H>(&self, state: &mut H)
795 where
796 H: Hasher,
797 {
798 self.repr.token.to_string().hash(state);
799 }
800 }
801
802 #[cfg(feature = "parsing")]
803 pub_if_not_doc! {
804 #[doc(hidden)]
805 #[allow(non_snake_case)]
806 pub fn $ty(marker: lookahead::TokenMarker) -> $ty {
807 match marker {}
808 }
809 }
810 };
811}
812
813lit_extra_traits!(LitStr);
814lit_extra_traits!(LitByteStr);
815lit_extra_traits!(LitCStr);
816lit_extra_traits!(LitByte);
817lit_extra_traits!(LitChar);
818lit_extra_traits!(LitInt);
819lit_extra_traits!(LitFloat);
820
821#[cfg(feature = "parsing")]
822pub_if_not_doc! {
823 #[doc(hidden)]
824 #[allow(non_snake_case)]
825 pub fn LitBool(marker: lookahead::TokenMarker) -> LitBool {
826 match marker {}
827 }
828}
829
830#[doc(hidden)] pub enum StrStyle {
834 Cooked,
836 Raw(usize),
840}
841
842#[cfg(feature = "parsing")]
843pub_if_not_doc! {
844 #[doc(hidden)]
845 #[allow(non_snake_case)]
846 pub fn Lit(marker: lookahead::TokenMarker) -> Lit {
847 match marker {}
848 }
849}
850
851#[cfg(feature = "parsing")]
852pub(crate) mod parsing {
853 use crate::buffer::Cursor;
854 use crate::error::Result;
855 use crate::lit::{
856 value, Lit, LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitFloatRepr, LitInt,
857 LitIntRepr, LitStr,
858 };
859 use crate::parse::{Parse, ParseStream, Unexpected};
860 use crate::token::{self, Token};
861 use proc_macro2::{Literal, Punct, Span};
862 use std::cell::Cell;
863 use std::rc::Rc;
864
865 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
866 impl Parse for Lit {
867 fn parse(input: ParseStream) -> Result<Self> {
868 input.step(|cursor| {
869 if let Some((lit, rest)) = cursor.literal() {
870 return Ok((Lit::new(lit), rest));
871 }
872
873 if let Some((ident, rest)) = cursor.ident() {
874 let value = ident == "true";
875 if value || ident == "false" {
876 let lit_bool = LitBool {
877 value,
878 span: ident.span(),
879 };
880 return Ok((Lit::Bool(lit_bool), rest));
881 }
882 }
883
884 if let Some((punct, rest)) = cursor.punct() {
885 if punct.as_char() == '-' {
886 if let Some((lit, rest)) = parse_negative_lit(punct, rest) {
887 return Ok((lit, rest));
888 }
889 }
890 }
891
892 Err(cursor.error("expected literal"))
893 })
894 }
895 }
896
897 fn parse_negative_lit(neg: Punct, cursor: Cursor) -> Option<(Lit, Cursor)> {
898 let (lit, rest) = cursor.literal()?;
899
900 let mut span = neg.span();
901 span = span.join(lit.span()).unwrap_or(span);
902
903 let mut repr = lit.to_string();
904 repr.insert(0, '-');
905
906 if let Some((digits, suffix)) = value::parse_lit_int(&repr) {
907 let mut token: Literal = repr.parse().unwrap();
908 token.set_span(span);
909 return Some((
910 Lit::Int(LitInt {
911 repr: Box::new(LitIntRepr {
912 token,
913 digits,
914 suffix,
915 }),
916 }),
917 rest,
918 ));
919 }
920
921 let (digits, suffix) = value::parse_lit_float(&repr)?;
922 let mut token: Literal = repr.parse().unwrap();
923 token.set_span(span);
924 Some((
925 Lit::Float(LitFloat {
926 repr: Box::new(LitFloatRepr {
927 token,
928 digits,
929 suffix,
930 }),
931 }),
932 rest,
933 ))
934 }
935
936 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
937 impl Parse for LitStr {
938 fn parse(input: ParseStream) -> Result<Self> {
939 let head = input.fork();
940 match input.parse() {
941 Ok(Lit::Str(lit)) => Ok(lit),
942 _ => Err(head.error("expected string literal")),
943 }
944 }
945 }
946
947 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
948 impl Parse for LitByteStr {
949 fn parse(input: ParseStream) -> Result<Self> {
950 let head = input.fork();
951 match input.parse() {
952 Ok(Lit::ByteStr(lit)) => Ok(lit),
953 _ => Err(head.error("expected byte string literal")),
954 }
955 }
956 }
957
958 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
959 impl Parse for LitCStr {
960 fn parse(input: ParseStream) -> Result<Self> {
961 let head = input.fork();
962 match input.parse() {
963 Ok(Lit::CStr(lit)) => Ok(lit),
964 _ => Err(head.error("expected C string literal")),
965 }
966 }
967 }
968
969 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
970 impl Parse for LitByte {
971 fn parse(input: ParseStream) -> Result<Self> {
972 let head = input.fork();
973 match input.parse() {
974 Ok(Lit::Byte(lit)) => Ok(lit),
975 _ => Err(head.error("expected byte literal")),
976 }
977 }
978 }
979
980 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
981 impl Parse for LitChar {
982 fn parse(input: ParseStream) -> Result<Self> {
983 let head = input.fork();
984 match input.parse() {
985 Ok(Lit::Char(lit)) => Ok(lit),
986 _ => Err(head.error("expected character literal")),
987 }
988 }
989 }
990
991 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
992 impl Parse for LitInt {
993 fn parse(input: ParseStream) -> Result<Self> {
994 let head = input.fork();
995 match input.parse() {
996 Ok(Lit::Int(lit)) => Ok(lit),
997 _ => Err(head.error("expected integer literal")),
998 }
999 }
1000 }
1001
1002 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
1003 impl Parse for LitFloat {
1004 fn parse(input: ParseStream) -> Result<Self> {
1005 let head = input.fork();
1006 match input.parse() {
1007 Ok(Lit::Float(lit)) => Ok(lit),
1008 _ => Err(head.error("expected floating point literal")),
1009 }
1010 }
1011 }
1012
1013 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
1014 impl Parse for LitBool {
1015 fn parse(input: ParseStream) -> Result<Self> {
1016 let head = input.fork();
1017 match input.parse() {
1018 Ok(Lit::Bool(lit)) => Ok(lit),
1019 _ => Err(head.error("expected boolean literal")),
1020 }
1021 }
1022 }
1023
1024 fn peek_impl(cursor: Cursor, peek: fn(ParseStream) -> bool) -> bool {
1025 let scope = Span::call_site();
1026 let unexpected = Rc::new(Cell::new(Unexpected::None));
1027 let buffer = crate::parse::new_parse_buffer(scope, cursor, unexpected);
1028 peek(&buffer)
1029 }
1030
1031 macro_rules! impl_token {
1032 ($display:literal $name:ty) => {
1033 impl Token for $name {
1034 fn peek(cursor: Cursor) -> bool {
1035 fn peek(input: ParseStream) -> bool {
1036 <$name as Parse>::parse(input).is_ok()
1037 }
1038 peek_impl(cursor, peek)
1039 }
1040
1041 fn display() -> &'static str {
1042 $display
1043 }
1044 }
1045
1046 impl token::private::Sealed for $name {}
1047 };
1048 }
1049
1050 impl_token!("literal" Lit);
1051 impl_token!("string literal" LitStr);
1052 impl_token!("byte string literal" LitByteStr);
1053 impl_token!("C-string literal" LitCStr);
1054 impl_token!("byte literal" LitByte);
1055 impl_token!("character literal" LitChar);
1056 impl_token!("integer literal" LitInt);
1057 impl_token!("floating point literal" LitFloat);
1058 impl_token!("boolean literal" LitBool);
1059}
1060
1061#[cfg(feature = "printing")]
1062mod printing {
1063 use crate::lit::{LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitInt, LitStr};
1064 use proc_macro2::TokenStream;
1065 use quote::{ToTokens, TokenStreamExt};
1066
1067 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
1068 impl ToTokens for LitStr {
1069 fn to_tokens(&self, tokens: &mut TokenStream) {
1070 self.repr.token.to_tokens(tokens);
1071 }
1072 }
1073
1074 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
1075 impl ToTokens for LitByteStr {
1076 fn to_tokens(&self, tokens: &mut TokenStream) {
1077 self.repr.token.to_tokens(tokens);
1078 }
1079 }
1080
1081 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
1082 impl ToTokens for LitCStr {
1083 fn to_tokens(&self, tokens: &mut TokenStream) {
1084 self.repr.token.to_tokens(tokens);
1085 }
1086 }
1087
1088 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
1089 impl ToTokens for LitByte {
1090 fn to_tokens(&self, tokens: &mut TokenStream) {
1091 self.repr.token.to_tokens(tokens);
1092 }
1093 }
1094
1095 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
1096 impl ToTokens for LitChar {
1097 fn to_tokens(&self, tokens: &mut TokenStream) {
1098 self.repr.token.to_tokens(tokens);
1099 }
1100 }
1101
1102 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
1103 impl ToTokens for LitInt {
1104 fn to_tokens(&self, tokens: &mut TokenStream) {
1105 self.repr.token.to_tokens(tokens);
1106 }
1107 }
1108
1109 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
1110 impl ToTokens for LitFloat {
1111 fn to_tokens(&self, tokens: &mut TokenStream) {
1112 self.repr.token.to_tokens(tokens);
1113 }
1114 }
1115
1116 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
1117 impl ToTokens for LitBool {
1118 fn to_tokens(&self, tokens: &mut TokenStream) {
1119 tokens.append(self.token());
1120 }
1121 }
1122}
1123
1124mod value {
1125 use crate::bigint::BigInt;
1126 use crate::lit::{
1127 Lit, LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitFloatRepr, LitInt,
1128 LitIntRepr, LitRepr, LitStr,
1129 };
1130 use proc_macro2::{Literal, Span};
1131 use std::ascii;
1132 use std::char;
1133 use std::ffi::CString;
1134 use std::ops::{Index, RangeFrom};
1135
1136 impl Lit {
1137 pub fn new(token: Literal) -> Self {
1139 let repr = token.to_string();
1140
1141 match byte(&repr, 0) {
1142 b'"' | b'r' => {
1144 let (_, suffix) = parse_lit_str(&repr);
1145 return Lit::Str(LitStr {
1146 repr: Box::new(LitRepr { token, suffix }),
1147 });
1148 }
1149 b'b' => match byte(&repr, 1) {
1150 b'"' | b'r' => {
1152 let (_, suffix) = parse_lit_byte_str(&repr);
1153 return Lit::ByteStr(LitByteStr {
1154 repr: Box::new(LitRepr { token, suffix }),
1155 });
1156 }
1157 b'\'' => {
1159 let (_, suffix) = parse_lit_byte(&repr);
1160 return Lit::Byte(LitByte {
1161 repr: Box::new(LitRepr { token, suffix }),
1162 });
1163 }
1164 _ => {}
1165 },
1166 b'c' => {
1168 let (_, suffix) = parse_lit_c_str(&repr);
1169 return Lit::CStr(LitCStr {
1170 repr: Box::new(LitRepr { token, suffix }),
1171 });
1172 }
1173 b'\'' => {
1175 let (_, suffix) = parse_lit_char(&repr);
1176 return Lit::Char(LitChar {
1177 repr: Box::new(LitRepr { token, suffix }),
1178 });
1179 }
1180 b'0'..=b'9' | b'-' => {
1181 if let Some((digits, suffix)) = parse_lit_int(&repr) {
1183 return Lit::Int(LitInt {
1184 repr: Box::new(LitIntRepr {
1185 token,
1186 digits,
1187 suffix,
1188 }),
1189 });
1190 }
1191 if let Some((digits, suffix)) = parse_lit_float(&repr) {
1193 return Lit::Float(LitFloat {
1194 repr: Box::new(LitFloatRepr {
1195 token,
1196 digits,
1197 suffix,
1198 }),
1199 });
1200 }
1201 }
1202 b't' | b'f' => {
1204 if repr == "true" || repr == "false" {
1205 return Lit::Bool(LitBool {
1206 value: repr == "true",
1207 span: token.span(),
1208 });
1209 }
1210 }
1211 b'(' if repr == "(/*ERROR*/)" => return Lit::Verbatim(token),
1212 _ => {}
1213 }
1214
1215 panic!("unrecognized literal: `{}`", repr);
1216 }
1217
1218 pub fn suffix(&self) -> &str {
1219 match self {
1220 Lit::Str(lit) => lit.suffix(),
1221 Lit::ByteStr(lit) => lit.suffix(),
1222 Lit::CStr(lit) => lit.suffix(),
1223 Lit::Byte(lit) => lit.suffix(),
1224 Lit::Char(lit) => lit.suffix(),
1225 Lit::Int(lit) => lit.suffix(),
1226 Lit::Float(lit) => lit.suffix(),
1227 Lit::Bool(_) | Lit::Verbatim(_) => "",
1228 }
1229 }
1230
1231 pub fn span(&self) -> Span {
1232 match self {
1233 Lit::Str(lit) => lit.span(),
1234 Lit::ByteStr(lit) => lit.span(),
1235 Lit::CStr(lit) => lit.span(),
1236 Lit::Byte(lit) => lit.span(),
1237 Lit::Char(lit) => lit.span(),
1238 Lit::Int(lit) => lit.span(),
1239 Lit::Float(lit) => lit.span(),
1240 Lit::Bool(lit) => lit.span,
1241 Lit::Verbatim(lit) => lit.span(),
1242 }
1243 }
1244
1245 pub fn set_span(&mut self, span: Span) {
1246 match self {
1247 Lit::Str(lit) => lit.set_span(span),
1248 Lit::ByteStr(lit) => lit.set_span(span),
1249 Lit::CStr(lit) => lit.set_span(span),
1250 Lit::Byte(lit) => lit.set_span(span),
1251 Lit::Char(lit) => lit.set_span(span),
1252 Lit::Int(lit) => lit.set_span(span),
1253 Lit::Float(lit) => lit.set_span(span),
1254 Lit::Bool(lit) => lit.span = span,
1255 Lit::Verbatim(lit) => lit.set_span(span),
1256 }
1257 }
1258 }
1259
1260 pub(crate) fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 {
1263 let s = s.as_ref();
1264 if idx < s.len() {
1265 s[idx]
1266 } else {
1267 0
1268 }
1269 }
1270
1271 fn next_chr(s: &str) -> char {
1272 s.chars().next().unwrap_or('\0')
1273 }
1274
1275 pub(crate) fn parse_lit_str(s: &str) -> (Box<str>, Box<str>) {
1277 match byte(s, 0) {
1278 b'"' => parse_lit_str_cooked(s),
1279 b'r' => parse_lit_str_raw(s),
1280 _ => unreachable!(),
1281 }
1282 }
1283
1284 #[allow(clippy::needless_continue)]
1287 fn parse_lit_str_cooked(mut s: &str) -> (Box<str>, Box<str>) {
1288 assert_eq!(byte(s, 0), b'"');
1289 s = &s[1..];
1290
1291 let mut content = String::new();
1292 'outer: loop {
1293 let ch = match byte(s, 0) {
1294 b'"' => break,
1295 b'\\' => {
1296 let b = byte(s, 1);
1297 s = &s[2..];
1298 match b {
1299 b'x' => {
1300 let (byte, rest) = backslash_x(s);
1301 s = rest;
1302 assert!(byte <= 0x7F, "invalid \\x byte in string literal");
1303 char::from_u32(u32::from(byte)).unwrap()
1304 }
1305 b'u' => {
1306 let (ch, rest) = backslash_u(s);
1307 s = rest;
1308 ch
1309 }
1310 b'n' => '\n',
1311 b'r' => '\r',
1312 b't' => '\t',
1313 b'\\' => '\\',
1314 b'0' => '\0',
1315 b'\'' => '\'',
1316 b'"' => '"',
1317 b'\r' | b'\n' => loop {
1318 let b = byte(s, 0);
1319 match b {
1320 b' ' | b'\t' | b'\n' | b'\r' => s = &s[1..],
1321 _ => continue 'outer,
1322 }
1323 },
1324 b => panic!(
1325 "unexpected byte '{}' after \\ character in string literal",
1326 ascii::escape_default(b),
1327 ),
1328 }
1329 }
1330 b'\r' => {
1331 assert_eq!(byte(s, 1), b'\n', "bare CR not allowed in string");
1332 s = &s[2..];
1333 '\n'
1334 }
1335 _ => {
1336 let ch = next_chr(s);
1337 s = &s[ch.len_utf8()..];
1338 ch
1339 }
1340 };
1341 content.push(ch);
1342 }
1343
1344 assert!(s.starts_with('"'));
1345 let content = content.into_boxed_str();
1346 let suffix = s[1..].to_owned().into_boxed_str();
1347 (content, suffix)
1348 }
1349
1350 fn parse_lit_str_raw(mut s: &str) -> (Box<str>, Box<str>) {
1351 assert_eq!(byte(s, 0), b'r');
1352 s = &s[1..];
1353
1354 let mut pounds = 0;
1355 while byte(s, pounds) == b'#' {
1356 pounds += 1;
1357 }
1358 assert_eq!(byte(s, pounds), b'"');
1359 let close = s.rfind('"').unwrap();
1360 for end in s[close + 1..close + 1 + pounds].bytes() {
1361 assert_eq!(end, b'#');
1362 }
1363
1364 let content = s[pounds + 1..close].to_owned().into_boxed_str();
1365 let suffix = s[close + 1 + pounds..].to_owned().into_boxed_str();
1366 (content, suffix)
1367 }
1368
1369 pub(crate) fn parse_lit_byte_str(s: &str) -> (Vec<u8>, Box<str>) {
1371 assert_eq!(byte(s, 0), b'b');
1372 match byte(s, 1) {
1373 b'"' => parse_lit_byte_str_cooked(s),
1374 b'r' => parse_lit_byte_str_raw(s),
1375 _ => unreachable!(),
1376 }
1377 }
1378
1379 #[allow(clippy::needless_continue)]
1382 fn parse_lit_byte_str_cooked(mut s: &str) -> (Vec<u8>, Box<str>) {
1383 assert_eq!(byte(s, 0), b'b');
1384 assert_eq!(byte(s, 1), b'"');
1385 s = &s[2..];
1386
1387 let mut v = s.as_bytes();
1389
1390 let mut out = Vec::new();
1391 'outer: loop {
1392 let byte = match byte(v, 0) {
1393 b'"' => break,
1394 b'\\' => {
1395 let b = byte(v, 1);
1396 v = &v[2..];
1397 match b {
1398 b'x' => {
1399 let (b, rest) = backslash_x(v);
1400 v = rest;
1401 b
1402 }
1403 b'n' => b'\n',
1404 b'r' => b'\r',
1405 b't' => b'\t',
1406 b'\\' => b'\\',
1407 b'0' => b'\0',
1408 b'\'' => b'\'',
1409 b'"' => b'"',
1410 b'\r' | b'\n' => loop {
1411 let byte = byte(v, 0);
1412 if matches!(byte, b' ' | b'\t' | b'\n' | b'\r') {
1413 v = &v[1..];
1414 } else {
1415 continue 'outer;
1416 }
1417 },
1418 b => panic!(
1419 "unexpected byte '{}' after \\ character in byte-string literal",
1420 ascii::escape_default(b),
1421 ),
1422 }
1423 }
1424 b'\r' => {
1425 assert_eq!(byte(v, 1), b'\n', "bare CR not allowed in string");
1426 v = &v[2..];
1427 b'\n'
1428 }
1429 b => {
1430 v = &v[1..];
1431 b
1432 }
1433 };
1434 out.push(byte);
1435 }
1436
1437 assert_eq!(byte(v, 0), b'"');
1438 let suffix = s[s.len() - v.len() + 1..].to_owned().into_boxed_str();
1439 (out, suffix)
1440 }
1441
1442 fn parse_lit_byte_str_raw(s: &str) -> (Vec<u8>, Box<str>) {
1443 assert_eq!(byte(s, 0), b'b');
1444 let (value, suffix) = parse_lit_str_raw(&s[1..]);
1445 (String::from(value).into_bytes(), suffix)
1446 }
1447
1448 pub(crate) fn parse_lit_c_str(s: &str) -> (CString, Box<str>) {
1450 assert_eq!(byte(s, 0), b'c');
1451 match byte(s, 1) {
1452 b'"' => parse_lit_c_str_cooked(s),
1453 b'r' => parse_lit_c_str_raw(s),
1454 _ => unreachable!(),
1455 }
1456 }
1457
1458 #[allow(clippy::needless_continue)]
1461 fn parse_lit_c_str_cooked(mut s: &str) -> (CString, Box<str>) {
1462 assert_eq!(byte(s, 0), b'c');
1463 assert_eq!(byte(s, 1), b'"');
1464 s = &s[2..];
1465
1466 let mut v = s.as_bytes();
1468
1469 let mut out = Vec::new();
1470 'outer: loop {
1471 let byte = match byte(v, 0) {
1472 b'"' => break,
1473 b'\\' => {
1474 let b = byte(v, 1);
1475 v = &v[2..];
1476 match b {
1477 b'x' => {
1478 let (b, rest) = backslash_x(v);
1479 assert!(b != 0, "\\x00 is not allowed in C-string literal");
1480 v = rest;
1481 b
1482 }
1483 b'u' => {
1484 let (ch, rest) = backslash_u(v);
1485 assert!(ch != '\0', "\\u{{0}} is not allowed in C-string literal");
1486 v = rest;
1487 out.extend_from_slice(ch.encode_utf8(&mut [0u8; 4]).as_bytes());
1488 continue 'outer;
1489 }
1490 b'n' => b'\n',
1491 b'r' => b'\r',
1492 b't' => b'\t',
1493 b'\\' => b'\\',
1494 b'\'' => b'\'',
1495 b'"' => b'"',
1496 b'\r' | b'\n' => loop {
1497 let byte = byte(v, 0);
1498 if matches!(byte, b' ' | b'\t' | b'\n' | b'\r') {
1499 v = &v[1..];
1500 } else {
1501 continue 'outer;
1502 }
1503 },
1504 b => panic!(
1505 "unexpected byte '{}' after \\ character in byte literal",
1506 ascii::escape_default(b),
1507 ),
1508 }
1509 }
1510 b'\r' => {
1511 assert_eq!(byte(v, 1), b'\n', "bare CR not allowed in string");
1512 v = &v[2..];
1513 b'\n'
1514 }
1515 b => {
1516 v = &v[1..];
1517 b
1518 }
1519 };
1520 out.push(byte);
1521 }
1522
1523 assert_eq!(byte(v, 0), b'"');
1524 let suffix = s[s.len() - v.len() + 1..].to_owned().into_boxed_str();
1525 (CString::new(out).unwrap(), suffix)
1526 }
1527
1528 fn parse_lit_c_str_raw(s: &str) -> (CString, Box<str>) {
1529 assert_eq!(byte(s, 0), b'c');
1530 let (value, suffix) = parse_lit_str_raw(&s[1..]);
1531 (CString::new(String::from(value)).unwrap(), suffix)
1532 }
1533
1534 pub(crate) fn parse_lit_byte(s: &str) -> (u8, Box<str>) {
1536 assert_eq!(byte(s, 0), b'b');
1537 assert_eq!(byte(s, 1), b'\'');
1538
1539 let mut v = &s.as_bytes()[2..];
1541
1542 let b = match byte(v, 0) {
1543 b'\\' => {
1544 let b = byte(v, 1);
1545 v = &v[2..];
1546 match b {
1547 b'x' => {
1548 let (b, rest) = backslash_x(v);
1549 v = rest;
1550 b
1551 }
1552 b'n' => b'\n',
1553 b'r' => b'\r',
1554 b't' => b'\t',
1555 b'\\' => b'\\',
1556 b'0' => b'\0',
1557 b'\'' => b'\'',
1558 b'"' => b'"',
1559 b => panic!(
1560 "unexpected byte '{}' after \\ character in byte literal",
1561 ascii::escape_default(b),
1562 ),
1563 }
1564 }
1565 b => {
1566 v = &v[1..];
1567 b
1568 }
1569 };
1570
1571 assert_eq!(byte(v, 0), b'\'');
1572 let suffix = s[s.len() - v.len() + 1..].to_owned().into_boxed_str();
1573 (b, suffix)
1574 }
1575
1576 pub(crate) fn parse_lit_char(mut s: &str) -> (char, Box<str>) {
1578 assert_eq!(byte(s, 0), b'\'');
1579 s = &s[1..];
1580
1581 let ch = match byte(s, 0) {
1582 b'\\' => {
1583 let b = byte(s, 1);
1584 s = &s[2..];
1585 match b {
1586 b'x' => {
1587 let (byte, rest) = backslash_x(s);
1588 s = rest;
1589 assert!(byte <= 0x7F, "invalid \\x byte in character literal");
1590 char::from_u32(u32::from(byte)).unwrap()
1591 }
1592 b'u' => {
1593 let (ch, rest) = backslash_u(s);
1594 s = rest;
1595 ch
1596 }
1597 b'n' => '\n',
1598 b'r' => '\r',
1599 b't' => '\t',
1600 b'\\' => '\\',
1601 b'0' => '\0',
1602 b'\'' => '\'',
1603 b'"' => '"',
1604 b => panic!(
1605 "unexpected byte '{}' after \\ character in character literal",
1606 ascii::escape_default(b),
1607 ),
1608 }
1609 }
1610 _ => {
1611 let ch = next_chr(s);
1612 s = &s[ch.len_utf8()..];
1613 ch
1614 }
1615 };
1616 assert_eq!(byte(s, 0), b'\'');
1617 let suffix = s[1..].to_owned().into_boxed_str();
1618 (ch, suffix)
1619 }
1620
1621 fn backslash_x<S>(s: &S) -> (u8, &S)
1622 where
1623 S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
1624 {
1625 let mut ch = 0;
1626 let b0 = byte(s, 0);
1627 let b1 = byte(s, 1);
1628 ch += 0x10
1629 * match b0 {
1630 b'0'..=b'9' => b0 - b'0',
1631 b'a'..=b'f' => 10 + (b0 - b'a'),
1632 b'A'..=b'F' => 10 + (b0 - b'A'),
1633 _ => panic!("unexpected non-hex character after \\x"),
1634 };
1635 ch += match b1 {
1636 b'0'..=b'9' => b1 - b'0',
1637 b'a'..=b'f' => 10 + (b1 - b'a'),
1638 b'A'..=b'F' => 10 + (b1 - b'A'),
1639 _ => panic!("unexpected non-hex character after \\x"),
1640 };
1641 (ch, &s[2..])
1642 }
1643
1644 fn backslash_u<S>(mut s: &S) -> (char, &S)
1645 where
1646 S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
1647 {
1648 if byte(s, 0) != b'{' {
1649 panic!("{}", "expected { after \\u");
1650 }
1651 s = &s[1..];
1652
1653 let mut ch = 0;
1654 let mut digits = 0;
1655 loop {
1656 let b = byte(s, 0);
1657 let digit = match b {
1658 b'0'..=b'9' => b - b'0',
1659 b'a'..=b'f' => 10 + b - b'a',
1660 b'A'..=b'F' => 10 + b - b'A',
1661 b'_' if digits > 0 => {
1662 s = &s[1..];
1663 continue;
1664 }
1665 b'}' if digits == 0 => panic!("invalid empty unicode escape"),
1666 b'}' => break,
1667 _ => panic!("unexpected non-hex character after \\u"),
1668 };
1669 if digits == 6 {
1670 panic!("overlong unicode escape (must have at most 6 hex digits)");
1671 }
1672 ch *= 0x10;
1673 ch += u32::from(digit);
1674 digits += 1;
1675 s = &s[1..];
1676 }
1677 assert!(byte(s, 0) == b'}');
1678 s = &s[1..];
1679
1680 if let Some(ch) = char::from_u32(ch) {
1681 (ch, s)
1682 } else {
1683 panic!("character code {:x} is not a valid unicode character", ch);
1684 }
1685 }
1686
1687 pub(crate) fn parse_lit_int(mut s: &str) -> Option<(Box<str>, Box<str>)> {
1689 let negative = byte(s, 0) == b'-';
1690 if negative {
1691 s = &s[1..];
1692 }
1693
1694 let base = match (byte(s, 0), byte(s, 1)) {
1695 (b'0', b'x') => {
1696 s = &s[2..];
1697 16
1698 }
1699 (b'0', b'o') => {
1700 s = &s[2..];
1701 8
1702 }
1703 (b'0', b'b') => {
1704 s = &s[2..];
1705 2
1706 }
1707 (b'0'..=b'9', _) => 10,
1708 _ => return None,
1709 };
1710
1711 let mut value = BigInt::new();
1712 let mut has_digit = false;
1713 'outer: loop {
1714 let b = byte(s, 0);
1715 let digit = match b {
1716 b'0'..=b'9' => b - b'0',
1717 b'a'..=b'f' if base > 10 => b - b'a' + 10,
1718 b'A'..=b'F' if base > 10 => b - b'A' + 10,
1719 b'_' => {
1720 s = &s[1..];
1721 continue;
1722 }
1723 b'.' if base == 10 => return None,
1726 b'e' | b'E' if base == 10 => {
1727 let mut has_exp = false;
1728 for (i, b) in s[1..].bytes().enumerate() {
1729 match b {
1730 b'_' => {}
1731 b'-' | b'+' => return None,
1732 b'0'..=b'9' => has_exp = true,
1733 _ => {
1734 let suffix = &s[1 + i..];
1735 if has_exp && crate::ident::xid_ok(suffix) {
1736 return None;
1737 } else {
1738 break 'outer;
1739 }
1740 }
1741 }
1742 }
1743 if has_exp {
1744 return None;
1745 } else {
1746 break;
1747 }
1748 }
1749 _ => break,
1750 };
1751
1752 if digit >= base {
1753 return None;
1754 }
1755
1756 has_digit = true;
1757 value *= base;
1758 value += digit;
1759 s = &s[1..];
1760 }
1761
1762 if !has_digit {
1763 return None;
1764 }
1765
1766 let suffix = s;
1767 if suffix.is_empty() || crate::ident::xid_ok(suffix) {
1768 let mut repr = value.to_string();
1769 if negative {
1770 repr.insert(0, '-');
1771 }
1772 Some((repr.into_boxed_str(), suffix.to_owned().into_boxed_str()))
1773 } else {
1774 None
1775 }
1776 }
1777
1778 pub(crate) fn parse_lit_float(input: &str) -> Option<(Box<str>, Box<str>)> {
1780 let mut bytes = input.to_owned().into_bytes();
1785
1786 let start = (*bytes.first()? == b'-') as usize;
1787 match bytes.get(start)? {
1788 b'0'..=b'9' => {}
1789 _ => return None,
1790 }
1791
1792 let mut read = start;
1793 let mut write = start;
1794 let mut has_dot = false;
1795 let mut has_e = false;
1796 let mut has_sign = false;
1797 let mut has_exponent = false;
1798 while read < bytes.len() {
1799 match bytes[read] {
1800 b'_' => {
1801 read += 1;
1803 continue;
1804 }
1805 b'0'..=b'9' => {
1806 if has_e {
1807 has_exponent = true;
1808 }
1809 bytes[write] = bytes[read];
1810 }
1811 b'.' => {
1812 if has_e || has_dot {
1813 return None;
1814 }
1815 has_dot = true;
1816 bytes[write] = b'.';
1817 }
1818 b'e' | b'E' => {
1819 match bytes[read + 1..]
1820 .iter()
1821 .find(|b| **b != b'_')
1822 .unwrap_or(&b'\0')
1823 {
1824 b'-' | b'+' | b'0'..=b'9' => {}
1825 _ => break,
1826 }
1827 if has_e {
1828 if has_exponent {
1829 break;
1830 } else {
1831 return None;
1832 }
1833 }
1834 has_e = true;
1835 bytes[write] = b'e';
1836 }
1837 b'-' | b'+' => {
1838 if has_sign || has_exponent || !has_e {
1839 return None;
1840 }
1841 has_sign = true;
1842 if bytes[read] == b'-' {
1843 bytes[write] = bytes[read];
1844 } else {
1845 read += 1;
1847 continue;
1848 }
1849 }
1850 _ => break,
1851 }
1852 read += 1;
1853 write += 1;
1854 }
1855
1856 if has_e && !has_exponent {
1857 return None;
1858 }
1859
1860 let mut digits = String::from_utf8(bytes).unwrap();
1861 let suffix = digits.split_off(read);
1862 digits.truncate(write);
1863 if suffix.is_empty() || crate::ident::xid_ok(&suffix) {
1864 Some((digits.into_boxed_str(), suffix.into_boxed_str()))
1865 } else {
1866 None
1867 }
1868 }
1869}