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 TokenStream {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result152 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
153 let mut joint = false;
154 for (i, tt) in self.inner.iter().enumerate() {
155 if i != 0 && !joint {
156 write!(f, " ")?;
157 }
158 joint = false;
159 match tt {
160 TokenTree::Group(tt) => {
161 let (start, end) = match tt.delimiter() {
162 Delimiter::Parenthesis => ("(", ")"),
163 Delimiter::Brace => ("{", "}"),
164 Delimiter::Bracket => ("[", "]"),
165 Delimiter::None => ("", ""),
166 };
167 if tt.stream().into_iter().next().is_none() {
168 write!(f, "{} {}", start, end)?
169 } else {
170 write!(f, "{} {} {}", start, tt.stream(), end)?
171 }
172 }
173 TokenTree::Ident(tt) => write!(f, "{}", tt)?,
174 TokenTree::Punct(tt) => {
175 write!(f, "{}", tt.as_char())?;
176 match tt.spacing() {
177 Spacing::Alone => {}
178 Spacing::Joint => joint = true,
179 }
180 }
181 TokenTree::Literal(tt) => write!(f, "{}", tt)?,
182 }
183 }
184
185 Ok(())
186 }
187 }
188
189 impl Debug for TokenStream {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result190 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
191 f.write_str("TokenStream ")?;
192 f.debug_list().entries(self.clone()).finish()
193 }
194 }
195
196 #[cfg(use_proc_macro)]
197 impl From<proc_macro::TokenStream> for TokenStream {
from(inner: proc_macro::TokenStream) -> TokenStream198 fn from(inner: proc_macro::TokenStream) -> TokenStream {
199 inner
200 .to_string()
201 .parse()
202 .expect("compiler token stream parse failed")
203 }
204 }
205
206 #[cfg(use_proc_macro)]
207 impl From<TokenStream> for proc_macro::TokenStream {
from(inner: TokenStream) -> proc_macro::TokenStream208 fn from(inner: TokenStream) -> proc_macro::TokenStream {
209 inner
210 .to_string()
211 .parse()
212 .expect("failed to parse to compiler tokens")
213 }
214 }
215
216 impl From<TokenTree> for TokenStream {
from(tree: TokenTree) -> TokenStream217 fn from(tree: TokenTree) -> TokenStream {
218 let mut stream = TokenStream::new();
219 stream.push_token(tree);
220 stream
221 }
222 }
223
224 impl FromIterator<TokenTree> for TokenStream {
from_iter<I: IntoIterator<Item = TokenTree>>(tokens: I) -> Self225 fn from_iter<I: IntoIterator<Item = TokenTree>>(tokens: I) -> Self {
226 let mut stream = TokenStream::new();
227 stream.extend(tokens);
228 stream
229 }
230 }
231
232 impl FromIterator<TokenStream> for TokenStream {
from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self233 fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self {
234 let mut v = Vec::new();
235
236 for mut stream in streams {
237 v.extend(stream.take_inner());
238 }
239
240 TokenStream { inner: v }
241 }
242 }
243
244 impl Extend<TokenTree> for TokenStream {
extend<I: IntoIterator<Item = TokenTree>>(&mut self, tokens: I)245 fn extend<I: IntoIterator<Item = TokenTree>>(&mut self, tokens: I) {
246 tokens.into_iter().for_each(|token| self.push_token(token));
247 }
248 }
249
250 impl Extend<TokenStream> for TokenStream {
extend<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I)251 fn extend<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I) {
252 self.inner.extend(streams.into_iter().flatten());
253 }
254 }
255
256 pub(crate) type TokenTreeIter = vec::IntoIter<TokenTree>;
257
258 impl IntoIterator for TokenStream {
259 type Item = TokenTree;
260 type IntoIter = TokenTreeIter;
261
into_iter(mut self) -> TokenTreeIter262 fn into_iter(mut self) -> TokenTreeIter {
263 self.take_inner().into_iter()
264 }
265 }
266
267 #[derive(Clone, PartialEq, Eq)]
268 pub(crate) struct SourceFile {
269 path: PathBuf,
270 }
271
272 impl SourceFile {
273 /// Get the path to this source file as a string.
path(&self) -> PathBuf274 pub fn path(&self) -> PathBuf {
275 self.path.clone()
276 }
277
is_real(&self) -> bool278 pub fn is_real(&self) -> bool {
279 // XXX(nika): Support real files in the future?
280 false
281 }
282 }
283
284 impl Debug for SourceFile {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result285 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
286 f.debug_struct("SourceFile")
287 .field("path", &self.path())
288 .field("is_real", &self.is_real())
289 .finish()
290 }
291 }
292
293 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
294 pub(crate) struct LineColumn {
295 pub line: usize,
296 pub column: usize,
297 }
298
299 #[cfg(span_locations)]
300 thread_local! {
301 static SOURCE_MAP: RefCell<SourceMap> = RefCell::new(SourceMap {
302 // NOTE: We start with a single dummy file which all call_site() and
303 // def_site() spans reference.
304 files: vec![FileInfo {
305 #[cfg(procmacro2_semver_exempt)]
306 name: "<unspecified>".to_owned(),
307 span: Span { lo: 0, hi: 0 },
308 lines: vec![0],
309 }],
310 });
311 }
312
313 #[cfg(span_locations)]
314 struct FileInfo {
315 #[cfg(procmacro2_semver_exempt)]
316 name: String,
317 span: Span,
318 lines: Vec<usize>,
319 }
320
321 #[cfg(span_locations)]
322 impl FileInfo {
offset_line_column(&self, offset: usize) -> LineColumn323 fn offset_line_column(&self, offset: usize) -> LineColumn {
324 assert!(self.span_within(Span {
325 lo: offset as u32,
326 hi: offset as u32
327 }));
328 let offset = offset - self.span.lo as usize;
329 match self.lines.binary_search(&offset) {
330 Ok(found) => LineColumn {
331 line: found + 1,
332 column: 0,
333 },
334 Err(idx) => LineColumn {
335 line: idx,
336 column: offset - self.lines[idx - 1],
337 },
338 }
339 }
340
span_within(&self, span: Span) -> bool341 fn span_within(&self, span: Span) -> bool {
342 span.lo >= self.span.lo && span.hi <= self.span.hi
343 }
344 }
345
346 /// Computes the offsets of each line in the given source string
347 /// and the total number of characters
348 #[cfg(span_locations)]
lines_offsets(s: &str) -> (usize, Vec<usize>)349 fn lines_offsets(s: &str) -> (usize, Vec<usize>) {
350 let mut lines = vec![0];
351 let mut total = 0;
352
353 for ch in s.chars() {
354 total += 1;
355 if ch == '\n' {
356 lines.push(total);
357 }
358 }
359
360 (total, lines)
361 }
362
363 #[cfg(span_locations)]
364 struct SourceMap {
365 files: Vec<FileInfo>,
366 }
367
368 #[cfg(span_locations)]
369 impl SourceMap {
next_start_pos(&self) -> u32370 fn next_start_pos(&self) -> u32 {
371 // Add 1 so there's always space between files.
372 //
373 // We'll always have at least 1 file, as we initialize our files list
374 // with a dummy file.
375 self.files.last().unwrap().span.hi + 1
376 }
377
add_file(&mut self, name: &str, src: &str) -> Span378 fn add_file(&mut self, name: &str, src: &str) -> Span {
379 let (len, lines) = lines_offsets(src);
380 let lo = self.next_start_pos();
381 // XXX(nika): Shouild we bother doing a checked cast or checked add here?
382 let span = Span {
383 lo,
384 hi: lo + (len as u32),
385 };
386
387 self.files.push(FileInfo {
388 #[cfg(procmacro2_semver_exempt)]
389 name: name.to_owned(),
390 span,
391 lines,
392 });
393
394 #[cfg(not(procmacro2_semver_exempt))]
395 let _ = name;
396
397 span
398 }
399
fileinfo(&self, span: Span) -> &FileInfo400 fn fileinfo(&self, span: Span) -> &FileInfo {
401 for file in &self.files {
402 if file.span_within(span) {
403 return file;
404 }
405 }
406 panic!("Invalid span with no related FileInfo!");
407 }
408 }
409
410 #[derive(Clone, Copy, PartialEq, Eq)]
411 pub(crate) struct Span {
412 #[cfg(span_locations)]
413 pub(crate) lo: u32,
414 #[cfg(span_locations)]
415 pub(crate) hi: u32,
416 }
417
418 impl Span {
419 #[cfg(not(span_locations))]
call_site() -> Span420 pub fn call_site() -> Span {
421 Span {}
422 }
423
424 #[cfg(span_locations)]
call_site() -> Span425 pub fn call_site() -> Span {
426 Span { lo: 0, hi: 0 }
427 }
428
429 #[cfg(procmacro2_semver_exempt)]
430 #[cfg(hygiene)]
mixed_site() -> Span431 pub fn mixed_site() -> Span {
432 Span::call_site()
433 }
434
435 #[cfg(procmacro2_semver_exempt)]
def_site() -> Span436 pub fn def_site() -> Span {
437 Span::call_site()
438 }
439
440 #[cfg(procmacro2_semver_exempt)]
resolved_at(&self, _other: Span) -> Span441 pub fn resolved_at(&self, _other: Span) -> Span {
442 // Stable spans consist only of line/column information, so
443 // `resolved_at` and `located_at` only select which span the
444 // caller wants line/column information from.
445 *self
446 }
447
448 #[cfg(procmacro2_semver_exempt)]
located_at(&self, other: Span) -> Span449 pub fn located_at(&self, other: Span) -> Span {
450 other
451 }
452
453 #[cfg(procmacro2_semver_exempt)]
source_file(&self) -> SourceFile454 pub fn source_file(&self) -> SourceFile {
455 SOURCE_MAP.with(|cm| {
456 let cm = cm.borrow();
457 let fi = cm.fileinfo(*self);
458 SourceFile {
459 path: Path::new(&fi.name).to_owned(),
460 }
461 })
462 }
463
464 #[cfg(span_locations)]
start(&self) -> LineColumn465 pub fn start(&self) -> LineColumn {
466 SOURCE_MAP.with(|cm| {
467 let cm = cm.borrow();
468 let fi = cm.fileinfo(*self);
469 fi.offset_line_column(self.lo as usize)
470 })
471 }
472
473 #[cfg(span_locations)]
end(&self) -> LineColumn474 pub fn end(&self) -> LineColumn {
475 SOURCE_MAP.with(|cm| {
476 let cm = cm.borrow();
477 let fi = cm.fileinfo(*self);
478 fi.offset_line_column(self.hi as usize)
479 })
480 }
481
482 #[cfg(not(span_locations))]
join(&self, _other: Span) -> Option<Span>483 pub fn join(&self, _other: Span) -> Option<Span> {
484 Some(Span {})
485 }
486
487 #[cfg(span_locations)]
join(&self, other: Span) -> Option<Span>488 pub fn join(&self, other: Span) -> Option<Span> {
489 SOURCE_MAP.with(|cm| {
490 let cm = cm.borrow();
491 // If `other` is not within the same FileInfo as us, return None.
492 if !cm.fileinfo(*self).span_within(other) {
493 return None;
494 }
495 Some(Span {
496 lo: cmp::min(self.lo, other.lo),
497 hi: cmp::max(self.hi, other.hi),
498 })
499 })
500 }
501
502 #[cfg(not(span_locations))]
first_byte(self) -> Self503 fn first_byte(self) -> Self {
504 self
505 }
506
507 #[cfg(span_locations)]
first_byte(self) -> Self508 fn first_byte(self) -> Self {
509 Span {
510 lo: self.lo,
511 hi: cmp::min(self.lo.saturating_add(1), self.hi),
512 }
513 }
514
515 #[cfg(not(span_locations))]
last_byte(self) -> Self516 fn last_byte(self) -> Self {
517 self
518 }
519
520 #[cfg(span_locations)]
last_byte(self) -> Self521 fn last_byte(self) -> Self {
522 Span {
523 lo: cmp::max(self.hi.saturating_sub(1), self.lo),
524 hi: self.hi,
525 }
526 }
527 }
528
529 impl Debug for Span {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result530 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
531 #[cfg(span_locations)]
532 return write!(f, "bytes({}..{})", self.lo, self.hi);
533
534 #[cfg(not(span_locations))]
535 write!(f, "Span")
536 }
537 }
538
debug_span_field_if_nontrivial(debug: &mut fmt::DebugStruct, span: Span)539 pub(crate) fn debug_span_field_if_nontrivial(debug: &mut fmt::DebugStruct, span: Span) {
540 #[cfg(span_locations)]
541 {
542 if span.lo == 0 && span.hi == 0 {
543 return;
544 }
545 }
546
547 if cfg!(span_locations) {
548 debug.field("span", &span);
549 }
550 }
551
552 #[derive(Clone)]
553 pub(crate) struct Group {
554 delimiter: Delimiter,
555 stream: TokenStream,
556 span: Span,
557 }
558
559 impl Group {
new(delimiter: Delimiter, stream: TokenStream) -> Group560 pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group {
561 Group {
562 delimiter,
563 stream,
564 span: Span::call_site(),
565 }
566 }
567
delimiter(&self) -> Delimiter568 pub fn delimiter(&self) -> Delimiter {
569 self.delimiter
570 }
571
stream(&self) -> TokenStream572 pub fn stream(&self) -> TokenStream {
573 self.stream.clone()
574 }
575
span(&self) -> Span576 pub fn span(&self) -> Span {
577 self.span
578 }
579
span_open(&self) -> Span580 pub fn span_open(&self) -> Span {
581 self.span.first_byte()
582 }
583
span_close(&self) -> Span584 pub fn span_close(&self) -> Span {
585 self.span.last_byte()
586 }
587
set_span(&mut self, span: Span)588 pub fn set_span(&mut self, span: Span) {
589 self.span = span;
590 }
591 }
592
593 impl Display for Group {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result594 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
595 let (left, right) = match self.delimiter {
596 Delimiter::Parenthesis => ("(", ")"),
597 Delimiter::Brace => ("{", "}"),
598 Delimiter::Bracket => ("[", "]"),
599 Delimiter::None => ("", ""),
600 };
601
602 f.write_str(left)?;
603 Display::fmt(&self.stream, f)?;
604 f.write_str(right)?;
605
606 Ok(())
607 }
608 }
609
610 impl Debug for Group {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result611 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
612 let mut debug = fmt.debug_struct("Group");
613 debug.field("delimiter", &self.delimiter);
614 debug.field("stream", &self.stream);
615 debug_span_field_if_nontrivial(&mut debug, self.span);
616 debug.finish()
617 }
618 }
619
620 #[derive(Clone)]
621 pub(crate) struct Ident {
622 sym: String,
623 span: Span,
624 raw: bool,
625 }
626
627 impl Ident {
_new(string: &str, raw: bool, span: Span) -> Ident628 fn _new(string: &str, raw: bool, span: Span) -> Ident {
629 validate_ident(string);
630
631 Ident {
632 sym: string.to_owned(),
633 span,
634 raw,
635 }
636 }
637
new(string: &str, span: Span) -> Ident638 pub fn new(string: &str, span: Span) -> Ident {
639 Ident::_new(string, false, span)
640 }
641
new_raw(string: &str, span: Span) -> Ident642 pub fn new_raw(string: &str, span: Span) -> Ident {
643 Ident::_new(string, true, span)
644 }
645
span(&self) -> Span646 pub fn span(&self) -> Span {
647 self.span
648 }
649
set_span(&mut self, span: Span)650 pub fn set_span(&mut self, span: Span) {
651 self.span = span;
652 }
653 }
654
is_ident_start(c: char) -> bool655 pub(crate) fn is_ident_start(c: char) -> bool {
656 ('a' <= c && c <= 'z')
657 || ('A' <= c && c <= 'Z')
658 || c == '_'
659 || (c > '\x7f' && UnicodeXID::is_xid_start(c))
660 }
661
is_ident_continue(c: char) -> bool662 pub(crate) fn is_ident_continue(c: char) -> bool {
663 ('a' <= c && c <= 'z')
664 || ('A' <= c && c <= 'Z')
665 || c == '_'
666 || ('0' <= c && c <= '9')
667 || (c > '\x7f' && UnicodeXID::is_xid_continue(c))
668 }
669
validate_ident(string: &str)670 fn validate_ident(string: &str) {
671 let validate = string;
672 if validate.is_empty() {
673 panic!("Ident is not allowed to be empty; use Option<Ident>");
674 }
675
676 if validate.bytes().all(|digit| digit >= b'0' && digit <= b'9') {
677 panic!("Ident cannot be a number; use Literal instead");
678 }
679
680 fn ident_ok(string: &str) -> bool {
681 let mut chars = string.chars();
682 let first = chars.next().unwrap();
683 if !is_ident_start(first) {
684 return false;
685 }
686 for ch in chars {
687 if !is_ident_continue(ch) {
688 return false;
689 }
690 }
691 true
692 }
693
694 if !ident_ok(validate) {
695 panic!("{:?} is not a valid Ident", string);
696 }
697 }
698
699 impl PartialEq for Ident {
eq(&self, other: &Ident) -> bool700 fn eq(&self, other: &Ident) -> bool {
701 self.sym == other.sym && self.raw == other.raw
702 }
703 }
704
705 impl<T> PartialEq<T> for Ident
706 where
707 T: ?Sized + AsRef<str>,
708 {
eq(&self, other: &T) -> bool709 fn eq(&self, other: &T) -> bool {
710 let other = other.as_ref();
711 if self.raw {
712 other.starts_with("r#") && self.sym == other[2..]
713 } else {
714 self.sym == other
715 }
716 }
717 }
718
719 impl Display for Ident {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result720 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
721 if self.raw {
722 f.write_str("r#")?;
723 }
724 Display::fmt(&self.sym, f)
725 }
726 }
727
728 impl Debug for Ident {
729 // Ident(proc_macro), Ident(r#union)
730 #[cfg(not(span_locations))]
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result731 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
732 let mut debug = f.debug_tuple("Ident");
733 debug.field(&format_args!("{}", self));
734 debug.finish()
735 }
736
737 // Ident {
738 // sym: proc_macro,
739 // span: bytes(128..138)
740 // }
741 #[cfg(span_locations)]
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result742 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
743 let mut debug = f.debug_struct("Ident");
744 debug.field("sym", &format_args!("{}", self));
745 debug_span_field_if_nontrivial(&mut debug, self.span);
746 debug.finish()
747 }
748 }
749
750 #[derive(Clone)]
751 pub(crate) struct Literal {
752 text: String,
753 span: Span,
754 }
755
756 macro_rules! suffixed_numbers {
757 ($($name:ident => $kind:ident,)*) => ($(
758 pub fn $name(n: $kind) -> Literal {
759 Literal::_new(format!(concat!("{}", stringify!($kind)), n))
760 }
761 )*)
762 }
763
764 macro_rules! unsuffixed_numbers {
765 ($($name:ident => $kind:ident,)*) => ($(
766 pub fn $name(n: $kind) -> Literal {
767 Literal::_new(n.to_string())
768 }
769 )*)
770 }
771
772 impl Literal {
_new(text: String) -> Literal773 pub(crate) fn _new(text: String) -> Literal {
774 Literal {
775 text,
776 span: Span::call_site(),
777 }
778 }
779
780 suffixed_numbers! {
781 u8_suffixed => u8,
782 u16_suffixed => u16,
783 u32_suffixed => u32,
784 u64_suffixed => u64,
785 u128_suffixed => u128,
786 usize_suffixed => usize,
787 i8_suffixed => i8,
788 i16_suffixed => i16,
789 i32_suffixed => i32,
790 i64_suffixed => i64,
791 i128_suffixed => i128,
792 isize_suffixed => isize,
793
794 f32_suffixed => f32,
795 f64_suffixed => f64,
796 }
797
798 unsuffixed_numbers! {
799 u8_unsuffixed => u8,
800 u16_unsuffixed => u16,
801 u32_unsuffixed => u32,
802 u64_unsuffixed => u64,
803 u128_unsuffixed => u128,
804 usize_unsuffixed => usize,
805 i8_unsuffixed => i8,
806 i16_unsuffixed => i16,
807 i32_unsuffixed => i32,
808 i64_unsuffixed => i64,
809 i128_unsuffixed => i128,
810 isize_unsuffixed => isize,
811 }
812
f32_unsuffixed(f: f32) -> Literal813 pub fn f32_unsuffixed(f: f32) -> Literal {
814 let mut s = f.to_string();
815 if !s.contains('.') {
816 s.push_str(".0");
817 }
818 Literal::_new(s)
819 }
820
f64_unsuffixed(f: f64) -> Literal821 pub fn f64_unsuffixed(f: f64) -> Literal {
822 let mut s = f.to_string();
823 if !s.contains('.') {
824 s.push_str(".0");
825 }
826 Literal::_new(s)
827 }
828
string(t: &str) -> Literal829 pub fn string(t: &str) -> Literal {
830 let mut text = String::with_capacity(t.len() + 2);
831 text.push('"');
832 for c in t.chars() {
833 if c == '\'' {
834 // escape_debug turns this into "\'" which is unnecessary.
835 text.push(c);
836 } else {
837 text.extend(c.escape_debug());
838 }
839 }
840 text.push('"');
841 Literal::_new(text)
842 }
843
character(t: char) -> Literal844 pub fn character(t: char) -> Literal {
845 let mut text = String::new();
846 text.push('\'');
847 if t == '"' {
848 // escape_debug turns this into '\"' which is unnecessary.
849 text.push(t);
850 } else {
851 text.extend(t.escape_debug());
852 }
853 text.push('\'');
854 Literal::_new(text)
855 }
856
byte_string(bytes: &[u8]) -> Literal857 pub fn byte_string(bytes: &[u8]) -> Literal {
858 let mut escaped = "b\"".to_string();
859 for b in bytes {
860 #[allow(clippy::match_overlapping_arm)]
861 match *b {
862 b'\0' => escaped.push_str(r"\0"),
863 b'\t' => escaped.push_str(r"\t"),
864 b'\n' => escaped.push_str(r"\n"),
865 b'\r' => escaped.push_str(r"\r"),
866 b'"' => escaped.push_str("\\\""),
867 b'\\' => escaped.push_str("\\\\"),
868 b'\x20'..=b'\x7E' => escaped.push(*b as char),
869 _ => escaped.push_str(&format!("\\x{:02X}", b)),
870 }
871 }
872 escaped.push('"');
873 Literal::_new(escaped)
874 }
875
span(&self) -> Span876 pub fn span(&self) -> Span {
877 self.span
878 }
879
set_span(&mut self, span: Span)880 pub fn set_span(&mut self, span: Span) {
881 self.span = span;
882 }
883
subspan<R: RangeBounds<usize>>(&self, _range: R) -> Option<Span>884 pub fn subspan<R: RangeBounds<usize>>(&self, _range: R) -> Option<Span> {
885 None
886 }
887 }
888
889 impl Display for Literal {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result890 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
891 Display::fmt(&self.text, f)
892 }
893 }
894
895 impl Debug for Literal {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result896 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
897 let mut debug = fmt.debug_struct("Literal");
898 debug.field("lit", &format_args!("{}", self.text));
899 debug_span_field_if_nontrivial(&mut debug, self.span);
900 debug.finish()
901 }
902 }
903