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