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 { new(value: &str, span: Span) -> Self122 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 value(&self) -> String133 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")))] parse<T: Parse>(&self) -> Result<T>172 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_with<F: Parser>(&self, parser: F) -> Result<F::Output>202 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 span(&self) -> Span244 pub fn span(&self) -> Span { 245 self.repr.token.span() 246 } 247 set_span(&mut self, span: Span)248 pub fn set_span(&mut self, span: Span) { 249 self.repr.token.set_span(span); 250 } 251 suffix(&self) -> &str252 pub fn suffix(&self) -> &str { 253 &self.repr.suffix 254 } 255 token(&self) -> Literal256 pub fn token(&self) -> Literal { 257 self.repr.token.clone() 258 } 259 } 260 261 impl LitByteStr { new(value: &[u8], span: Span) -> Self262 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 value(&self) -> Vec<u8>273 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 span(&self) -> Span279 pub fn span(&self) -> Span { 280 self.repr.token.span() 281 } 282 set_span(&mut self, span: Span)283 pub fn set_span(&mut self, span: Span) { 284 self.repr.token.set_span(span); 285 } 286 suffix(&self) -> &str287 pub fn suffix(&self) -> &str { 288 &self.repr.suffix 289 } 290 token(&self) -> Literal291 pub fn token(&self) -> Literal { 292 self.repr.token.clone() 293 } 294 } 295 296 impl LitByte { new(value: u8, span: Span) -> Self297 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 value(&self) -> u8308 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 span(&self) -> Span314 pub fn span(&self) -> Span { 315 self.repr.token.span() 316 } 317 set_span(&mut self, span: Span)318 pub fn set_span(&mut self, span: Span) { 319 self.repr.token.set_span(span); 320 } 321 suffix(&self) -> &str322 pub fn suffix(&self) -> &str { 323 &self.repr.suffix 324 } 325 token(&self) -> Literal326 pub fn token(&self) -> Literal { 327 self.repr.token.clone() 328 } 329 } 330 331 impl LitChar { new(value: char, span: Span) -> Self332 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 value(&self) -> char343 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 span(&self) -> Span349 pub fn span(&self) -> Span { 350 self.repr.token.span() 351 } 352 set_span(&mut self, span: Span)353 pub fn set_span(&mut self, span: Span) { 354 self.repr.token.set_span(span); 355 } 356 suffix(&self) -> &str357 pub fn suffix(&self) -> &str { 358 &self.repr.suffix 359 } 360 token(&self) -> Literal361 pub fn token(&self) -> Literal { 362 self.repr.token.clone() 363 } 364 } 365 366 impl LitInt { new(repr: &str, span: Span) -> Self367 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_digits(&self) -> &str384 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_parse<N>(&self) -> Result<N> where N: FromStr, N::Err: Display,410 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 suffix(&self) -> &str420 pub fn suffix(&self) -> &str { 421 &self.repr.suffix 422 } 423 span(&self) -> Span424 pub fn span(&self) -> Span { 425 self.repr.token.span() 426 } 427 set_span(&mut self, span: Span)428 pub fn set_span(&mut self, span: Span) { 429 self.repr.token.set_span(span); 430 } 431 token(&self) -> Literal432 pub fn token(&self) -> Literal { 433 self.repr.token.clone() 434 } 435 } 436 437 impl From<Literal> for LitInt { from(token: Literal) -> Self438 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 { fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result455 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 456 self.repr.token.fmt(formatter) 457 } 458 } 459 460 impl LitFloat { new(repr: &str, span: Span) -> Self461 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_digits(&self) -> &str478 pub fn base10_digits(&self) -> &str { 479 &self.repr.digits 480 } 481 base10_parse<N>(&self) -> Result<N> where N: FromStr, N::Err: Display,482 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 suffix(&self) -> &str492 pub fn suffix(&self) -> &str { 493 &self.repr.suffix 494 } 495 span(&self) -> Span496 pub fn span(&self) -> Span { 497 self.repr.token.span() 498 } 499 set_span(&mut self, span: Span)500 pub fn set_span(&mut self, span: Span) { 501 self.repr.token.set_span(span); 502 } 503 token(&self) -> Literal504 pub fn token(&self) -> Literal { 505 self.repr.token.clone() 506 } 507 } 508 509 impl From<Literal> for LitFloat { from(token: Literal) -> Self510 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 { fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result527 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 528 self.repr.token.fmt(formatter) 529 } 530 } 531 532 impl LitBool { new(value: bool, span: Span) -> Self533 pub fn new(value: bool, span: Span) -> Self { 534 LitBool { value, span } 535 } 536 value(&self) -> bool537 pub fn value(&self) -> bool { 538 self.value 539 } 540 span(&self) -> Span541 pub fn span(&self) -> Span { 542 self.span 543 } 544 set_span(&mut self, span: Span)545 pub fn set_span(&mut self, span: Span) { 546 self.span = span; 547 } 548 token(&self) -> Ident549 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 { fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result562 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 { fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result581 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 { fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result600 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 { fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result619 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 { fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result638 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 { fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result657 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 { fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result676 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 { clone(&self) -> Self697 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 { clone(&self) -> Self708 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 { clone(&self) -> Self720 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 { 734 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 { 744 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 { 752 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)] 782 pub fn LitBool(marker: lookahead::TokenMarker) -> LitBool { 783 match marker {} 784 } 785 } 786 787 ast_enum! { 788 /// The style of a string literal, either plain quoted or a raw string like 789 /// `r##"data"##`. 790 pub enum StrStyle #no_visit { 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 800 #[cfg(feature = "parsing")] 801 pub_if_not_doc! { 802 #[doc(hidden)] 803 #[allow(non_snake_case)] 804 pub fn Lit(marker: lookahead::TokenMarker) -> Lit { 805 match marker {} 806 } 807 } 808 809 #[cfg(feature = "parsing")] 810 pub(crate) mod parsing { 811 use super::*; 812 use crate::buffer::Cursor; 813 use crate::parse::{Parse, ParseStream, Result}; 814 use proc_macro2::Punct; 815 816 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 817 impl Parse for Lit { parse(input: ParseStream) -> Result<Self>818 fn parse(input: ParseStream) -> Result<Self> { 819 input.step(|cursor| { 820 if let Some((lit, rest)) = cursor.literal() { 821 return Ok((Lit::new(lit), rest)); 822 } 823 824 if let Some((ident, rest)) = cursor.ident() { 825 let value = ident == "true"; 826 if value || ident == "false" { 827 let lit_bool = LitBool { 828 value, 829 span: ident.span(), 830 }; 831 return Ok((Lit::Bool(lit_bool), rest)); 832 } 833 } 834 835 if let Some((punct, rest)) = cursor.punct() { 836 if punct.as_char() == '-' { 837 if let Some((lit, rest)) = parse_negative_lit(punct, rest) { 838 return Ok((lit, rest)); 839 } 840 } 841 } 842 843 Err(cursor.error("expected literal")) 844 }) 845 } 846 } 847 parse_negative_lit(neg: Punct, cursor: Cursor) -> Option<(Lit, Cursor)>848 fn parse_negative_lit(neg: Punct, cursor: Cursor) -> Option<(Lit, Cursor)> { 849 let (lit, rest) = cursor.literal()?; 850 851 let mut span = neg.span(); 852 span = span.join(lit.span()).unwrap_or(span); 853 854 let mut repr = lit.to_string(); 855 repr.insert(0, '-'); 856 857 if let Some((digits, suffix)) = value::parse_lit_int(&repr) { 858 let mut token: Literal = repr.parse().unwrap(); 859 token.set_span(span); 860 return Some(( 861 Lit::Int(LitInt { 862 repr: Box::new(LitIntRepr { 863 token, 864 digits, 865 suffix, 866 }), 867 }), 868 rest, 869 )); 870 } 871 872 let (digits, suffix) = value::parse_lit_float(&repr)?; 873 let mut token: Literal = repr.parse().unwrap(); 874 token.set_span(span); 875 Some(( 876 Lit::Float(LitFloat { 877 repr: Box::new(LitFloatRepr { 878 token, 879 digits, 880 suffix, 881 }), 882 }), 883 rest, 884 )) 885 } 886 887 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 888 impl Parse for LitStr { parse(input: ParseStream) -> Result<Self>889 fn parse(input: ParseStream) -> Result<Self> { 890 let head = input.fork(); 891 match input.parse() { 892 Ok(Lit::Str(lit)) => Ok(lit), 893 _ => Err(head.error("expected string literal")), 894 } 895 } 896 } 897 898 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 899 impl Parse for LitByteStr { parse(input: ParseStream) -> Result<Self>900 fn parse(input: ParseStream) -> Result<Self> { 901 let head = input.fork(); 902 match input.parse() { 903 Ok(Lit::ByteStr(lit)) => Ok(lit), 904 _ => Err(head.error("expected byte string literal")), 905 } 906 } 907 } 908 909 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 910 impl Parse for LitByte { parse(input: ParseStream) -> Result<Self>911 fn parse(input: ParseStream) -> Result<Self> { 912 let head = input.fork(); 913 match input.parse() { 914 Ok(Lit::Byte(lit)) => Ok(lit), 915 _ => Err(head.error("expected byte literal")), 916 } 917 } 918 } 919 920 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 921 impl Parse for LitChar { parse(input: ParseStream) -> Result<Self>922 fn parse(input: ParseStream) -> Result<Self> { 923 let head = input.fork(); 924 match input.parse() { 925 Ok(Lit::Char(lit)) => Ok(lit), 926 _ => Err(head.error("expected character literal")), 927 } 928 } 929 } 930 931 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 932 impl Parse for LitInt { parse(input: ParseStream) -> Result<Self>933 fn parse(input: ParseStream) -> Result<Self> { 934 let head = input.fork(); 935 match input.parse() { 936 Ok(Lit::Int(lit)) => Ok(lit), 937 _ => Err(head.error("expected integer literal")), 938 } 939 } 940 } 941 942 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 943 impl Parse for LitFloat { parse(input: ParseStream) -> Result<Self>944 fn parse(input: ParseStream) -> Result<Self> { 945 let head = input.fork(); 946 match input.parse() { 947 Ok(Lit::Float(lit)) => Ok(lit), 948 _ => Err(head.error("expected floating point literal")), 949 } 950 } 951 } 952 953 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 954 impl Parse for LitBool { parse(input: ParseStream) -> Result<Self>955 fn parse(input: ParseStream) -> Result<Self> { 956 let head = input.fork(); 957 match input.parse() { 958 Ok(Lit::Bool(lit)) => Ok(lit), 959 _ => Err(head.error("expected boolean literal")), 960 } 961 } 962 } 963 } 964 965 #[cfg(feature = "printing")] 966 mod printing { 967 use super::*; 968 use proc_macro2::TokenStream; 969 use quote::{ToTokens, TokenStreamExt}; 970 971 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 972 impl ToTokens for LitStr { to_tokens(&self, tokens: &mut TokenStream)973 fn to_tokens(&self, tokens: &mut TokenStream) { 974 self.repr.token.to_tokens(tokens); 975 } 976 } 977 978 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 979 impl ToTokens for LitByteStr { to_tokens(&self, tokens: &mut TokenStream)980 fn to_tokens(&self, tokens: &mut TokenStream) { 981 self.repr.token.to_tokens(tokens); 982 } 983 } 984 985 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 986 impl ToTokens for LitByte { to_tokens(&self, tokens: &mut TokenStream)987 fn to_tokens(&self, tokens: &mut TokenStream) { 988 self.repr.token.to_tokens(tokens); 989 } 990 } 991 992 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 993 impl ToTokens for LitChar { to_tokens(&self, tokens: &mut TokenStream)994 fn to_tokens(&self, tokens: &mut TokenStream) { 995 self.repr.token.to_tokens(tokens); 996 } 997 } 998 999 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 1000 impl ToTokens for LitInt { to_tokens(&self, tokens: &mut TokenStream)1001 fn to_tokens(&self, tokens: &mut TokenStream) { 1002 self.repr.token.to_tokens(tokens); 1003 } 1004 } 1005 1006 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 1007 impl ToTokens for LitFloat { to_tokens(&self, tokens: &mut TokenStream)1008 fn to_tokens(&self, tokens: &mut TokenStream) { 1009 self.repr.token.to_tokens(tokens); 1010 } 1011 } 1012 1013 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 1014 impl ToTokens for LitBool { to_tokens(&self, tokens: &mut TokenStream)1015 fn to_tokens(&self, tokens: &mut TokenStream) { 1016 tokens.append(self.token()); 1017 } 1018 } 1019 } 1020 1021 mod value { 1022 use super::*; 1023 use crate::bigint::BigInt; 1024 use std::char; 1025 use std::ops::{Index, RangeFrom}; 1026 1027 impl Lit { 1028 /// Interpret a Syn literal from a proc-macro2 literal. new(token: Literal) -> Self1029 pub fn new(token: Literal) -> Self { 1030 let repr = token.to_string(); 1031 1032 match byte(&repr, 0) { 1033 // "...", r"...", r#"..."# 1034 b'"' | b'r' => { 1035 let (_, suffix) = parse_lit_str(&repr); 1036 return Lit::Str(LitStr { 1037 repr: Box::new(LitRepr { token, suffix }), 1038 }); 1039 } 1040 b'b' => match byte(&repr, 1) { 1041 // b"...", br"...", br#"...#" 1042 b'"' | b'r' => { 1043 let (_, suffix) = parse_lit_byte_str(&repr); 1044 return Lit::ByteStr(LitByteStr { 1045 repr: Box::new(LitRepr { token, suffix }), 1046 }); 1047 } 1048 // b'...' 1049 b'\'' => { 1050 let (_, suffix) = parse_lit_byte(&repr); 1051 return Lit::Byte(LitByte { 1052 repr: Box::new(LitRepr { token, suffix }), 1053 }); 1054 } 1055 _ => {} 1056 }, 1057 // '...' 1058 b'\'' => { 1059 let (_, suffix) = parse_lit_char(&repr); 1060 return Lit::Char(LitChar { 1061 repr: Box::new(LitRepr { token, suffix }), 1062 }); 1063 } 1064 b'0'..=b'9' | b'-' => { 1065 // 0, 123, 0xFF, 0o77, 0b11 1066 if let Some((digits, suffix)) = parse_lit_int(&repr) { 1067 return Lit::Int(LitInt { 1068 repr: Box::new(LitIntRepr { 1069 token, 1070 digits, 1071 suffix, 1072 }), 1073 }); 1074 } 1075 // 1.0, 1e-1, 1e+1 1076 if let Some((digits, suffix)) = parse_lit_float(&repr) { 1077 return Lit::Float(LitFloat { 1078 repr: Box::new(LitFloatRepr { 1079 token, 1080 digits, 1081 suffix, 1082 }), 1083 }); 1084 } 1085 } 1086 // true, false 1087 b't' | b'f' => { 1088 if repr == "true" || repr == "false" { 1089 return Lit::Bool(LitBool { 1090 value: repr == "true", 1091 span: token.span(), 1092 }); 1093 } 1094 } 1095 // c"...", cr"...", cr#"..."# 1096 // TODO: add a Lit::CStr variant? 1097 b'c' => return Lit::Verbatim(token), 1098 b'(' if repr == "(/*ERROR*/)" => return Lit::Verbatim(token), 1099 _ => {} 1100 } 1101 1102 panic!("Unrecognized literal: `{}`", repr); 1103 } 1104 suffix(&self) -> &str1105 pub fn suffix(&self) -> &str { 1106 match self { 1107 Lit::Str(lit) => lit.suffix(), 1108 Lit::ByteStr(lit) => lit.suffix(), 1109 Lit::Byte(lit) => lit.suffix(), 1110 Lit::Char(lit) => lit.suffix(), 1111 Lit::Int(lit) => lit.suffix(), 1112 Lit::Float(lit) => lit.suffix(), 1113 Lit::Bool(_) | Lit::Verbatim(_) => "", 1114 } 1115 } 1116 span(&self) -> Span1117 pub fn span(&self) -> Span { 1118 match self { 1119 Lit::Str(lit) => lit.span(), 1120 Lit::ByteStr(lit) => lit.span(), 1121 Lit::Byte(lit) => lit.span(), 1122 Lit::Char(lit) => lit.span(), 1123 Lit::Int(lit) => lit.span(), 1124 Lit::Float(lit) => lit.span(), 1125 Lit::Bool(lit) => lit.span, 1126 Lit::Verbatim(lit) => lit.span(), 1127 } 1128 } 1129 set_span(&mut self, span: Span)1130 pub fn set_span(&mut self, span: Span) { 1131 match self { 1132 Lit::Str(lit) => lit.set_span(span), 1133 Lit::ByteStr(lit) => lit.set_span(span), 1134 Lit::Byte(lit) => lit.set_span(span), 1135 Lit::Char(lit) => lit.set_span(span), 1136 Lit::Int(lit) => lit.set_span(span), 1137 Lit::Float(lit) => lit.set_span(span), 1138 Lit::Bool(lit) => lit.span = span, 1139 Lit::Verbatim(lit) => lit.set_span(span), 1140 } 1141 } 1142 } 1143 1144 /// Get the byte at offset idx, or a default of `b'\0'` if we're looking 1145 /// past the end of the input buffer. byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u81146 pub(crate) fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 { 1147 let s = s.as_ref(); 1148 if idx < s.len() { 1149 s[idx] 1150 } else { 1151 0 1152 } 1153 } 1154 next_chr(s: &str) -> char1155 fn next_chr(s: &str) -> char { 1156 s.chars().next().unwrap_or('\0') 1157 } 1158 1159 // Returns (content, suffix). parse_lit_str(s: &str) -> (Box<str>, Box<str>)1160 pub(crate) fn parse_lit_str(s: &str) -> (Box<str>, Box<str>) { 1161 match byte(s, 0) { 1162 b'"' => parse_lit_str_cooked(s), 1163 b'r' => parse_lit_str_raw(s), 1164 _ => unreachable!(), 1165 } 1166 } 1167 1168 // Clippy false positive 1169 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329 1170 #[allow(clippy::needless_continue)] parse_lit_str_cooked(mut s: &str) -> (Box<str>, Box<str>)1171 fn parse_lit_str_cooked(mut s: &str) -> (Box<str>, Box<str>) { 1172 assert_eq!(byte(s, 0), b'"'); 1173 s = &s[1..]; 1174 1175 let mut content = String::new(); 1176 'outer: loop { 1177 let ch = match byte(s, 0) { 1178 b'"' => break, 1179 b'\\' => { 1180 let b = byte(s, 1); 1181 s = &s[2..]; 1182 match b { 1183 b'x' => { 1184 let (byte, rest) = backslash_x(s); 1185 s = rest; 1186 assert!(byte <= 0x7F, "Invalid \\x byte in string literal"); 1187 char::from_u32(u32::from(byte)).unwrap() 1188 } 1189 b'u' => { 1190 let (chr, rest) = backslash_u(s); 1191 s = rest; 1192 chr 1193 } 1194 b'n' => '\n', 1195 b'r' => '\r', 1196 b't' => '\t', 1197 b'\\' => '\\', 1198 b'0' => '\0', 1199 b'\'' => '\'', 1200 b'"' => '"', 1201 b'\r' | b'\n' => loop { 1202 let b = byte(s, 0); 1203 match b { 1204 b' ' | b'\t' | b'\n' | b'\r' => s = &s[1..], 1205 _ => continue 'outer, 1206 } 1207 }, 1208 b => panic!("unexpected byte {:?} after \\ character in byte literal", b), 1209 } 1210 } 1211 b'\r' => { 1212 assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string"); 1213 s = &s[2..]; 1214 '\n' 1215 } 1216 _ => { 1217 let ch = next_chr(s); 1218 s = &s[ch.len_utf8()..]; 1219 ch 1220 } 1221 }; 1222 content.push(ch); 1223 } 1224 1225 assert!(s.starts_with('"')); 1226 let content = content.into_boxed_str(); 1227 let suffix = s[1..].to_owned().into_boxed_str(); 1228 (content, suffix) 1229 } 1230 parse_lit_str_raw(mut s: &str) -> (Box<str>, Box<str>)1231 fn parse_lit_str_raw(mut s: &str) -> (Box<str>, Box<str>) { 1232 assert_eq!(byte(s, 0), b'r'); 1233 s = &s[1..]; 1234 1235 let mut pounds = 0; 1236 while byte(s, pounds) == b'#' { 1237 pounds += 1; 1238 } 1239 assert_eq!(byte(s, pounds), b'"'); 1240 let close = s.rfind('"').unwrap(); 1241 for end in s[close + 1..close + 1 + pounds].bytes() { 1242 assert_eq!(end, b'#'); 1243 } 1244 1245 let content = s[pounds + 1..close].to_owned().into_boxed_str(); 1246 let suffix = s[close + 1 + pounds..].to_owned().into_boxed_str(); 1247 (content, suffix) 1248 } 1249 1250 // Returns (content, suffix). parse_lit_byte_str(s: &str) -> (Vec<u8>, Box<str>)1251 pub(crate) fn parse_lit_byte_str(s: &str) -> (Vec<u8>, Box<str>) { 1252 assert_eq!(byte(s, 0), b'b'); 1253 match byte(s, 1) { 1254 b'"' => parse_lit_byte_str_cooked(s), 1255 b'r' => parse_lit_byte_str_raw(s), 1256 _ => unreachable!(), 1257 } 1258 } 1259 1260 // Clippy false positive 1261 // https://github.com/rust-lang-nursery/rust-clippy/issues/2329 1262 #[allow(clippy::needless_continue)] parse_lit_byte_str_cooked(mut s: &str) -> (Vec<u8>, Box<str>)1263 fn parse_lit_byte_str_cooked(mut s: &str) -> (Vec<u8>, Box<str>) { 1264 assert_eq!(byte(s, 0), b'b'); 1265 assert_eq!(byte(s, 1), b'"'); 1266 s = &s[2..]; 1267 1268 // We're going to want to have slices which don't respect codepoint boundaries. 1269 let mut v = s.as_bytes(); 1270 1271 let mut out = Vec::new(); 1272 'outer: loop { 1273 let byte = match byte(v, 0) { 1274 b'"' => break, 1275 b'\\' => { 1276 let b = byte(v, 1); 1277 v = &v[2..]; 1278 match b { 1279 b'x' => { 1280 let (b, rest) = backslash_x(v); 1281 v = rest; 1282 b 1283 } 1284 b'n' => b'\n', 1285 b'r' => b'\r', 1286 b't' => b'\t', 1287 b'\\' => b'\\', 1288 b'0' => b'\0', 1289 b'\'' => b'\'', 1290 b'"' => b'"', 1291 b'\r' | b'\n' => loop { 1292 let byte = byte(v, 0); 1293 if matches!(byte, b' ' | b'\t' | b'\n' | b'\r') { 1294 v = &v[1..]; 1295 } else { 1296 continue 'outer; 1297 } 1298 }, 1299 b => panic!("unexpected byte {:?} after \\ character in byte literal", b), 1300 } 1301 } 1302 b'\r' => { 1303 assert_eq!(byte(v, 1), b'\n', "Bare CR not allowed in string"); 1304 v = &v[2..]; 1305 b'\n' 1306 } 1307 b => { 1308 v = &v[1..]; 1309 b 1310 } 1311 }; 1312 out.push(byte); 1313 } 1314 1315 assert_eq!(byte(v, 0), b'"'); 1316 let suffix = s[s.len() - v.len() + 1..].to_owned().into_boxed_str(); 1317 (out, suffix) 1318 } 1319 parse_lit_byte_str_raw(s: &str) -> (Vec<u8>, Box<str>)1320 fn parse_lit_byte_str_raw(s: &str) -> (Vec<u8>, Box<str>) { 1321 assert_eq!(byte(s, 0), b'b'); 1322 let (value, suffix) = parse_lit_str_raw(&s[1..]); 1323 (String::from(value).into_bytes(), suffix) 1324 } 1325 1326 // Returns (value, suffix). parse_lit_byte(s: &str) -> (u8, Box<str>)1327 pub(crate) fn parse_lit_byte(s: &str) -> (u8, Box<str>) { 1328 assert_eq!(byte(s, 0), b'b'); 1329 assert_eq!(byte(s, 1), b'\''); 1330 1331 // We're going to want to have slices which don't respect codepoint boundaries. 1332 let mut v = s[2..].as_bytes(); 1333 1334 let b = match byte(v, 0) { 1335 b'\\' => { 1336 let b = byte(v, 1); 1337 v = &v[2..]; 1338 match b { 1339 b'x' => { 1340 let (b, rest) = backslash_x(v); 1341 v = rest; 1342 b 1343 } 1344 b'n' => b'\n', 1345 b'r' => b'\r', 1346 b't' => b'\t', 1347 b'\\' => b'\\', 1348 b'0' => b'\0', 1349 b'\'' => b'\'', 1350 b'"' => b'"', 1351 b => panic!("unexpected byte {:?} after \\ character in byte literal", b), 1352 } 1353 } 1354 b => { 1355 v = &v[1..]; 1356 b 1357 } 1358 }; 1359 1360 assert_eq!(byte(v, 0), b'\''); 1361 let suffix = s[s.len() - v.len() + 1..].to_owned().into_boxed_str(); 1362 (b, suffix) 1363 } 1364 1365 // Returns (value, suffix). parse_lit_char(mut s: &str) -> (char, Box<str>)1366 pub(crate) fn parse_lit_char(mut s: &str) -> (char, Box<str>) { 1367 assert_eq!(byte(s, 0), b'\''); 1368 s = &s[1..]; 1369 1370 let ch = match byte(s, 0) { 1371 b'\\' => { 1372 let b = byte(s, 1); 1373 s = &s[2..]; 1374 match b { 1375 b'x' => { 1376 let (byte, rest) = backslash_x(s); 1377 s = rest; 1378 assert!(byte <= 0x80, "Invalid \\x byte in string literal"); 1379 char::from_u32(u32::from(byte)).unwrap() 1380 } 1381 b'u' => { 1382 let (chr, rest) = backslash_u(s); 1383 s = rest; 1384 chr 1385 } 1386 b'n' => '\n', 1387 b'r' => '\r', 1388 b't' => '\t', 1389 b'\\' => '\\', 1390 b'0' => '\0', 1391 b'\'' => '\'', 1392 b'"' => '"', 1393 b => panic!("unexpected byte {:?} after \\ character in byte literal", b), 1394 } 1395 } 1396 _ => { 1397 let ch = next_chr(s); 1398 s = &s[ch.len_utf8()..]; 1399 ch 1400 } 1401 }; 1402 assert_eq!(byte(s, 0), b'\''); 1403 let suffix = s[1..].to_owned().into_boxed_str(); 1404 (ch, suffix) 1405 } 1406 backslash_x<S>(s: &S) -> (u8, &S) where S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,1407 fn backslash_x<S>(s: &S) -> (u8, &S) 1408 where 1409 S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized, 1410 { 1411 let mut ch = 0; 1412 let b0 = byte(s, 0); 1413 let b1 = byte(s, 1); 1414 ch += 0x10 1415 * match b0 { 1416 b'0'..=b'9' => b0 - b'0', 1417 b'a'..=b'f' => 10 + (b0 - b'a'), 1418 b'A'..=b'F' => 10 + (b0 - b'A'), 1419 _ => panic!("unexpected non-hex character after \\x"), 1420 }; 1421 ch += match b1 { 1422 b'0'..=b'9' => b1 - b'0', 1423 b'a'..=b'f' => 10 + (b1 - b'a'), 1424 b'A'..=b'F' => 10 + (b1 - b'A'), 1425 _ => panic!("unexpected non-hex character after \\x"), 1426 }; 1427 (ch, &s[2..]) 1428 } 1429 backslash_u(mut s: &str) -> (char, &str)1430 fn backslash_u(mut s: &str) -> (char, &str) { 1431 if byte(s, 0) != b'{' { 1432 panic!("{}", "expected { after \\u"); 1433 } 1434 s = &s[1..]; 1435 1436 let mut ch = 0; 1437 let mut digits = 0; 1438 loop { 1439 let b = byte(s, 0); 1440 let digit = match b { 1441 b'0'..=b'9' => b - b'0', 1442 b'a'..=b'f' => 10 + b - b'a', 1443 b'A'..=b'F' => 10 + b - b'A', 1444 b'_' if digits > 0 => { 1445 s = &s[1..]; 1446 continue; 1447 } 1448 b'}' if digits == 0 => panic!("invalid empty unicode escape"), 1449 b'}' => break, 1450 _ => panic!("unexpected non-hex character after \\u"), 1451 }; 1452 if digits == 6 { 1453 panic!("overlong unicode escape (must have at most 6 hex digits)"); 1454 } 1455 ch *= 0x10; 1456 ch += u32::from(digit); 1457 digits += 1; 1458 s = &s[1..]; 1459 } 1460 assert!(byte(s, 0) == b'}'); 1461 s = &s[1..]; 1462 1463 if let Some(ch) = char::from_u32(ch) { 1464 (ch, s) 1465 } else { 1466 panic!("character code {:x} is not a valid unicode character", ch); 1467 } 1468 } 1469 1470 // Returns base 10 digits and suffix. parse_lit_int(mut s: &str) -> Option<(Box<str>, Box<str>)>1471 pub(crate) fn parse_lit_int(mut s: &str) -> Option<(Box<str>, Box<str>)> { 1472 let negative = byte(s, 0) == b'-'; 1473 if negative { 1474 s = &s[1..]; 1475 } 1476 1477 let base = match (byte(s, 0), byte(s, 1)) { 1478 (b'0', b'x') => { 1479 s = &s[2..]; 1480 16 1481 } 1482 (b'0', b'o') => { 1483 s = &s[2..]; 1484 8 1485 } 1486 (b'0', b'b') => { 1487 s = &s[2..]; 1488 2 1489 } 1490 (b'0'..=b'9', _) => 10, 1491 _ => return None, 1492 }; 1493 1494 let mut value = BigInt::new(); 1495 let mut has_digit = false; 1496 'outer: loop { 1497 let b = byte(s, 0); 1498 let digit = match b { 1499 b'0'..=b'9' => b - b'0', 1500 b'a'..=b'f' if base > 10 => b - b'a' + 10, 1501 b'A'..=b'F' if base > 10 => b - b'A' + 10, 1502 b'_' => { 1503 s = &s[1..]; 1504 continue; 1505 } 1506 // If looking at a floating point literal, we don't want to 1507 // consider it an integer. 1508 b'.' if base == 10 => return None, 1509 b'e' | b'E' if base == 10 => { 1510 let mut has_exp = false; 1511 for (i, b) in s[1..].bytes().enumerate() { 1512 match b { 1513 b'_' => {} 1514 b'-' | b'+' => return None, 1515 b'0'..=b'9' => has_exp = true, 1516 _ => { 1517 let suffix = &s[1 + i..]; 1518 if has_exp && crate::ident::xid_ok(suffix) { 1519 return None; 1520 } else { 1521 break 'outer; 1522 } 1523 } 1524 } 1525 } 1526 if has_exp { 1527 return None; 1528 } else { 1529 break; 1530 } 1531 } 1532 _ => break, 1533 }; 1534 1535 if digit >= base { 1536 return None; 1537 } 1538 1539 has_digit = true; 1540 value *= base; 1541 value += digit; 1542 s = &s[1..]; 1543 } 1544 1545 if !has_digit { 1546 return None; 1547 } 1548 1549 let suffix = s; 1550 if suffix.is_empty() || crate::ident::xid_ok(suffix) { 1551 let mut repr = value.to_string(); 1552 if negative { 1553 repr.insert(0, '-'); 1554 } 1555 Some((repr.into_boxed_str(), suffix.to_owned().into_boxed_str())) 1556 } else { 1557 None 1558 } 1559 } 1560 1561 // Returns base 10 digits and suffix. parse_lit_float(input: &str) -> Option<(Box<str>, Box<str>)>1562 pub(crate) fn parse_lit_float(input: &str) -> Option<(Box<str>, Box<str>)> { 1563 // Rust's floating point literals are very similar to the ones parsed by 1564 // the standard library, except that rust's literals can contain 1565 // ignorable underscores. Let's remove those underscores. 1566 1567 let mut bytes = input.to_owned().into_bytes(); 1568 1569 let start = (*bytes.first()? == b'-') as usize; 1570 match bytes.get(start)? { 1571 b'0'..=b'9' => {} 1572 _ => return None, 1573 } 1574 1575 let mut read = start; 1576 let mut write = start; 1577 let mut has_dot = false; 1578 let mut has_e = false; 1579 let mut has_sign = false; 1580 let mut has_exponent = false; 1581 while read < bytes.len() { 1582 match bytes[read] { 1583 b'_' => { 1584 // Don't increase write 1585 read += 1; 1586 continue; 1587 } 1588 b'0'..=b'9' => { 1589 if has_e { 1590 has_exponent = true; 1591 } 1592 bytes[write] = bytes[read]; 1593 } 1594 b'.' => { 1595 if has_e || has_dot { 1596 return None; 1597 } 1598 has_dot = true; 1599 bytes[write] = b'.'; 1600 } 1601 b'e' | b'E' => { 1602 match bytes[read + 1..] 1603 .iter() 1604 .find(|b| **b != b'_') 1605 .unwrap_or(&b'\0') 1606 { 1607 b'-' | b'+' | b'0'..=b'9' => {} 1608 _ => break, 1609 } 1610 if has_e { 1611 if has_exponent { 1612 break; 1613 } else { 1614 return None; 1615 } 1616 } 1617 has_e = true; 1618 bytes[write] = b'e'; 1619 } 1620 b'-' | b'+' => { 1621 if has_sign || has_exponent || !has_e { 1622 return None; 1623 } 1624 has_sign = true; 1625 if bytes[read] == b'-' { 1626 bytes[write] = bytes[read]; 1627 } else { 1628 // Omit '+' 1629 read += 1; 1630 continue; 1631 } 1632 } 1633 _ => break, 1634 } 1635 read += 1; 1636 write += 1; 1637 } 1638 1639 if has_e && !has_exponent { 1640 return None; 1641 } 1642 1643 let mut digits = String::from_utf8(bytes).unwrap(); 1644 let suffix = digits.split_off(read); 1645 digits.truncate(write); 1646 if suffix.is_empty() || crate::ident::xid_ok(&suffix) { 1647 Some((digits.into_boxed_str(), suffix.into_boxed_str())) 1648 } else { 1649 None 1650 } 1651 } 1652 } 1653