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