1 use crate::parse::{self, 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 pub(crate) span: Span,
40 }
41
42 impl LexError {
span(&self) -> Span43 pub(crate) fn span(&self) -> Span {
44 self.span
45 }
46
call_site() -> Self47 fn call_site() -> Self {
48 LexError {
49 span: Span::call_site(),
50 }
51 }
52 }
53
54 impl TokenStream {
new() -> TokenStream55 pub fn new() -> TokenStream {
56 TokenStream { inner: Vec::new() }
57 }
58
is_empty(&self) -> bool59 pub fn is_empty(&self) -> bool {
60 self.inner.len() == 0
61 }
62
take_inner(&mut self) -> Vec<TokenTree>63 fn take_inner(&mut self) -> Vec<TokenTree> {
64 mem::replace(&mut self.inner, Vec::new())
65 }
66
push_token(&mut self, token: TokenTree)67 fn push_token(&mut self, token: TokenTree) {
68 // https://github.com/alexcrichton/proc-macro2/issues/235
69 match token {
70 #[cfg(not(no_bind_by_move_pattern_guard))]
71 TokenTree::Literal(crate::Literal {
72 #[cfg(wrap_proc_macro)]
73 inner: crate::imp::Literal::Fallback(literal),
74 #[cfg(not(wrap_proc_macro))]
75 inner: literal,
76 ..
77 }) if literal.text.starts_with('-') => {
78 push_negative_literal(self, literal);
79 }
80 #[cfg(no_bind_by_move_pattern_guard)]
81 TokenTree::Literal(crate::Literal {
82 #[cfg(wrap_proc_macro)]
83 inner: crate::imp::Literal::Fallback(literal),
84 #[cfg(not(wrap_proc_macro))]
85 inner: literal,
86 ..
87 }) => {
88 if literal.text.starts_with('-') {
89 push_negative_literal(self, literal);
90 } else {
91 self.inner
92 .push(TokenTree::Literal(crate::Literal::_new_stable(literal)));
93 }
94 }
95 _ => self.inner.push(token),
96 }
97
98 #[cold]
99 fn push_negative_literal(stream: &mut TokenStream, mut literal: Literal) {
100 literal.text.remove(0);
101 let mut punct = crate::Punct::new('-', Spacing::Alone);
102 punct.set_span(crate::Span::_new_stable(literal.span));
103 stream.inner.push(TokenTree::Punct(punct));
104 stream
105 .inner
106 .push(TokenTree::Literal(crate::Literal::_new_stable(literal)));
107 }
108 }
109 }
110
111 // Nonrecursive to prevent stack overflow.
112 impl Drop for TokenStream {
drop(&mut self)113 fn drop(&mut self) {
114 while let Some(token) = self.inner.pop() {
115 let group = match token {
116 TokenTree::Group(group) => group.inner,
117 _ => continue,
118 };
119 #[cfg(wrap_proc_macro)]
120 let group = match group {
121 crate::imp::Group::Fallback(group) => group,
122 _ => continue,
123 };
124 let mut group = group;
125 self.inner.extend(group.stream.take_inner());
126 }
127 }
128 }
129
130 #[cfg(span_locations)]
get_cursor(src: &str) -> Cursor131 fn get_cursor(src: &str) -> Cursor {
132 // Create a dummy file & add it to the source map
133 SOURCE_MAP.with(|cm| {
134 let mut cm = cm.borrow_mut();
135 let name = format!("<parsed string {}>", cm.files.len());
136 let span = cm.add_file(&name, src);
137 Cursor {
138 rest: src,
139 off: span.lo,
140 }
141 })
142 }
143
144 #[cfg(not(span_locations))]
get_cursor(src: &str) -> Cursor145 fn get_cursor(src: &str) -> Cursor {
146 Cursor { rest: src }
147 }
148
149 impl FromStr for TokenStream {
150 type Err = LexError;
151
from_str(src: &str) -> Result<TokenStream, LexError>152 fn from_str(src: &str) -> Result<TokenStream, LexError> {
153 // Create a dummy file & add it to the source map
154 let cursor = get_cursor(src);
155
156 parse::token_stream(cursor)
157 }
158 }
159
160 impl Display for LexError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result161 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
162 f.write_str("cannot parse string into token stream")
163 }
164 }
165
166 impl Display for TokenStream {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result167 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
168 let mut joint = false;
169 for (i, tt) in self.inner.iter().enumerate() {
170 if i != 0 && !joint {
171 write!(f, " ")?;
172 }
173 joint = false;
174 match tt {
175 TokenTree::Group(tt) => Display::fmt(tt, f),
176 TokenTree::Ident(tt) => Display::fmt(tt, f),
177 TokenTree::Punct(tt) => {
178 joint = tt.spacing() == Spacing::Joint;
179 Display::fmt(tt, f)
180 }
181 TokenTree::Literal(tt) => Display::fmt(tt, f),
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 {
591 // We attempt to match libproc_macro's formatting.
592 // Empty parens: ()
593 // Nonempty parens: (...)
594 // Empty brackets: []
595 // Nonempty brackets: [...]
596 // Empty braces: { }
597 // Nonempty braces: { ... }
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result598 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
599 let (open, close) = match self.delimiter {
600 Delimiter::Parenthesis => ("(", ")"),
601 Delimiter::Brace => ("{ ", "}"),
602 Delimiter::Bracket => ("[", "]"),
603 Delimiter::None => ("", ""),
604 };
605
606 f.write_str(open)?;
607 Display::fmt(&self.stream, f)?;
608 if self.delimiter == Delimiter::Brace && !self.stream.inner.is_empty() {
609 f.write_str(" ")?;
610 }
611 f.write_str(close)?;
612
613 Ok(())
614 }
615 }
616
617 impl Debug for Group {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result618 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
619 let mut debug = fmt.debug_struct("Group");
620 debug.field("delimiter", &self.delimiter);
621 debug.field("stream", &self.stream);
622 debug_span_field_if_nontrivial(&mut debug, self.span);
623 debug.finish()
624 }
625 }
626
627 #[derive(Clone)]
628 pub(crate) struct Ident {
629 sym: String,
630 span: Span,
631 raw: bool,
632 }
633
634 impl Ident {
_new(string: &str, raw: bool, span: Span) -> Ident635 fn _new(string: &str, raw: bool, span: Span) -> Ident {
636 validate_ident(string);
637
638 Ident {
639 sym: string.to_owned(),
640 span,
641 raw,
642 }
643 }
644
new(string: &str, span: Span) -> Ident645 pub fn new(string: &str, span: Span) -> Ident {
646 Ident::_new(string, false, span)
647 }
648
new_raw(string: &str, span: Span) -> Ident649 pub fn new_raw(string: &str, span: Span) -> Ident {
650 Ident::_new(string, true, span)
651 }
652
span(&self) -> Span653 pub fn span(&self) -> Span {
654 self.span
655 }
656
set_span(&mut self, span: Span)657 pub fn set_span(&mut self, span: Span) {
658 self.span = span;
659 }
660 }
661
is_ident_start(c: char) -> bool662 pub(crate) fn is_ident_start(c: char) -> bool {
663 ('a' <= c && c <= 'z')
664 || ('A' <= c && c <= 'Z')
665 || c == '_'
666 || (c > '\x7f' && UnicodeXID::is_xid_start(c))
667 }
668
is_ident_continue(c: char) -> bool669 pub(crate) fn is_ident_continue(c: char) -> bool {
670 ('a' <= c && c <= 'z')
671 || ('A' <= c && c <= 'Z')
672 || c == '_'
673 || ('0' <= c && c <= '9')
674 || (c > '\x7f' && UnicodeXID::is_xid_continue(c))
675 }
676
validate_ident(string: &str)677 fn validate_ident(string: &str) {
678 let validate = string;
679 if validate.is_empty() {
680 panic!("Ident is not allowed to be empty; use Option<Ident>");
681 }
682
683 if validate.bytes().all(|digit| digit >= b'0' && digit <= b'9') {
684 panic!("Ident cannot be a number; use Literal instead");
685 }
686
687 fn ident_ok(string: &str) -> bool {
688 let mut chars = string.chars();
689 let first = chars.next().unwrap();
690 if !is_ident_start(first) {
691 return false;
692 }
693 for ch in chars {
694 if !is_ident_continue(ch) {
695 return false;
696 }
697 }
698 true
699 }
700
701 if !ident_ok(validate) {
702 panic!("{:?} is not a valid Ident", string);
703 }
704 }
705
706 impl PartialEq for Ident {
eq(&self, other: &Ident) -> bool707 fn eq(&self, other: &Ident) -> bool {
708 self.sym == other.sym && self.raw == other.raw
709 }
710 }
711
712 impl<T> PartialEq<T> for Ident
713 where
714 T: ?Sized + AsRef<str>,
715 {
eq(&self, other: &T) -> bool716 fn eq(&self, other: &T) -> bool {
717 let other = other.as_ref();
718 if self.raw {
719 other.starts_with("r#") && self.sym == other[2..]
720 } else {
721 self.sym == other
722 }
723 }
724 }
725
726 impl Display for Ident {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result727 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
728 if self.raw {
729 f.write_str("r#")?;
730 }
731 Display::fmt(&self.sym, f)
732 }
733 }
734
735 impl Debug for Ident {
736 // Ident(proc_macro), Ident(r#union)
737 #[cfg(not(span_locations))]
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result738 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
739 let mut debug = f.debug_tuple("Ident");
740 debug.field(&format_args!("{}", self));
741 debug.finish()
742 }
743
744 // Ident {
745 // sym: proc_macro,
746 // span: bytes(128..138)
747 // }
748 #[cfg(span_locations)]
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result749 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
750 let mut debug = f.debug_struct("Ident");
751 debug.field("sym", &format_args!("{}", self));
752 debug_span_field_if_nontrivial(&mut debug, self.span);
753 debug.finish()
754 }
755 }
756
757 #[derive(Clone)]
758 pub(crate) struct Literal {
759 text: String,
760 span: Span,
761 }
762
763 macro_rules! suffixed_numbers {
764 ($($name:ident => $kind:ident,)*) => ($(
765 pub fn $name(n: $kind) -> Literal {
766 Literal::_new(format!(concat!("{}", stringify!($kind)), n))
767 }
768 )*)
769 }
770
771 macro_rules! unsuffixed_numbers {
772 ($($name:ident => $kind:ident,)*) => ($(
773 pub fn $name(n: $kind) -> Literal {
774 Literal::_new(n.to_string())
775 }
776 )*)
777 }
778
779 impl Literal {
_new(text: String) -> Literal780 pub(crate) fn _new(text: String) -> Literal {
781 Literal {
782 text,
783 span: Span::call_site(),
784 }
785 }
786
787 suffixed_numbers! {
788 u8_suffixed => u8,
789 u16_suffixed => u16,
790 u32_suffixed => u32,
791 u64_suffixed => u64,
792 u128_suffixed => u128,
793 usize_suffixed => usize,
794 i8_suffixed => i8,
795 i16_suffixed => i16,
796 i32_suffixed => i32,
797 i64_suffixed => i64,
798 i128_suffixed => i128,
799 isize_suffixed => isize,
800
801 f32_suffixed => f32,
802 f64_suffixed => f64,
803 }
804
805 unsuffixed_numbers! {
806 u8_unsuffixed => u8,
807 u16_unsuffixed => u16,
808 u32_unsuffixed => u32,
809 u64_unsuffixed => u64,
810 u128_unsuffixed => u128,
811 usize_unsuffixed => usize,
812 i8_unsuffixed => i8,
813 i16_unsuffixed => i16,
814 i32_unsuffixed => i32,
815 i64_unsuffixed => i64,
816 i128_unsuffixed => i128,
817 isize_unsuffixed => isize,
818 }
819
f32_unsuffixed(f: f32) -> Literal820 pub fn f32_unsuffixed(f: f32) -> Literal {
821 let mut s = f.to_string();
822 if !s.contains('.') {
823 s.push_str(".0");
824 }
825 Literal::_new(s)
826 }
827
f64_unsuffixed(f: f64) -> Literal828 pub fn f64_unsuffixed(f: f64) -> Literal {
829 let mut s = f.to_string();
830 if !s.contains('.') {
831 s.push_str(".0");
832 }
833 Literal::_new(s)
834 }
835
string(t: &str) -> Literal836 pub fn string(t: &str) -> Literal {
837 let mut text = String::with_capacity(t.len() + 2);
838 text.push('"');
839 for c in t.chars() {
840 if c == '\'' {
841 // escape_debug turns this into "\'" which is unnecessary.
842 text.push(c);
843 } else {
844 text.extend(c.escape_debug());
845 }
846 }
847 text.push('"');
848 Literal::_new(text)
849 }
850
character(t: char) -> Literal851 pub fn character(t: char) -> Literal {
852 let mut text = String::new();
853 text.push('\'');
854 if t == '"' {
855 // escape_debug turns this into '\"' which is unnecessary.
856 text.push(t);
857 } else {
858 text.extend(t.escape_debug());
859 }
860 text.push('\'');
861 Literal::_new(text)
862 }
863
byte_string(bytes: &[u8]) -> Literal864 pub fn byte_string(bytes: &[u8]) -> Literal {
865 let mut escaped = "b\"".to_string();
866 for b in bytes {
867 #[allow(clippy::match_overlapping_arm)]
868 match *b {
869 b'\0' => escaped.push_str(r"\0"),
870 b'\t' => escaped.push_str(r"\t"),
871 b'\n' => escaped.push_str(r"\n"),
872 b'\r' => escaped.push_str(r"\r"),
873 b'"' => escaped.push_str("\\\""),
874 b'\\' => escaped.push_str("\\\\"),
875 b'\x20'..=b'\x7E' => escaped.push(*b as char),
876 _ => escaped.push_str(&format!("\\x{:02X}", b)),
877 }
878 }
879 escaped.push('"');
880 Literal::_new(escaped)
881 }
882
span(&self) -> Span883 pub fn span(&self) -> Span {
884 self.span
885 }
886
set_span(&mut self, span: Span)887 pub fn set_span(&mut self, span: Span) {
888 self.span = span;
889 }
890
subspan<R: RangeBounds<usize>>(&self, _range: R) -> Option<Span>891 pub fn subspan<R: RangeBounds<usize>>(&self, _range: R) -> Option<Span> {
892 None
893 }
894 }
895
896 impl FromStr for Literal {
897 type Err = LexError;
898
from_str(repr: &str) -> Result<Self, Self::Err>899 fn from_str(repr: &str) -> Result<Self, Self::Err> {
900 let cursor = get_cursor(repr);
901 if let Ok((_rest, literal)) = parse::literal(cursor) {
902 if literal.text.len() == repr.len() {
903 return Ok(literal);
904 }
905 }
906 Err(LexError::call_site())
907 }
908 }
909
910 impl Display for Literal {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result911 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
912 Display::fmt(&self.text, f)
913 }
914 }
915
916 impl Debug for Literal {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result917 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
918 let mut debug = fmt.debug_struct("Literal");
919 debug.field("lit", &format_args!("{}", self.text));
920 debug_span_field_if_nontrivial(&mut debug, self.span);
921 debug.finish()
922 }
923 }
924