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(hygiene)]
mixed_site() -> Span430 pub fn mixed_site() -> Span {
431 Span::call_site()
432 }
433
434 #[cfg(procmacro2_semver_exempt)]
def_site() -> Span435 pub fn def_site() -> Span {
436 Span::call_site()
437 }
438
resolved_at(&self, _other: Span) -> Span439 pub fn resolved_at(&self, _other: Span) -> Span {
440 // Stable spans consist only of line/column information, so
441 // `resolved_at` and `located_at` only select which span the
442 // caller wants line/column information from.
443 *self
444 }
445
located_at(&self, other: Span) -> Span446 pub fn located_at(&self, other: Span) -> Span {
447 other
448 }
449
450 #[cfg(procmacro2_semver_exempt)]
source_file(&self) -> SourceFile451 pub fn source_file(&self) -> SourceFile {
452 SOURCE_MAP.with(|cm| {
453 let cm = cm.borrow();
454 let fi = cm.fileinfo(*self);
455 SourceFile {
456 path: Path::new(&fi.name).to_owned(),
457 }
458 })
459 }
460
461 #[cfg(span_locations)]
start(&self) -> LineColumn462 pub fn start(&self) -> LineColumn {
463 SOURCE_MAP.with(|cm| {
464 let cm = cm.borrow();
465 let fi = cm.fileinfo(*self);
466 fi.offset_line_column(self.lo as usize)
467 })
468 }
469
470 #[cfg(span_locations)]
end(&self) -> LineColumn471 pub fn end(&self) -> LineColumn {
472 SOURCE_MAP.with(|cm| {
473 let cm = cm.borrow();
474 let fi = cm.fileinfo(*self);
475 fi.offset_line_column(self.hi as usize)
476 })
477 }
478
479 #[cfg(not(span_locations))]
join(&self, _other: Span) -> Option<Span>480 pub fn join(&self, _other: Span) -> Option<Span> {
481 Some(Span {})
482 }
483
484 #[cfg(span_locations)]
join(&self, other: Span) -> Option<Span>485 pub fn join(&self, other: Span) -> Option<Span> {
486 SOURCE_MAP.with(|cm| {
487 let cm = cm.borrow();
488 // If `other` is not within the same FileInfo as us, return None.
489 if !cm.fileinfo(*self).span_within(other) {
490 return None;
491 }
492 Some(Span {
493 lo: cmp::min(self.lo, other.lo),
494 hi: cmp::max(self.hi, other.hi),
495 })
496 })
497 }
498
499 #[cfg(not(span_locations))]
first_byte(self) -> Self500 fn first_byte(self) -> Self {
501 self
502 }
503
504 #[cfg(span_locations)]
first_byte(self) -> Self505 fn first_byte(self) -> Self {
506 Span {
507 lo: self.lo,
508 hi: cmp::min(self.lo.saturating_add(1), self.hi),
509 }
510 }
511
512 #[cfg(not(span_locations))]
last_byte(self) -> Self513 fn last_byte(self) -> Self {
514 self
515 }
516
517 #[cfg(span_locations)]
last_byte(self) -> Self518 fn last_byte(self) -> Self {
519 Span {
520 lo: cmp::max(self.hi.saturating_sub(1), self.lo),
521 hi: self.hi,
522 }
523 }
524 }
525
526 impl Debug for Span {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result527 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
528 #[cfg(span_locations)]
529 return write!(f, "bytes({}..{})", self.lo, self.hi);
530
531 #[cfg(not(span_locations))]
532 write!(f, "Span")
533 }
534 }
535
debug_span_field_if_nontrivial(debug: &mut fmt::DebugStruct, span: Span)536 pub(crate) fn debug_span_field_if_nontrivial(debug: &mut fmt::DebugStruct, span: Span) {
537 #[cfg(span_locations)]
538 {
539 if span.lo == 0 && span.hi == 0 {
540 return;
541 }
542 }
543
544 if cfg!(span_locations) {
545 debug.field("span", &span);
546 }
547 }
548
549 #[derive(Clone)]
550 pub(crate) struct Group {
551 delimiter: Delimiter,
552 stream: TokenStream,
553 span: Span,
554 }
555
556 impl Group {
new(delimiter: Delimiter, stream: TokenStream) -> Group557 pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group {
558 Group {
559 delimiter,
560 stream,
561 span: Span::call_site(),
562 }
563 }
564
delimiter(&self) -> Delimiter565 pub fn delimiter(&self) -> Delimiter {
566 self.delimiter
567 }
568
stream(&self) -> TokenStream569 pub fn stream(&self) -> TokenStream {
570 self.stream.clone()
571 }
572
span(&self) -> Span573 pub fn span(&self) -> Span {
574 self.span
575 }
576
span_open(&self) -> Span577 pub fn span_open(&self) -> Span {
578 self.span.first_byte()
579 }
580
span_close(&self) -> Span581 pub fn span_close(&self) -> Span {
582 self.span.last_byte()
583 }
584
set_span(&mut self, span: Span)585 pub fn set_span(&mut self, span: Span) {
586 self.span = span;
587 }
588 }
589
590 impl Display for Group {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result591 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
592 let (left, right) = match self.delimiter {
593 Delimiter::Parenthesis => ("(", ")"),
594 Delimiter::Brace => ("{", "}"),
595 Delimiter::Bracket => ("[", "]"),
596 Delimiter::None => ("", ""),
597 };
598
599 f.write_str(left)?;
600 Display::fmt(&self.stream, f)?;
601 f.write_str(right)?;
602
603 Ok(())
604 }
605 }
606
607 impl Debug for Group {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result608 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
609 let mut debug = fmt.debug_struct("Group");
610 debug.field("delimiter", &self.delimiter);
611 debug.field("stream", &self.stream);
612 debug_span_field_if_nontrivial(&mut debug, self.span);
613 debug.finish()
614 }
615 }
616
617 #[derive(Clone)]
618 pub(crate) struct Ident {
619 sym: String,
620 span: Span,
621 raw: bool,
622 }
623
624 impl Ident {
_new(string: &str, raw: bool, span: Span) -> Ident625 fn _new(string: &str, raw: bool, span: Span) -> Ident {
626 validate_ident(string);
627
628 Ident {
629 sym: string.to_owned(),
630 span,
631 raw,
632 }
633 }
634
new(string: &str, span: Span) -> Ident635 pub fn new(string: &str, span: Span) -> Ident {
636 Ident::_new(string, false, span)
637 }
638
new_raw(string: &str, span: Span) -> Ident639 pub fn new_raw(string: &str, span: Span) -> Ident {
640 Ident::_new(string, true, span)
641 }
642
span(&self) -> Span643 pub fn span(&self) -> Span {
644 self.span
645 }
646
set_span(&mut self, span: Span)647 pub fn set_span(&mut self, span: Span) {
648 self.span = span;
649 }
650 }
651
is_ident_start(c: char) -> bool652 pub(crate) fn is_ident_start(c: char) -> bool {
653 ('a' <= c && c <= 'z')
654 || ('A' <= c && c <= 'Z')
655 || c == '_'
656 || (c > '\x7f' && UnicodeXID::is_xid_start(c))
657 }
658
is_ident_continue(c: char) -> bool659 pub(crate) fn is_ident_continue(c: char) -> bool {
660 ('a' <= c && c <= 'z')
661 || ('A' <= c && c <= 'Z')
662 || c == '_'
663 || ('0' <= c && c <= '9')
664 || (c > '\x7f' && UnicodeXID::is_xid_continue(c))
665 }
666
validate_ident(string: &str)667 fn validate_ident(string: &str) {
668 let validate = string;
669 if validate.is_empty() {
670 panic!("Ident is not allowed to be empty; use Option<Ident>");
671 }
672
673 if validate.bytes().all(|digit| digit >= b'0' && digit <= b'9') {
674 panic!("Ident cannot be a number; use Literal instead");
675 }
676
677 fn ident_ok(string: &str) -> bool {
678 let mut chars = string.chars();
679 let first = chars.next().unwrap();
680 if !is_ident_start(first) {
681 return false;
682 }
683 for ch in chars {
684 if !is_ident_continue(ch) {
685 return false;
686 }
687 }
688 true
689 }
690
691 if !ident_ok(validate) {
692 panic!("{:?} is not a valid Ident", string);
693 }
694 }
695
696 impl PartialEq for Ident {
eq(&self, other: &Ident) -> bool697 fn eq(&self, other: &Ident) -> bool {
698 self.sym == other.sym && self.raw == other.raw
699 }
700 }
701
702 impl<T> PartialEq<T> for Ident
703 where
704 T: ?Sized + AsRef<str>,
705 {
eq(&self, other: &T) -> bool706 fn eq(&self, other: &T) -> bool {
707 let other = other.as_ref();
708 if self.raw {
709 other.starts_with("r#") && self.sym == other[2..]
710 } else {
711 self.sym == other
712 }
713 }
714 }
715
716 impl Display for Ident {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result717 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
718 if self.raw {
719 f.write_str("r#")?;
720 }
721 Display::fmt(&self.sym, f)
722 }
723 }
724
725 impl Debug for Ident {
726 // Ident(proc_macro), Ident(r#union)
727 #[cfg(not(span_locations))]
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result728 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
729 let mut debug = f.debug_tuple("Ident");
730 debug.field(&format_args!("{}", self));
731 debug.finish()
732 }
733
734 // Ident {
735 // sym: proc_macro,
736 // span: bytes(128..138)
737 // }
738 #[cfg(span_locations)]
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result739 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
740 let mut debug = f.debug_struct("Ident");
741 debug.field("sym", &format_args!("{}", self));
742 debug_span_field_if_nontrivial(&mut debug, self.span);
743 debug.finish()
744 }
745 }
746
747 #[derive(Clone)]
748 pub(crate) struct Literal {
749 text: String,
750 span: Span,
751 }
752
753 macro_rules! suffixed_numbers {
754 ($($name:ident => $kind:ident,)*) => ($(
755 pub fn $name(n: $kind) -> Literal {
756 Literal::_new(format!(concat!("{}", stringify!($kind)), n))
757 }
758 )*)
759 }
760
761 macro_rules! unsuffixed_numbers {
762 ($($name:ident => $kind:ident,)*) => ($(
763 pub fn $name(n: $kind) -> Literal {
764 Literal::_new(n.to_string())
765 }
766 )*)
767 }
768
769 impl Literal {
_new(text: String) -> Literal770 pub(crate) fn _new(text: String) -> Literal {
771 Literal {
772 text,
773 span: Span::call_site(),
774 }
775 }
776
777 suffixed_numbers! {
778 u8_suffixed => u8,
779 u16_suffixed => u16,
780 u32_suffixed => u32,
781 u64_suffixed => u64,
782 u128_suffixed => u128,
783 usize_suffixed => usize,
784 i8_suffixed => i8,
785 i16_suffixed => i16,
786 i32_suffixed => i32,
787 i64_suffixed => i64,
788 i128_suffixed => i128,
789 isize_suffixed => isize,
790
791 f32_suffixed => f32,
792 f64_suffixed => f64,
793 }
794
795 unsuffixed_numbers! {
796 u8_unsuffixed => u8,
797 u16_unsuffixed => u16,
798 u32_unsuffixed => u32,
799 u64_unsuffixed => u64,
800 u128_unsuffixed => u128,
801 usize_unsuffixed => usize,
802 i8_unsuffixed => i8,
803 i16_unsuffixed => i16,
804 i32_unsuffixed => i32,
805 i64_unsuffixed => i64,
806 i128_unsuffixed => i128,
807 isize_unsuffixed => isize,
808 }
809
f32_unsuffixed(f: f32) -> Literal810 pub fn f32_unsuffixed(f: f32) -> Literal {
811 let mut s = f.to_string();
812 if !s.contains('.') {
813 s.push_str(".0");
814 }
815 Literal::_new(s)
816 }
817
f64_unsuffixed(f: f64) -> Literal818 pub fn f64_unsuffixed(f: f64) -> Literal {
819 let mut s = f.to_string();
820 if !s.contains('.') {
821 s.push_str(".0");
822 }
823 Literal::_new(s)
824 }
825
string(t: &str) -> Literal826 pub fn string(t: &str) -> Literal {
827 let mut text = String::with_capacity(t.len() + 2);
828 text.push('"');
829 for c in t.chars() {
830 if c == '\'' {
831 // escape_debug turns this into "\'" which is unnecessary.
832 text.push(c);
833 } else {
834 text.extend(c.escape_debug());
835 }
836 }
837 text.push('"');
838 Literal::_new(text)
839 }
840
character(t: char) -> Literal841 pub fn character(t: char) -> Literal {
842 let mut text = String::new();
843 text.push('\'');
844 if t == '"' {
845 // escape_debug turns this into '\"' which is unnecessary.
846 text.push(t);
847 } else {
848 text.extend(t.escape_debug());
849 }
850 text.push('\'');
851 Literal::_new(text)
852 }
853
byte_string(bytes: &[u8]) -> Literal854 pub fn byte_string(bytes: &[u8]) -> Literal {
855 let mut escaped = "b\"".to_string();
856 for b in bytes {
857 #[allow(clippy::match_overlapping_arm)]
858 match *b {
859 b'\0' => escaped.push_str(r"\0"),
860 b'\t' => escaped.push_str(r"\t"),
861 b'\n' => escaped.push_str(r"\n"),
862 b'\r' => escaped.push_str(r"\r"),
863 b'"' => escaped.push_str("\\\""),
864 b'\\' => escaped.push_str("\\\\"),
865 b'\x20'..=b'\x7E' => escaped.push(*b as char),
866 _ => escaped.push_str(&format!("\\x{:02X}", b)),
867 }
868 }
869 escaped.push('"');
870 Literal::_new(escaped)
871 }
872
span(&self) -> Span873 pub fn span(&self) -> Span {
874 self.span
875 }
876
set_span(&mut self, span: Span)877 pub fn set_span(&mut self, span: Span) {
878 self.span = span;
879 }
880
subspan<R: RangeBounds<usize>>(&self, _range: R) -> Option<Span>881 pub fn subspan<R: RangeBounds<usize>>(&self, _range: R) -> Option<Span> {
882 None
883 }
884 }
885
886 impl Display for Literal {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result887 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
888 Display::fmt(&self.text, f)
889 }
890 }
891
892 impl Debug for Literal {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result893 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
894 let mut debug = fmt.debug_struct("Literal");
895 debug.field("lit", &format_args!("{}", self.text));
896 debug_span_field_if_nontrivial(&mut debug, self.span);
897 debug.finish()
898 }
899 }
900