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