1#[cfg(span_locations)] 2use crate::location::LineColumn; 3use crate::parse::{self, Cursor}; 4use crate::rcvec::{RcVec, RcVecBuilder, RcVecIntoIter, RcVecMut}; 5use crate::{Delimiter, Spacing, TokenTree}; 6#[cfg(all(span_locations, not(fuzzing)))] 7use alloc::collections::BTreeMap; 8#[cfg(all(span_locations, not(fuzzing)))] 9use core::cell::RefCell; 10#[cfg(span_locations)] 11use core::cmp; 12use core::fmt::{self, Debug, Display, Write}; 13use core::mem::ManuallyDrop; 14use core::ops::RangeBounds; 15use core::ptr; 16use core::str::FromStr; 17use std::path::PathBuf; 18 19/// Force use of proc-macro2's fallback implementation of the API for now, even 20/// if the compiler's implementation is available. 21pub fn force() { 22 #[cfg(wrap_proc_macro)] 23 crate::detection::force_fallback(); 24} 25 26/// Resume using the compiler's implementation of the proc macro API if it is 27/// available. 28pub fn unforce() { 29 #[cfg(wrap_proc_macro)] 30 crate::detection::unforce_fallback(); 31} 32 33#[derive(Clone)] 34pub(crate) struct TokenStream { 35 inner: RcVec<TokenTree>, 36} 37 38#[derive(Debug)] 39pub(crate) struct LexError { 40 pub(crate) span: Span, 41} 42 43impl LexError { 44 pub(crate) fn span(&self) -> Span { 45 self.span 46 } 47 48 pub(crate) fn call_site() -> Self { 49 LexError { 50 span: Span::call_site(), 51 } 52 } 53} 54 55impl TokenStream { 56 pub fn new() -> Self { 57 TokenStream { 58 inner: RcVecBuilder::new().build(), 59 } 60 } 61 62 pub fn is_empty(&self) -> bool { 63 self.inner.len() == 0 64 } 65 66 fn take_inner(self) -> RcVecBuilder<TokenTree> { 67 let nodrop = ManuallyDrop::new(self); 68 unsafe { ptr::read(&nodrop.inner) }.make_owned() 69 } 70} 71 72fn push_token_from_proc_macro(mut vec: RcVecMut<TokenTree>, token: TokenTree) { 73 // https://github.com/dtolnay/proc-macro2/issues/235 74 match token { 75 TokenTree::Literal(crate::Literal { 76 #[cfg(wrap_proc_macro)] 77 inner: crate::imp::Literal::Fallback(literal), 78 #[cfg(not(wrap_proc_macro))] 79 inner: literal, 80 .. 81 }) if literal.repr.starts_with('-') => { 82 push_negative_literal(vec, literal); 83 } 84 _ => vec.push(token), 85 } 86 87 #[cold] 88 fn push_negative_literal(mut vec: RcVecMut<TokenTree>, mut literal: Literal) { 89 literal.repr.remove(0); 90 let mut punct = crate::Punct::new('-', Spacing::Alone); 91 punct.set_span(crate::Span::_new_fallback(literal.span)); 92 vec.push(TokenTree::Punct(punct)); 93 vec.push(TokenTree::Literal(crate::Literal::_new_fallback(literal))); 94 } 95} 96 97// Nonrecursive to prevent stack overflow. 98impl Drop for TokenStream { 99 fn drop(&mut self) { 100 let mut inner = match self.inner.get_mut() { 101 Some(inner) => inner, 102 None => return, 103 }; 104 while let Some(token) = inner.pop() { 105 let group = match token { 106 TokenTree::Group(group) => group.inner, 107 _ => continue, 108 }; 109 #[cfg(wrap_proc_macro)] 110 let group = match group { 111 crate::imp::Group::Fallback(group) => group, 112 crate::imp::Group::Compiler(_) => continue, 113 }; 114 inner.extend(group.stream.take_inner()); 115 } 116 } 117} 118 119pub(crate) struct TokenStreamBuilder { 120 inner: RcVecBuilder<TokenTree>, 121} 122 123impl TokenStreamBuilder { 124 pub fn new() -> Self { 125 TokenStreamBuilder { 126 inner: RcVecBuilder::new(), 127 } 128 } 129 130 pub fn with_capacity(cap: usize) -> Self { 131 TokenStreamBuilder { 132 inner: RcVecBuilder::with_capacity(cap), 133 } 134 } 135 136 pub fn push_token_from_parser(&mut self, tt: TokenTree) { 137 self.inner.push(tt); 138 } 139 140 pub fn build(self) -> TokenStream { 141 TokenStream { 142 inner: self.inner.build(), 143 } 144 } 145} 146 147#[cfg(span_locations)] 148fn get_cursor(src: &str) -> Cursor { 149 #[cfg(fuzzing)] 150 return Cursor { rest: src, off: 1 }; 151 152 // Create a dummy file & add it to the source map 153 #[cfg(not(fuzzing))] 154 SOURCE_MAP.with(|cm| { 155 let mut cm = cm.borrow_mut(); 156 let span = cm.add_file(src); 157 Cursor { 158 rest: src, 159 off: span.lo, 160 } 161 }) 162} 163 164#[cfg(not(span_locations))] 165fn get_cursor(src: &str) -> Cursor { 166 Cursor { rest: src } 167} 168 169impl FromStr for TokenStream { 170 type Err = LexError; 171 172 fn from_str(src: &str) -> Result<TokenStream, LexError> { 173 // Create a dummy file & add it to the source map 174 let mut cursor = get_cursor(src); 175 176 // Strip a byte order mark if present 177 const BYTE_ORDER_MARK: &str = "\u{feff}"; 178 if cursor.starts_with(BYTE_ORDER_MARK) { 179 cursor = cursor.advance(BYTE_ORDER_MARK.len()); 180 } 181 182 parse::token_stream(cursor) 183 } 184} 185 186impl Display for LexError { 187 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 188 f.write_str("cannot parse string into token stream") 189 } 190} 191 192impl Display for TokenStream { 193 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 194 let mut joint = false; 195 for (i, tt) in self.inner.iter().enumerate() { 196 if i != 0 && !joint { 197 write!(f, " ")?; 198 } 199 joint = false; 200 match tt { 201 TokenTree::Group(tt) => Display::fmt(tt, f), 202 TokenTree::Ident(tt) => Display::fmt(tt, f), 203 TokenTree::Punct(tt) => { 204 joint = tt.spacing() == Spacing::Joint; 205 Display::fmt(tt, f) 206 } 207 TokenTree::Literal(tt) => Display::fmt(tt, f), 208 }?; 209 } 210 211 Ok(()) 212 } 213} 214 215impl Debug for TokenStream { 216 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 217 f.write_str("TokenStream ")?; 218 f.debug_list().entries(self.clone()).finish() 219 } 220} 221 222#[cfg(feature = "proc-macro")] 223impl From<proc_macro::TokenStream> for TokenStream { 224 fn from(inner: proc_macro::TokenStream) -> Self { 225 inner 226 .to_string() 227 .parse() 228 .expect("compiler token stream parse failed") 229 } 230} 231 232#[cfg(feature = "proc-macro")] 233impl From<TokenStream> for proc_macro::TokenStream { 234 fn from(inner: TokenStream) -> Self { 235 inner 236 .to_string() 237 .parse() 238 .expect("failed to parse to compiler tokens") 239 } 240} 241 242impl From<TokenTree> for TokenStream { 243 fn from(tree: TokenTree) -> Self { 244 let mut stream = RcVecBuilder::new(); 245 push_token_from_proc_macro(stream.as_mut(), tree); 246 TokenStream { 247 inner: stream.build(), 248 } 249 } 250} 251 252impl FromIterator<TokenTree> for TokenStream { 253 fn from_iter<I: IntoIterator<Item = TokenTree>>(tokens: I) -> Self { 254 let mut stream = TokenStream::new(); 255 stream.extend(tokens); 256 stream 257 } 258} 259 260impl FromIterator<TokenStream> for TokenStream { 261 fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self { 262 let mut v = RcVecBuilder::new(); 263 264 for stream in streams { 265 v.extend(stream.take_inner()); 266 } 267 268 TokenStream { inner: v.build() } 269 } 270} 271 272impl Extend<TokenTree> for TokenStream { 273 fn extend<I: IntoIterator<Item = TokenTree>>(&mut self, tokens: I) { 274 let mut vec = self.inner.make_mut(); 275 tokens 276 .into_iter() 277 .for_each(|token| push_token_from_proc_macro(vec.as_mut(), token)); 278 } 279} 280 281impl Extend<TokenStream> for TokenStream { 282 fn extend<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I) { 283 self.inner.make_mut().extend(streams.into_iter().flatten()); 284 } 285} 286 287pub(crate) type TokenTreeIter = RcVecIntoIter<TokenTree>; 288 289impl IntoIterator for TokenStream { 290 type Item = TokenTree; 291 type IntoIter = TokenTreeIter; 292 293 fn into_iter(self) -> TokenTreeIter { 294 self.take_inner().into_iter() 295 } 296} 297 298#[derive(Clone, PartialEq, Eq)] 299pub(crate) struct SourceFile { 300 path: PathBuf, 301} 302 303impl SourceFile { 304 /// Get the path to this source file as a string. 305 pub fn path(&self) -> PathBuf { 306 self.path.clone() 307 } 308 309 pub fn is_real(&self) -> bool { 310 false 311 } 312} 313 314impl Debug for SourceFile { 315 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 316 f.debug_struct("SourceFile") 317 .field("path", &self.path()) 318 .field("is_real", &self.is_real()) 319 .finish() 320 } 321} 322 323#[cfg(all(span_locations, not(fuzzing)))] 324thread_local! { 325 static SOURCE_MAP: RefCell<SourceMap> = RefCell::new(SourceMap { 326 // Start with a single dummy file which all call_site() and def_site() 327 // spans reference. 328 files: vec![FileInfo { 329 source_text: String::new(), 330 span: Span { lo: 0, hi: 0 }, 331 lines: vec![0], 332 char_index_to_byte_offset: BTreeMap::new(), 333 }], 334 }); 335} 336 337#[cfg(all(span_locations, not(fuzzing)))] 338struct FileInfo { 339 source_text: String, 340 span: Span, 341 lines: Vec<usize>, 342 char_index_to_byte_offset: BTreeMap<usize, usize>, 343} 344 345#[cfg(all(span_locations, not(fuzzing)))] 346impl FileInfo { 347 fn offset_line_column(&self, offset: usize) -> LineColumn { 348 assert!(self.span_within(Span { 349 lo: offset as u32, 350 hi: offset as u32, 351 })); 352 let offset = offset - self.span.lo as usize; 353 match self.lines.binary_search(&offset) { 354 Ok(found) => LineColumn { 355 line: found + 1, 356 column: 0, 357 }, 358 Err(idx) => LineColumn { 359 line: idx, 360 column: offset - self.lines[idx - 1], 361 }, 362 } 363 } 364 365 fn span_within(&self, span: Span) -> bool { 366 span.lo >= self.span.lo && span.hi <= self.span.hi 367 } 368 369 fn source_text(&mut self, span: Span) -> String { 370 let lo_char = (span.lo - self.span.lo) as usize; 371 372 // Look up offset of the largest already-computed char index that is 373 // less than or equal to the current requested one. We resume counting 374 // chars from that point. 375 let (&last_char_index, &last_byte_offset) = self 376 .char_index_to_byte_offset 377 .range(..=lo_char) 378 .next_back() 379 .unwrap_or((&0, &0)); 380 381 let lo_byte = if last_char_index == lo_char { 382 last_byte_offset 383 } else { 384 let total_byte_offset = match self.source_text[last_byte_offset..] 385 .char_indices() 386 .nth(lo_char - last_char_index) 387 { 388 Some((additional_offset, _ch)) => last_byte_offset + additional_offset, 389 None => self.source_text.len(), 390 }; 391 self.char_index_to_byte_offset 392 .insert(lo_char, total_byte_offset); 393 total_byte_offset 394 }; 395 396 let trunc_lo = &self.source_text[lo_byte..]; 397 let char_len = (span.hi - span.lo) as usize; 398 let source_text = match trunc_lo.char_indices().nth(char_len) { 399 Some((offset, _ch)) => &trunc_lo[..offset], 400 None => trunc_lo, 401 }; 402 source_text.to_owned() 403 } 404} 405 406/// Computes the offsets of each line in the given source string 407/// and the total number of characters 408#[cfg(all(span_locations, not(fuzzing)))] 409fn lines_offsets(s: &str) -> (usize, Vec<usize>) { 410 let mut lines = vec![0]; 411 let mut total = 0; 412 413 for ch in s.chars() { 414 total += 1; 415 if ch == '\n' { 416 lines.push(total); 417 } 418 } 419 420 (total, lines) 421} 422 423#[cfg(all(span_locations, not(fuzzing)))] 424struct SourceMap { 425 files: Vec<FileInfo>, 426} 427 428#[cfg(all(span_locations, not(fuzzing)))] 429impl SourceMap { 430 fn next_start_pos(&self) -> u32 { 431 // Add 1 so there's always space between files. 432 // 433 // We'll always have at least 1 file, as we initialize our files list 434 // with a dummy file. 435 self.files.last().unwrap().span.hi + 1 436 } 437 438 fn add_file(&mut self, src: &str) -> Span { 439 let (len, lines) = lines_offsets(src); 440 let lo = self.next_start_pos(); 441 let span = Span { 442 lo, 443 hi: lo + (len as u32), 444 }; 445 446 self.files.push(FileInfo { 447 source_text: src.to_owned(), 448 span, 449 lines, 450 // Populated lazily by source_text(). 451 char_index_to_byte_offset: BTreeMap::new(), 452 }); 453 454 span 455 } 456 457 #[cfg(procmacro2_semver_exempt)] 458 fn filepath(&self, span: Span) -> PathBuf { 459 for (i, file) in self.files.iter().enumerate() { 460 if file.span_within(span) { 461 return PathBuf::from(if i == 0 { 462 "<unspecified>".to_owned() 463 } else { 464 format!("<parsed string {}>", i) 465 }); 466 } 467 } 468 unreachable!("Invalid span with no related FileInfo!"); 469 } 470 471 fn fileinfo(&self, span: Span) -> &FileInfo { 472 for file in &self.files { 473 if file.span_within(span) { 474 return file; 475 } 476 } 477 unreachable!("Invalid span with no related FileInfo!"); 478 } 479 480 fn fileinfo_mut(&mut self, span: Span) -> &mut FileInfo { 481 for file in &mut self.files { 482 if file.span_within(span) { 483 return file; 484 } 485 } 486 unreachable!("Invalid span with no related FileInfo!"); 487 } 488} 489 490#[derive(Clone, Copy, PartialEq, Eq)] 491pub(crate) struct Span { 492 #[cfg(span_locations)] 493 pub(crate) lo: u32, 494 #[cfg(span_locations)] 495 pub(crate) hi: u32, 496} 497 498impl Span { 499 #[cfg(not(span_locations))] 500 pub fn call_site() -> Self { 501 Span {} 502 } 503 504 #[cfg(span_locations)] 505 pub fn call_site() -> Self { 506 Span { lo: 0, hi: 0 } 507 } 508 509 pub fn mixed_site() -> Self { 510 Span::call_site() 511 } 512 513 #[cfg(procmacro2_semver_exempt)] 514 pub fn def_site() -> Self { 515 Span::call_site() 516 } 517 518 pub fn resolved_at(&self, _other: Span) -> Span { 519 // Stable spans consist only of line/column information, so 520 // `resolved_at` and `located_at` only select which span the 521 // caller wants line/column information from. 522 *self 523 } 524 525 pub fn located_at(&self, other: Span) -> Span { 526 other 527 } 528 529 #[cfg(procmacro2_semver_exempt)] 530 pub fn source_file(&self) -> SourceFile { 531 #[cfg(fuzzing)] 532 return SourceFile { 533 path: PathBuf::from("<unspecified>"), 534 }; 535 536 #[cfg(not(fuzzing))] 537 SOURCE_MAP.with(|cm| { 538 let cm = cm.borrow(); 539 let path = cm.filepath(*self); 540 SourceFile { path } 541 }) 542 } 543 544 #[cfg(span_locations)] 545 pub fn start(&self) -> LineColumn { 546 #[cfg(fuzzing)] 547 return LineColumn { line: 0, column: 0 }; 548 549 #[cfg(not(fuzzing))] 550 SOURCE_MAP.with(|cm| { 551 let cm = cm.borrow(); 552 let fi = cm.fileinfo(*self); 553 fi.offset_line_column(self.lo as usize) 554 }) 555 } 556 557 #[cfg(span_locations)] 558 pub fn end(&self) -> LineColumn { 559 #[cfg(fuzzing)] 560 return LineColumn { line: 0, column: 0 }; 561 562 #[cfg(not(fuzzing))] 563 SOURCE_MAP.with(|cm| { 564 let cm = cm.borrow(); 565 let fi = cm.fileinfo(*self); 566 fi.offset_line_column(self.hi as usize) 567 }) 568 } 569 570 #[cfg(not(span_locations))] 571 pub fn join(&self, _other: Span) -> Option<Span> { 572 Some(Span {}) 573 } 574 575 #[cfg(span_locations)] 576 pub fn join(&self, other: Span) -> Option<Span> { 577 #[cfg(fuzzing)] 578 return { 579 let _ = other; 580 None 581 }; 582 583 #[cfg(not(fuzzing))] 584 SOURCE_MAP.with(|cm| { 585 let cm = cm.borrow(); 586 // If `other` is not within the same FileInfo as us, return None. 587 if !cm.fileinfo(*self).span_within(other) { 588 return None; 589 } 590 Some(Span { 591 lo: cmp::min(self.lo, other.lo), 592 hi: cmp::max(self.hi, other.hi), 593 }) 594 }) 595 } 596 597 #[cfg(not(span_locations))] 598 pub fn source_text(&self) -> Option<String> { 599 None 600 } 601 602 #[cfg(span_locations)] 603 pub fn source_text(&self) -> Option<String> { 604 #[cfg(fuzzing)] 605 return None; 606 607 #[cfg(not(fuzzing))] 608 { 609 if self.is_call_site() { 610 None 611 } else { 612 Some(SOURCE_MAP.with(|cm| cm.borrow_mut().fileinfo_mut(*self).source_text(*self))) 613 } 614 } 615 } 616 617 #[cfg(not(span_locations))] 618 pub(crate) fn first_byte(self) -> Self { 619 self 620 } 621 622 #[cfg(span_locations)] 623 pub(crate) fn first_byte(self) -> Self { 624 Span { 625 lo: self.lo, 626 hi: cmp::min(self.lo.saturating_add(1), self.hi), 627 } 628 } 629 630 #[cfg(not(span_locations))] 631 pub(crate) fn last_byte(self) -> Self { 632 self 633 } 634 635 #[cfg(span_locations)] 636 pub(crate) fn last_byte(self) -> Self { 637 Span { 638 lo: cmp::max(self.hi.saturating_sub(1), self.lo), 639 hi: self.hi, 640 } 641 } 642 643 #[cfg(span_locations)] 644 fn is_call_site(&self) -> bool { 645 self.lo == 0 && self.hi == 0 646 } 647} 648 649impl Debug for Span { 650 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 651 #[cfg(span_locations)] 652 return write!(f, "bytes({}..{})", self.lo, self.hi); 653 654 #[cfg(not(span_locations))] 655 write!(f, "Span") 656 } 657} 658 659pub(crate) fn debug_span_field_if_nontrivial(debug: &mut fmt::DebugStruct, span: Span) { 660 #[cfg(span_locations)] 661 { 662 if span.is_call_site() { 663 return; 664 } 665 } 666 667 if cfg!(span_locations) { 668 debug.field("span", &span); 669 } 670} 671 672#[derive(Clone)] 673pub(crate) struct Group { 674 delimiter: Delimiter, 675 stream: TokenStream, 676 span: Span, 677} 678 679impl Group { 680 pub fn new(delimiter: Delimiter, stream: TokenStream) -> Self { 681 Group { 682 delimiter, 683 stream, 684 span: Span::call_site(), 685 } 686 } 687 688 pub fn delimiter(&self) -> Delimiter { 689 self.delimiter 690 } 691 692 pub fn stream(&self) -> TokenStream { 693 self.stream.clone() 694 } 695 696 pub fn span(&self) -> Span { 697 self.span 698 } 699 700 pub fn span_open(&self) -> Span { 701 self.span.first_byte() 702 } 703 704 pub fn span_close(&self) -> Span { 705 self.span.last_byte() 706 } 707 708 pub fn set_span(&mut self, span: Span) { 709 self.span = span; 710 } 711} 712 713impl Display for Group { 714 // We attempt to match libproc_macro's formatting. 715 // Empty parens: () 716 // Nonempty parens: (...) 717 // Empty brackets: [] 718 // Nonempty brackets: [...] 719 // Empty braces: { } 720 // Nonempty braces: { ... } 721 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 722 let (open, close) = match self.delimiter { 723 Delimiter::Parenthesis => ("(", ")"), 724 Delimiter::Brace => ("{ ", "}"), 725 Delimiter::Bracket => ("[", "]"), 726 Delimiter::None => ("", ""), 727 }; 728 729 f.write_str(open)?; 730 Display::fmt(&self.stream, f)?; 731 if self.delimiter == Delimiter::Brace && !self.stream.inner.is_empty() { 732 f.write_str(" ")?; 733 } 734 f.write_str(close)?; 735 736 Ok(()) 737 } 738} 739 740impl Debug for Group { 741 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 742 let mut debug = fmt.debug_struct("Group"); 743 debug.field("delimiter", &self.delimiter); 744 debug.field("stream", &self.stream); 745 debug_span_field_if_nontrivial(&mut debug, self.span); 746 debug.finish() 747 } 748} 749 750#[derive(Clone)] 751pub(crate) struct Ident { 752 sym: String, 753 span: Span, 754 raw: bool, 755} 756 757impl Ident { 758 #[track_caller] 759 pub fn new_checked(string: &str, span: Span) -> Self { 760 validate_ident(string); 761 Ident::new_unchecked(string, span) 762 } 763 764 pub fn new_unchecked(string: &str, span: Span) -> Self { 765 Ident { 766 sym: string.to_owned(), 767 span, 768 raw: false, 769 } 770 } 771 772 #[track_caller] 773 pub fn new_raw_checked(string: &str, span: Span) -> Self { 774 validate_ident_raw(string); 775 Ident::new_raw_unchecked(string, span) 776 } 777 778 pub fn new_raw_unchecked(string: &str, span: Span) -> Self { 779 Ident { 780 sym: string.to_owned(), 781 span, 782 raw: true, 783 } 784 } 785 786 pub fn span(&self) -> Span { 787 self.span 788 } 789 790 pub fn set_span(&mut self, span: Span) { 791 self.span = span; 792 } 793} 794 795pub(crate) fn is_ident_start(c: char) -> bool { 796 c == '_' || unicode_ident::is_xid_start(c) 797} 798 799pub(crate) fn is_ident_continue(c: char) -> bool { 800 unicode_ident::is_xid_continue(c) 801} 802 803#[track_caller] 804fn validate_ident(string: &str) { 805 if string.is_empty() { 806 panic!("Ident is not allowed to be empty; use Option<Ident>"); 807 } 808 809 if string.bytes().all(|digit| b'0' <= digit && digit <= b'9') { 810 panic!("Ident cannot be a number; use Literal instead"); 811 } 812 813 fn ident_ok(string: &str) -> bool { 814 let mut chars = string.chars(); 815 let first = chars.next().unwrap(); 816 if !is_ident_start(first) { 817 return false; 818 } 819 for ch in chars { 820 if !is_ident_continue(ch) { 821 return false; 822 } 823 } 824 true 825 } 826 827 if !ident_ok(string) { 828 panic!("{:?} is not a valid Ident", string); 829 } 830} 831 832#[track_caller] 833fn validate_ident_raw(string: &str) { 834 validate_ident(string); 835 836 match string { 837 "_" | "super" | "self" | "Self" | "crate" => { 838 panic!("`r#{}` cannot be a raw identifier", string); 839 } 840 _ => {} 841 } 842} 843 844impl PartialEq for Ident { 845 fn eq(&self, other: &Ident) -> bool { 846 self.sym == other.sym && self.raw == other.raw 847 } 848} 849 850impl<T> PartialEq<T> for Ident 851where 852 T: ?Sized + AsRef<str>, 853{ 854 fn eq(&self, other: &T) -> bool { 855 let other = other.as_ref(); 856 if self.raw { 857 other.starts_with("r#") && self.sym == other[2..] 858 } else { 859 self.sym == other 860 } 861 } 862} 863 864impl Display for Ident { 865 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 866 if self.raw { 867 f.write_str("r#")?; 868 } 869 Display::fmt(&self.sym, f) 870 } 871} 872 873#[allow(clippy::missing_fields_in_debug)] 874impl Debug for Ident { 875 // Ident(proc_macro), Ident(r#union) 876 #[cfg(not(span_locations))] 877 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 878 let mut debug = f.debug_tuple("Ident"); 879 debug.field(&format_args!("{}", self)); 880 debug.finish() 881 } 882 883 // Ident { 884 // sym: proc_macro, 885 // span: bytes(128..138) 886 // } 887 #[cfg(span_locations)] 888 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 889 let mut debug = f.debug_struct("Ident"); 890 debug.field("sym", &format_args!("{}", self)); 891 debug_span_field_if_nontrivial(&mut debug, self.span); 892 debug.finish() 893 } 894} 895 896#[derive(Clone)] 897pub(crate) struct Literal { 898 repr: String, 899 span: Span, 900} 901 902macro_rules! suffixed_numbers { 903 ($($name:ident => $kind:ident,)*) => ($( 904 pub fn $name(n: $kind) -> Literal { 905 Literal::_new(format!(concat!("{}", stringify!($kind)), n)) 906 } 907 )*) 908} 909 910macro_rules! unsuffixed_numbers { 911 ($($name:ident => $kind:ident,)*) => ($( 912 pub fn $name(n: $kind) -> Literal { 913 Literal::_new(n.to_string()) 914 } 915 )*) 916} 917 918impl Literal { 919 pub(crate) fn _new(repr: String) -> Self { 920 Literal { 921 repr, 922 span: Span::call_site(), 923 } 924 } 925 926 pub(crate) unsafe fn from_str_unchecked(repr: &str) -> Self { 927 Literal::_new(repr.to_owned()) 928 } 929 930 suffixed_numbers! { 931 u8_suffixed => u8, 932 u16_suffixed => u16, 933 u32_suffixed => u32, 934 u64_suffixed => u64, 935 u128_suffixed => u128, 936 usize_suffixed => usize, 937 i8_suffixed => i8, 938 i16_suffixed => i16, 939 i32_suffixed => i32, 940 i64_suffixed => i64, 941 i128_suffixed => i128, 942 isize_suffixed => isize, 943 944 f32_suffixed => f32, 945 f64_suffixed => f64, 946 } 947 948 unsuffixed_numbers! { 949 u8_unsuffixed => u8, 950 u16_unsuffixed => u16, 951 u32_unsuffixed => u32, 952 u64_unsuffixed => u64, 953 u128_unsuffixed => u128, 954 usize_unsuffixed => usize, 955 i8_unsuffixed => i8, 956 i16_unsuffixed => i16, 957 i32_unsuffixed => i32, 958 i64_unsuffixed => i64, 959 i128_unsuffixed => i128, 960 isize_unsuffixed => isize, 961 } 962 963 pub fn f32_unsuffixed(f: f32) -> Literal { 964 let mut s = f.to_string(); 965 if !s.contains('.') { 966 s.push_str(".0"); 967 } 968 Literal::_new(s) 969 } 970 971 pub fn f64_unsuffixed(f: f64) -> Literal { 972 let mut s = f.to_string(); 973 if !s.contains('.') { 974 s.push_str(".0"); 975 } 976 Literal::_new(s) 977 } 978 979 pub fn string(t: &str) -> Literal { 980 let mut repr = String::with_capacity(t.len() + 2); 981 repr.push('"'); 982 let mut chars = t.chars(); 983 while let Some(ch) = chars.next() { 984 if ch == '\0' { 985 repr.push_str( 986 if chars 987 .as_str() 988 .starts_with(|next| '0' <= next && next <= '7') 989 { 990 // circumvent clippy::octal_escapes lint 991 "\\x00" 992 } else { 993 "\\0" 994 }, 995 ); 996 } else if ch == '\'' { 997 // escape_debug turns this into "\'" which is unnecessary. 998 repr.push(ch); 999 } else { 1000 repr.extend(ch.escape_debug()); 1001 } 1002 } 1003 repr.push('"'); 1004 Literal::_new(repr) 1005 } 1006 1007 pub fn character(t: char) -> Literal { 1008 let mut repr = String::new(); 1009 repr.push('\''); 1010 if t == '"' { 1011 // escape_debug turns this into '\"' which is unnecessary. 1012 repr.push(t); 1013 } else { 1014 repr.extend(t.escape_debug()); 1015 } 1016 repr.push('\''); 1017 Literal::_new(repr) 1018 } 1019 1020 pub fn byte_string(bytes: &[u8]) -> Literal { 1021 let mut escaped = "b\"".to_string(); 1022 let mut bytes = bytes.iter(); 1023 while let Some(&b) = bytes.next() { 1024 #[allow(clippy::match_overlapping_arm)] 1025 match b { 1026 b'\0' => escaped.push_str(match bytes.as_slice().first() { 1027 // circumvent clippy::octal_escapes lint 1028 Some(b'0'..=b'7') => r"\x00", 1029 _ => r"\0", 1030 }), 1031 b'\t' => escaped.push_str(r"\t"), 1032 b'\n' => escaped.push_str(r"\n"), 1033 b'\r' => escaped.push_str(r"\r"), 1034 b'"' => escaped.push_str("\\\""), 1035 b'\\' => escaped.push_str("\\\\"), 1036 b'\x20'..=b'\x7E' => escaped.push(b as char), 1037 _ => { 1038 let _ = write!(escaped, "\\x{:02X}", b); 1039 } 1040 } 1041 } 1042 escaped.push('"'); 1043 Literal::_new(escaped) 1044 } 1045 1046 pub fn span(&self) -> Span { 1047 self.span 1048 } 1049 1050 pub fn set_span(&mut self, span: Span) { 1051 self.span = span; 1052 } 1053 1054 pub fn subspan<R: RangeBounds<usize>>(&self, range: R) -> Option<Span> { 1055 #[cfg(not(span_locations))] 1056 { 1057 let _ = range; 1058 None 1059 } 1060 1061 #[cfg(span_locations)] 1062 { 1063 use core::ops::Bound; 1064 1065 let lo = match range.start_bound() { 1066 Bound::Included(start) => { 1067 let start = u32::try_from(*start).ok()?; 1068 self.span.lo.checked_add(start)? 1069 } 1070 Bound::Excluded(start) => { 1071 let start = u32::try_from(*start).ok()?; 1072 self.span.lo.checked_add(start)?.checked_add(1)? 1073 } 1074 Bound::Unbounded => self.span.lo, 1075 }; 1076 let hi = match range.end_bound() { 1077 Bound::Included(end) => { 1078 let end = u32::try_from(*end).ok()?; 1079 self.span.lo.checked_add(end)?.checked_add(1)? 1080 } 1081 Bound::Excluded(end) => { 1082 let end = u32::try_from(*end).ok()?; 1083 self.span.lo.checked_add(end)? 1084 } 1085 Bound::Unbounded => self.span.hi, 1086 }; 1087 if lo <= hi && hi <= self.span.hi { 1088 Some(Span { lo, hi }) 1089 } else { 1090 None 1091 } 1092 } 1093 } 1094} 1095 1096impl FromStr for Literal { 1097 type Err = LexError; 1098 1099 fn from_str(repr: &str) -> Result<Self, Self::Err> { 1100 let mut cursor = get_cursor(repr); 1101 #[cfg(span_locations)] 1102 let lo = cursor.off; 1103 1104 let negative = cursor.starts_with_char('-'); 1105 if negative { 1106 cursor = cursor.advance(1); 1107 if !cursor.starts_with_fn(|ch| ch.is_ascii_digit()) { 1108 return Err(LexError::call_site()); 1109 } 1110 } 1111 1112 if let Ok((rest, mut literal)) = parse::literal(cursor) { 1113 if rest.is_empty() { 1114 if negative { 1115 literal.repr.insert(0, '-'); 1116 } 1117 literal.span = Span { 1118 #[cfg(span_locations)] 1119 lo, 1120 #[cfg(span_locations)] 1121 hi: rest.off, 1122 }; 1123 return Ok(literal); 1124 } 1125 } 1126 Err(LexError::call_site()) 1127 } 1128} 1129 1130impl Display for Literal { 1131 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1132 Display::fmt(&self.repr, f) 1133 } 1134} 1135 1136impl Debug for Literal { 1137 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 1138 let mut debug = fmt.debug_struct("Literal"); 1139 debug.field("lit", &format_args!("{}", self.repr)); 1140 debug_span_field_if_nontrivial(&mut debug, self.span); 1141 debug.finish() 1142 } 1143} 1144