proc_macro2/
fallback.rs

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