1 use crate::parse::{token_stream, Cursor};
2 use crate::{Delimiter, Spacing, TokenTree};
3 #[cfg(span_locations)]
4 use std::cell::RefCell;
5 #[cfg(span_locations)]
6 use std::cmp;
7 use std::fmt::{self, Debug, Display};
8 use std::iter::FromIterator;
9 use std::mem;
10 use std::ops::RangeBounds;
11 #[cfg(procmacro2_semver_exempt)]
12 use std::path::Path;
13 use std::path::PathBuf;
14 use std::str::FromStr;
15 use std::vec;
16 use unicode_xid::UnicodeXID;
17
18 /// Force use of proc-macro2's fallback implementation of the API for now, even
19 /// if the compiler's implementation is available.
force()20 pub fn force() {
21 #[cfg(wrap_proc_macro)]
22 crate::detection::force_fallback();
23 }
24
25 /// Resume using the compiler's implementation of the proc macro API if it is
26 /// available.
unforce()27 pub fn unforce() {
28 #[cfg(wrap_proc_macro)]
29 crate::detection::unforce_fallback();
30 }
31
32 #[derive(Clone)]
33 pub(crate) struct TokenStream {
34 pub(crate) inner: Vec<TokenTree>,
35 }
36
37 #[derive(Debug)]
38 pub(crate) struct LexError;
39
40 impl TokenStream {
new() -> TokenStream41 pub fn new() -> TokenStream {
42 TokenStream { inner: Vec::new() }
43 }
44
is_empty(&self) -> bool45 pub fn is_empty(&self) -> bool {
46 self.inner.len() == 0
47 }
48
take_inner(&mut self) -> Vec<TokenTree>49 fn take_inner(&mut self) -> Vec<TokenTree> {
50 mem::replace(&mut self.inner, Vec::new())
51 }
52
push_token(&mut self, token: TokenTree)53 fn push_token(&mut self, token: TokenTree) {
54 // https://github.com/alexcrichton/proc-macro2/issues/235
55 match token {
56 #[cfg(not(no_bind_by_move_pattern_guard))]
57 TokenTree::Literal(crate::Literal {
58 #[cfg(wrap_proc_macro)]
59 inner: crate::imp::Literal::Fallback(literal),
60 #[cfg(not(wrap_proc_macro))]
61 inner: literal,
62 ..
63 }) if literal.text.starts_with('-') => {
64 push_negative_literal(self, literal);
65 }
66 #[cfg(no_bind_by_move_pattern_guard)]
67 TokenTree::Literal(crate::Literal {
68 #[cfg(wrap_proc_macro)]
69 inner: crate::imp::Literal::Fallback(literal),
70 #[cfg(not(wrap_proc_macro))]
71 inner: literal,
72 ..
73 }) => {
74 if literal.text.starts_with('-') {
75 push_negative_literal(self, literal);
76 } else {
77 self.inner
78 .push(TokenTree::Literal(crate::Literal::_new_stable(literal)));
79 }
80 }
81 _ => self.inner.push(token),
82 }
83
84 #[cold]
85 fn push_negative_literal(stream: &mut TokenStream, mut literal: Literal) {
86 literal.text.remove(0);
87 let mut punct = crate::Punct::new('-', Spacing::Alone);
88 punct.set_span(crate::Span::_new_stable(literal.span));
89 stream.inner.push(TokenTree::Punct(punct));
90 stream
91 .inner
92 .push(TokenTree::Literal(crate::Literal::_new_stable(literal)));
93 }
94 }
95 }
96
97 // Nonrecursive to prevent stack overflow.
98 impl Drop for TokenStream {
drop(&mut self)99 fn drop(&mut self) {
100 while let Some(token) = self.inner.pop() {
101 let group = match token {
102 TokenTree::Group(group) => group.inner,
103 _ => continue,
104 };
105 #[cfg(wrap_proc_macro)]
106 let group = match group {
107 crate::imp::Group::Fallback(group) => group,
108 _ => continue,
109 };
110 let mut group = group;
111 self.inner.extend(group.stream.take_inner());
112 }
113 }
114 }
115
116 #[cfg(span_locations)]
get_cursor(src: &str) -> Cursor117 fn get_cursor(src: &str) -> Cursor {
118 // Create a dummy file & add it to the source map
119 SOURCE_MAP.with(|cm| {
120 let mut cm = cm.borrow_mut();
121 let name = format!("<parsed string {}>", cm.files.len());
122 let span = cm.add_file(&name, src);
123 Cursor {
124 rest: src,
125 off: span.lo,
126 }
127 })
128 }
129
130 #[cfg(not(span_locations))]
get_cursor(src: &str) -> Cursor131 fn get_cursor(src: &str) -> Cursor {
132 Cursor { rest: src }
133 }
134
135 impl FromStr for TokenStream {
136 type Err = LexError;
137
from_str(src: &str) -> Result<TokenStream, LexError>138 fn from_str(src: &str) -> Result<TokenStream, LexError> {
139 // Create a dummy file & add it to the source map
140 let cursor = get_cursor(src);
141
142 let (rest, tokens) = token_stream(cursor)?;
143 if rest.is_empty() {
144 Ok(tokens)
145 } else {
146 Err(LexError)
147 }
148 }
149 }
150
151 impl Display for LexError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result152 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
153 f.write_str("cannot parse string into token stream")
154 }
155 }
156
157 impl Display for TokenStream {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result158 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
159 let mut joint = false;
160 for (i, tt) in self.inner.iter().enumerate() {
161 if i != 0 && !joint {
162 write!(f, " ")?;
163 }
164 joint = false;
165 match tt {
166 TokenTree::Group(tt) => Display::fmt(tt, f),
167 TokenTree::Ident(tt) => Display::fmt(tt, f),
168 TokenTree::Punct(tt) => {
169 joint = tt.spacing() == Spacing::Joint;
170 Display::fmt(tt, f)
171 }
172 TokenTree::Literal(tt) => Display::fmt(tt, f),
173 }?
174 }
175
176 Ok(())
177 }
178 }
179
180 impl Debug for TokenStream {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result181 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
182 f.write_str("TokenStream ")?;
183 f.debug_list().entries(self.clone()).finish()
184 }
185 }
186
187 #[cfg(use_proc_macro)]
188 impl From<proc_macro::TokenStream> for TokenStream {
from(inner: proc_macro::TokenStream) -> TokenStream189 fn from(inner: proc_macro::TokenStream) -> TokenStream {
190 inner
191 .to_string()
192 .parse()
193 .expect("compiler token stream parse failed")
194 }
195 }
196
197 #[cfg(use_proc_macro)]
198 impl From<TokenStream> for proc_macro::TokenStream {
from(inner: TokenStream) -> proc_macro::TokenStream199 fn from(inner: TokenStream) -> proc_macro::TokenStream {
200 inner
201 .to_string()
202 .parse()
203 .expect("failed to parse to compiler tokens")
204 }
205 }
206
207 impl From<TokenTree> for TokenStream {
from(tree: TokenTree) -> TokenStream208 fn from(tree: TokenTree) -> TokenStream {
209 let mut stream = TokenStream::new();
210 stream.push_token(tree);
211 stream
212 }
213 }
214
215 impl FromIterator<TokenTree> for TokenStream {
from_iter<I: IntoIterator<Item = TokenTree>>(tokens: I) -> Self216 fn from_iter<I: IntoIterator<Item = TokenTree>>(tokens: I) -> Self {
217 let mut stream = TokenStream::new();
218 stream.extend(tokens);
219 stream
220 }
221 }
222
223 impl FromIterator<TokenStream> for TokenStream {
from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self224 fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self {
225 let mut v = Vec::new();
226
227 for mut stream in streams {
228 v.extend(stream.take_inner());
229 }
230
231 TokenStream { inner: v }
232 }
233 }
234
235 impl Extend<TokenTree> for TokenStream {
extend<I: IntoIterator<Item = TokenTree>>(&mut self, tokens: I)236 fn extend<I: IntoIterator<Item = TokenTree>>(&mut self, tokens: I) {
237 tokens.into_iter().for_each(|token| self.push_token(token));
238 }
239 }
240
241 impl Extend<TokenStream> for TokenStream {
extend<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I)242 fn extend<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I) {
243 self.inner.extend(streams.into_iter().flatten());
244 }
245 }
246
247 pub(crate) type TokenTreeIter = vec::IntoIter<TokenTree>;
248
249 impl IntoIterator for TokenStream {
250 type Item = TokenTree;
251 type IntoIter = TokenTreeIter;
252
into_iter(mut self) -> TokenTreeIter253 fn into_iter(mut self) -> TokenTreeIter {
254 self.take_inner().into_iter()
255 }
256 }
257
258 #[derive(Clone, PartialEq, Eq)]
259 pub(crate) struct SourceFile {
260 path: PathBuf,
261 }
262
263 impl SourceFile {
264 /// Get the path to this source file as a string.
path(&self) -> PathBuf265 pub fn path(&self) -> PathBuf {
266 self.path.clone()
267 }
268
is_real(&self) -> bool269 pub fn is_real(&self) -> bool {
270 // XXX(nika): Support real files in the future?
271 false
272 }
273 }
274
275 impl Debug for SourceFile {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result276 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
277 f.debug_struct("SourceFile")
278 .field("path", &self.path())
279 .field("is_real", &self.is_real())
280 .finish()
281 }
282 }
283
284 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
285 pub(crate) struct LineColumn {
286 pub line: usize,
287 pub column: usize,
288 }
289
290 #[cfg(span_locations)]
291 thread_local! {
292 static SOURCE_MAP: RefCell<SourceMap> = RefCell::new(SourceMap {
293 // NOTE: We start with a single dummy file which all call_site() and
294 // def_site() spans reference.
295 files: vec![FileInfo {
296 #[cfg(procmacro2_semver_exempt)]
297 name: "<unspecified>".to_owned(),
298 span: Span { lo: 0, hi: 0 },
299 lines: vec![0],
300 }],
301 });
302 }
303
304 #[cfg(span_locations)]
305 struct FileInfo {
306 #[cfg(procmacro2_semver_exempt)]
307 name: String,
308 span: Span,
309 lines: Vec<usize>,
310 }
311
312 #[cfg(span_locations)]
313 impl FileInfo {
offset_line_column(&self, offset: usize) -> LineColumn314 fn offset_line_column(&self, offset: usize) -> LineColumn {
315 assert!(self.span_within(Span {
316 lo: offset as u32,
317 hi: offset as u32
318 }));
319 let offset = offset - self.span.lo as usize;
320 match self.lines.binary_search(&offset) {
321 Ok(found) => LineColumn {
322 line: found + 1,
323 column: 0,
324 },
325 Err(idx) => LineColumn {
326 line: idx,
327 column: offset - self.lines[idx - 1],
328 },
329 }
330 }
331
span_within(&self, span: Span) -> bool332 fn span_within(&self, span: Span) -> bool {
333 span.lo >= self.span.lo && span.hi <= self.span.hi
334 }
335 }
336
337 /// Computes the offsets of each line in the given source string
338 /// and the total number of characters
339 #[cfg(span_locations)]
lines_offsets(s: &str) -> (usize, Vec<usize>)340 fn lines_offsets(s: &str) -> (usize, Vec<usize>) {
341 let mut lines = vec![0];
342 let mut total = 0;
343
344 for ch in s.chars() {
345 total += 1;
346 if ch == '\n' {
347 lines.push(total);
348 }
349 }
350
351 (total, lines)
352 }
353
354 #[cfg(span_locations)]
355 struct SourceMap {
356 files: Vec<FileInfo>,
357 }
358
359 #[cfg(span_locations)]
360 impl SourceMap {
next_start_pos(&self) -> u32361 fn next_start_pos(&self) -> u32 {
362 // Add 1 so there's always space between files.
363 //
364 // We'll always have at least 1 file, as we initialize our files list
365 // with a dummy file.
366 self.files.last().unwrap().span.hi + 1
367 }
368
add_file(&mut self, name: &str, src: &str) -> Span369 fn add_file(&mut self, name: &str, src: &str) -> Span {
370 let (len, lines) = lines_offsets(src);
371 let lo = self.next_start_pos();
372 // XXX(nika): Shouild we bother doing a checked cast or checked add here?
373 let span = Span {
374 lo,
375 hi: lo + (len as u32),
376 };
377
378 self.files.push(FileInfo {
379 #[cfg(procmacro2_semver_exempt)]
380 name: name.to_owned(),
381 span,
382 lines,
383 });
384
385 #[cfg(not(procmacro2_semver_exempt))]
386 let _ = name;
387
388 span
389 }
390
fileinfo(&self, span: Span) -> &FileInfo391 fn fileinfo(&self, span: Span) -> &FileInfo {
392 for file in &self.files {
393 if file.span_within(span) {
394 return file;
395 }
396 }
397 panic!("Invalid span with no related FileInfo!");
398 }
399 }
400
401 #[derive(Clone, Copy, PartialEq, Eq)]
402 pub(crate) struct Span {
403 #[cfg(span_locations)]
404 pub(crate) lo: u32,
405 #[cfg(span_locations)]
406 pub(crate) hi: u32,
407 }
408
409 impl Span {
410 #[cfg(not(span_locations))]
call_site() -> Span411 pub fn call_site() -> Span {
412 Span {}
413 }
414
415 #[cfg(span_locations)]
call_site() -> Span416 pub fn call_site() -> Span {
417 Span { lo: 0, hi: 0 }
418 }
419
420 #[cfg(hygiene)]
mixed_site() -> Span421 pub fn mixed_site() -> Span {
422 Span::call_site()
423 }
424
425 #[cfg(procmacro2_semver_exempt)]
def_site() -> Span426 pub fn def_site() -> Span {
427 Span::call_site()
428 }
429
resolved_at(&self, _other: Span) -> Span430 pub fn resolved_at(&self, _other: Span) -> Span {
431 // Stable spans consist only of line/column information, so
432 // `resolved_at` and `located_at` only select which span the
433 // caller wants line/column information from.
434 *self
435 }
436
located_at(&self, other: Span) -> Span437 pub fn located_at(&self, other: Span) -> Span {
438 other
439 }
440
441 #[cfg(procmacro2_semver_exempt)]
source_file(&self) -> SourceFile442 pub fn source_file(&self) -> SourceFile {
443 SOURCE_MAP.with(|cm| {
444 let cm = cm.borrow();
445 let fi = cm.fileinfo(*self);
446 SourceFile {
447 path: Path::new(&fi.name).to_owned(),
448 }
449 })
450 }
451
452 #[cfg(span_locations)]
start(&self) -> LineColumn453 pub fn start(&self) -> LineColumn {
454 SOURCE_MAP.with(|cm| {
455 let cm = cm.borrow();
456 let fi = cm.fileinfo(*self);
457 fi.offset_line_column(self.lo as usize)
458 })
459 }
460
461 #[cfg(span_locations)]
end(&self) -> LineColumn462 pub fn end(&self) -> LineColumn {
463 SOURCE_MAP.with(|cm| {
464 let cm = cm.borrow();
465 let fi = cm.fileinfo(*self);
466 fi.offset_line_column(self.hi as usize)
467 })
468 }
469
470 #[cfg(not(span_locations))]
join(&self, _other: Span) -> Option<Span>471 pub fn join(&self, _other: Span) -> Option<Span> {
472 Some(Span {})
473 }
474
475 #[cfg(span_locations)]
join(&self, other: Span) -> Option<Span>476 pub fn join(&self, other: Span) -> Option<Span> {
477 SOURCE_MAP.with(|cm| {
478 let cm = cm.borrow();
479 // If `other` is not within the same FileInfo as us, return None.
480 if !cm.fileinfo(*self).span_within(other) {
481 return None;
482 }
483 Some(Span {
484 lo: cmp::min(self.lo, other.lo),
485 hi: cmp::max(self.hi, other.hi),
486 })
487 })
488 }
489
490 #[cfg(not(span_locations))]
first_byte(self) -> Self491 fn first_byte(self) -> Self {
492 self
493 }
494
495 #[cfg(span_locations)]
first_byte(self) -> Self496 fn first_byte(self) -> Self {
497 Span {
498 lo: self.lo,
499 hi: cmp::min(self.lo.saturating_add(1), self.hi),
500 }
501 }
502
503 #[cfg(not(span_locations))]
last_byte(self) -> Self504 fn last_byte(self) -> Self {
505 self
506 }
507
508 #[cfg(span_locations)]
last_byte(self) -> Self509 fn last_byte(self) -> Self {
510 Span {
511 lo: cmp::max(self.hi.saturating_sub(1), self.lo),
512 hi: self.hi,
513 }
514 }
515 }
516
517 impl Debug for Span {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result518 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
519 #[cfg(span_locations)]
520 return write!(f, "bytes({}..{})", self.lo, self.hi);
521
522 #[cfg(not(span_locations))]
523 write!(f, "Span")
524 }
525 }
526
debug_span_field_if_nontrivial(debug: &mut fmt::DebugStruct, span: Span)527 pub(crate) fn debug_span_field_if_nontrivial(debug: &mut fmt::DebugStruct, span: Span) {
528 #[cfg(span_locations)]
529 {
530 if span.lo == 0 && span.hi == 0 {
531 return;
532 }
533 }
534
535 if cfg!(span_locations) {
536 debug.field("span", &span);
537 }
538 }
539
540 #[derive(Clone)]
541 pub(crate) struct Group {
542 delimiter: Delimiter,
543 stream: TokenStream,
544 span: Span,
545 }
546
547 impl Group {
new(delimiter: Delimiter, stream: TokenStream) -> Group548 pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group {
549 Group {
550 delimiter,
551 stream,
552 span: Span::call_site(),
553 }
554 }
555
delimiter(&self) -> Delimiter556 pub fn delimiter(&self) -> Delimiter {
557 self.delimiter
558 }
559
stream(&self) -> TokenStream560 pub fn stream(&self) -> TokenStream {
561 self.stream.clone()
562 }
563
span(&self) -> Span564 pub fn span(&self) -> Span {
565 self.span
566 }
567
span_open(&self) -> Span568 pub fn span_open(&self) -> Span {
569 self.span.first_byte()
570 }
571
span_close(&self) -> Span572 pub fn span_close(&self) -> Span {
573 self.span.last_byte()
574 }
575
set_span(&mut self, span: Span)576 pub fn set_span(&mut self, span: Span) {
577 self.span = span;
578 }
579 }
580
581 impl Display for Group {
582 // We attempt to match libproc_macro's formatting.
583 // Empty parens: ()
584 // Nonempty parens: (...)
585 // Empty brackets: []
586 // Nonempty brackets: [...]
587 // Empty braces: { }
588 // Nonempty braces: { ... }
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result589 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
590 let (open, close) = match self.delimiter {
591 Delimiter::Parenthesis => ("(", ")"),
592 Delimiter::Brace => ("{ ", "}"),
593 Delimiter::Bracket => ("[", "]"),
594 Delimiter::None => ("", ""),
595 };
596
597 f.write_str(open)?;
598 Display::fmt(&self.stream, f)?;
599 if self.delimiter == Delimiter::Brace && !self.stream.inner.is_empty() {
600 f.write_str(" ")?;
601 }
602 f.write_str(close)?;
603
604 Ok(())
605 }
606 }
607
608 impl Debug for Group {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result609 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
610 let mut debug = fmt.debug_struct("Group");
611 debug.field("delimiter", &self.delimiter);
612 debug.field("stream", &self.stream);
613 debug_span_field_if_nontrivial(&mut debug, self.span);
614 debug.finish()
615 }
616 }
617
618 #[derive(Clone)]
619 pub(crate) struct Ident {
620 sym: String,
621 span: Span,
622 raw: bool,
623 }
624
625 impl Ident {
_new(string: &str, raw: bool, span: Span) -> Ident626 fn _new(string: &str, raw: bool, span: Span) -> Ident {
627 validate_ident(string);
628
629 Ident {
630 sym: string.to_owned(),
631 span,
632 raw,
633 }
634 }
635
new(string: &str, span: Span) -> Ident636 pub fn new(string: &str, span: Span) -> Ident {
637 Ident::_new(string, false, span)
638 }
639
new_raw(string: &str, span: Span) -> Ident640 pub fn new_raw(string: &str, span: Span) -> Ident {
641 Ident::_new(string, true, span)
642 }
643
span(&self) -> Span644 pub fn span(&self) -> Span {
645 self.span
646 }
647
set_span(&mut self, span: Span)648 pub fn set_span(&mut self, span: Span) {
649 self.span = span;
650 }
651 }
652
is_ident_start(c: char) -> bool653 pub(crate) fn is_ident_start(c: char) -> bool {
654 ('a' <= c && c <= 'z')
655 || ('A' <= c && c <= 'Z')
656 || c == '_'
657 || (c > '\x7f' && UnicodeXID::is_xid_start(c))
658 }
659
is_ident_continue(c: char) -> bool660 pub(crate) fn is_ident_continue(c: char) -> bool {
661 ('a' <= c && c <= 'z')
662 || ('A' <= c && c <= 'Z')
663 || c == '_'
664 || ('0' <= c && c <= '9')
665 || (c > '\x7f' && UnicodeXID::is_xid_continue(c))
666 }
667
validate_ident(string: &str)668 fn validate_ident(string: &str) {
669 let validate = string;
670 if validate.is_empty() {
671 panic!("Ident is not allowed to be empty; use Option<Ident>");
672 }
673
674 if validate.bytes().all(|digit| digit >= b'0' && digit <= b'9') {
675 panic!("Ident cannot be a number; use Literal instead");
676 }
677
678 fn ident_ok(string: &str) -> bool {
679 let mut chars = string.chars();
680 let first = chars.next().unwrap();
681 if !is_ident_start(first) {
682 return false;
683 }
684 for ch in chars {
685 if !is_ident_continue(ch) {
686 return false;
687 }
688 }
689 true
690 }
691
692 if !ident_ok(validate) {
693 panic!("{:?} is not a valid Ident", string);
694 }
695 }
696
697 impl PartialEq for Ident {
eq(&self, other: &Ident) -> bool698 fn eq(&self, other: &Ident) -> bool {
699 self.sym == other.sym && self.raw == other.raw
700 }
701 }
702
703 impl<T> PartialEq<T> for Ident
704 where
705 T: ?Sized + AsRef<str>,
706 {
eq(&self, other: &T) -> bool707 fn eq(&self, other: &T) -> bool {
708 let other = other.as_ref();
709 if self.raw {
710 other.starts_with("r#") && self.sym == other[2..]
711 } else {
712 self.sym == other
713 }
714 }
715 }
716
717 impl Display for Ident {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result718 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
719 if self.raw {
720 f.write_str("r#")?;
721 }
722 Display::fmt(&self.sym, f)
723 }
724 }
725
726 impl Debug for Ident {
727 // Ident(proc_macro), Ident(r#union)
728 #[cfg(not(span_locations))]
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result729 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
730 let mut debug = f.debug_tuple("Ident");
731 debug.field(&format_args!("{}", self));
732 debug.finish()
733 }
734
735 // Ident {
736 // sym: proc_macro,
737 // span: bytes(128..138)
738 // }
739 #[cfg(span_locations)]
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result740 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
741 let mut debug = f.debug_struct("Ident");
742 debug.field("sym", &format_args!("{}", self));
743 debug_span_field_if_nontrivial(&mut debug, self.span);
744 debug.finish()
745 }
746 }
747
748 #[derive(Clone)]
749 pub(crate) struct Literal {
750 text: String,
751 span: Span,
752 }
753
754 macro_rules! suffixed_numbers {
755 ($($name:ident => $kind:ident,)*) => ($(
756 pub fn $name(n: $kind) -> Literal {
757 Literal::_new(format!(concat!("{}", stringify!($kind)), n))
758 }
759 )*)
760 }
761
762 macro_rules! unsuffixed_numbers {
763 ($($name:ident => $kind:ident,)*) => ($(
764 pub fn $name(n: $kind) -> Literal {
765 Literal::_new(n.to_string())
766 }
767 )*)
768 }
769
770 impl Literal {
_new(text: String) -> Literal771 pub(crate) fn _new(text: String) -> Literal {
772 Literal {
773 text,
774 span: Span::call_site(),
775 }
776 }
777
778 suffixed_numbers! {
779 u8_suffixed => u8,
780 u16_suffixed => u16,
781 u32_suffixed => u32,
782 u64_suffixed => u64,
783 u128_suffixed => u128,
784 usize_suffixed => usize,
785 i8_suffixed => i8,
786 i16_suffixed => i16,
787 i32_suffixed => i32,
788 i64_suffixed => i64,
789 i128_suffixed => i128,
790 isize_suffixed => isize,
791
792 f32_suffixed => f32,
793 f64_suffixed => f64,
794 }
795
796 unsuffixed_numbers! {
797 u8_unsuffixed => u8,
798 u16_unsuffixed => u16,
799 u32_unsuffixed => u32,
800 u64_unsuffixed => u64,
801 u128_unsuffixed => u128,
802 usize_unsuffixed => usize,
803 i8_unsuffixed => i8,
804 i16_unsuffixed => i16,
805 i32_unsuffixed => i32,
806 i64_unsuffixed => i64,
807 i128_unsuffixed => i128,
808 isize_unsuffixed => isize,
809 }
810
f32_unsuffixed(f: f32) -> Literal811 pub fn f32_unsuffixed(f: f32) -> Literal {
812 let mut s = f.to_string();
813 if !s.contains('.') {
814 s.push_str(".0");
815 }
816 Literal::_new(s)
817 }
818
f64_unsuffixed(f: f64) -> Literal819 pub fn f64_unsuffixed(f: f64) -> Literal {
820 let mut s = f.to_string();
821 if !s.contains('.') {
822 s.push_str(".0");
823 }
824 Literal::_new(s)
825 }
826
string(t: &str) -> Literal827 pub fn string(t: &str) -> Literal {
828 let mut text = String::with_capacity(t.len() + 2);
829 text.push('"');
830 for c in t.chars() {
831 if c == '\'' {
832 // escape_debug turns this into "\'" which is unnecessary.
833 text.push(c);
834 } else {
835 text.extend(c.escape_debug());
836 }
837 }
838 text.push('"');
839 Literal::_new(text)
840 }
841
character(t: char) -> Literal842 pub fn character(t: char) -> Literal {
843 let mut text = String::new();
844 text.push('\'');
845 if t == '"' {
846 // escape_debug turns this into '\"' which is unnecessary.
847 text.push(t);
848 } else {
849 text.extend(t.escape_debug());
850 }
851 text.push('\'');
852 Literal::_new(text)
853 }
854
byte_string(bytes: &[u8]) -> Literal855 pub fn byte_string(bytes: &[u8]) -> Literal {
856 let mut escaped = "b\"".to_string();
857 for b in bytes {
858 #[allow(clippy::match_overlapping_arm)]
859 match *b {
860 b'\0' => escaped.push_str(r"\0"),
861 b'\t' => escaped.push_str(r"\t"),
862 b'\n' => escaped.push_str(r"\n"),
863 b'\r' => escaped.push_str(r"\r"),
864 b'"' => escaped.push_str("\\\""),
865 b'\\' => escaped.push_str("\\\\"),
866 b'\x20'..=b'\x7E' => escaped.push(*b as char),
867 _ => escaped.push_str(&format!("\\x{:02X}", b)),
868 }
869 }
870 escaped.push('"');
871 Literal::_new(escaped)
872 }
873
span(&self) -> Span874 pub fn span(&self) -> Span {
875 self.span
876 }
877
set_span(&mut self, span: Span)878 pub fn set_span(&mut self, span: Span) {
879 self.span = span;
880 }
881
subspan<R: RangeBounds<usize>>(&self, _range: R) -> Option<Span>882 pub fn subspan<R: RangeBounds<usize>>(&self, _range: R) -> Option<Span> {
883 None
884 }
885 }
886
887 impl Display for Literal {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result888 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
889 Display::fmt(&self.text, f)
890 }
891 }
892
893 impl Debug for Literal {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result894 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
895 let mut debug = fmt.debug_struct("Literal");
896 debug.field("lit", &format_args!("{}", self.text));
897 debug_span_field_if_nontrivial(&mut debug, self.span);
898 debug.finish()
899 }
900 }
901