1 use crate::strnom::{block_comment, skip_whitespace, whitespace, word_break, Cursor, PResult};
2 use crate::{Delimiter, Punct, Spacing, TokenTree};
3 #[cfg(span_locations)]
4 use std::cell::RefCell;
5 #[cfg(span_locations)]
6 use std::cmp;
7 use std::fmt;
8 use std::iter;
9 use std::ops::RangeBounds;
10 #[cfg(procmacro2_semver_exempt)]
11 use std::path::Path;
12 use std::path::PathBuf;
13 use std::str::FromStr;
14 use std::vec;
15 use unicode_xid::UnicodeXID;
16 
17 /// Force use of proc-macro2's fallback implementation of the API for now, even
18 /// if the compiler's implementation is available.
19 #[cfg(wrap_proc_macro)]
force()20 pub fn force() {
21     crate::detection::force_fallback();
22 }
23 
24 /// Resume using the compiler's implementation of the proc macro API if it is
25 /// available.
26 #[cfg(wrap_proc_macro)]
unforce()27 pub fn unforce() {
28     crate::detection::unforce_fallback();
29 }
30 
31 #[derive(Clone)]
32 pub(crate) struct TokenStream {
33     inner: Vec<TokenTree>,
34 }
35 
36 #[derive(Debug)]
37 pub(crate) struct LexError;
38 
39 impl TokenStream {
new() -> TokenStream40     pub fn new() -> TokenStream {
41         TokenStream { inner: Vec::new() }
42     }
43 
is_empty(&self) -> bool44     pub fn is_empty(&self) -> bool {
45         self.inner.len() == 0
46     }
47 }
48 
49 #[cfg(span_locations)]
get_cursor(src: &str) -> Cursor50 fn get_cursor(src: &str) -> Cursor {
51     // Create a dummy file & add it to the source map
52     SOURCE_MAP.with(|cm| {
53         let mut cm = cm.borrow_mut();
54         let name = format!("<parsed string {}>", cm.files.len());
55         let span = cm.add_file(&name, src);
56         Cursor {
57             rest: src,
58             off: span.lo,
59         }
60     })
61 }
62 
63 #[cfg(not(span_locations))]
get_cursor(src: &str) -> Cursor64 fn get_cursor(src: &str) -> Cursor {
65     Cursor { rest: src }
66 }
67 
68 impl FromStr for TokenStream {
69     type Err = LexError;
70 
from_str(src: &str) -> Result<TokenStream, LexError>71     fn from_str(src: &str) -> Result<TokenStream, LexError> {
72         // Create a dummy file & add it to the source map
73         let cursor = get_cursor(src);
74 
75         match token_stream(cursor) {
76             Ok((input, output)) => {
77                 if skip_whitespace(input).len() != 0 {
78                     Err(LexError)
79                 } else {
80                     Ok(output)
81                 }
82             }
83             Err(LexError) => Err(LexError),
84         }
85     }
86 }
87 
88 impl fmt::Display for TokenStream {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result89     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
90         let mut joint = false;
91         for (i, tt) in self.inner.iter().enumerate() {
92             if i != 0 && !joint {
93                 write!(f, " ")?;
94             }
95             joint = false;
96             match *tt {
97                 TokenTree::Group(ref tt) => {
98                     let (start, end) = match tt.delimiter() {
99                         Delimiter::Parenthesis => ("(", ")"),
100                         Delimiter::Brace => ("{", "}"),
101                         Delimiter::Bracket => ("[", "]"),
102                         Delimiter::None => ("", ""),
103                     };
104                     if tt.stream().into_iter().next().is_none() {
105                         write!(f, "{} {}", start, end)?
106                     } else {
107                         write!(f, "{} {} {}", start, tt.stream(), end)?
108                     }
109                 }
110                 TokenTree::Ident(ref tt) => write!(f, "{}", tt)?,
111                 TokenTree::Punct(ref tt) => {
112                     write!(f, "{}", tt.as_char())?;
113                     match tt.spacing() {
114                         Spacing::Alone => {}
115                         Spacing::Joint => joint = true,
116                     }
117                 }
118                 TokenTree::Literal(ref tt) => write!(f, "{}", tt)?,
119             }
120         }
121 
122         Ok(())
123     }
124 }
125 
126 impl fmt::Debug for TokenStream {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result127     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
128         f.write_str("TokenStream ")?;
129         f.debug_list().entries(self.clone()).finish()
130     }
131 }
132 
133 #[cfg(use_proc_macro)]
134 impl From<proc_macro::TokenStream> for TokenStream {
from(inner: proc_macro::TokenStream) -> TokenStream135     fn from(inner: proc_macro::TokenStream) -> TokenStream {
136         inner
137             .to_string()
138             .parse()
139             .expect("compiler token stream parse failed")
140     }
141 }
142 
143 #[cfg(use_proc_macro)]
144 impl From<TokenStream> for proc_macro::TokenStream {
from(inner: TokenStream) -> proc_macro::TokenStream145     fn from(inner: TokenStream) -> proc_macro::TokenStream {
146         inner
147             .to_string()
148             .parse()
149             .expect("failed to parse to compiler tokens")
150     }
151 }
152 
153 impl From<TokenTree> for TokenStream {
from(tree: TokenTree) -> TokenStream154     fn from(tree: TokenTree) -> TokenStream {
155         TokenStream { inner: vec![tree] }
156     }
157 }
158 
159 impl iter::FromIterator<TokenTree> for TokenStream {
from_iter<I: IntoIterator<Item = TokenTree>>(streams: I) -> Self160     fn from_iter<I: IntoIterator<Item = TokenTree>>(streams: I) -> Self {
161         let mut v = Vec::new();
162 
163         for token in streams.into_iter() {
164             v.push(token);
165         }
166 
167         TokenStream { inner: v }
168     }
169 }
170 
171 impl iter::FromIterator<TokenStream> for TokenStream {
from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self172     fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self {
173         let mut v = Vec::new();
174 
175         for stream in streams.into_iter() {
176             v.extend(stream.inner);
177         }
178 
179         TokenStream { inner: v }
180     }
181 }
182 
183 impl Extend<TokenTree> for TokenStream {
extend<I: IntoIterator<Item = TokenTree>>(&mut self, streams: I)184     fn extend<I: IntoIterator<Item = TokenTree>>(&mut self, streams: I) {
185         self.inner.extend(streams);
186     }
187 }
188 
189 impl Extend<TokenStream> for TokenStream {
extend<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I)190     fn extend<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I) {
191         self.inner
192             .extend(streams.into_iter().flat_map(|stream| stream));
193     }
194 }
195 
196 pub(crate) type TokenTreeIter = vec::IntoIter<TokenTree>;
197 
198 impl IntoIterator for TokenStream {
199     type Item = TokenTree;
200     type IntoIter = TokenTreeIter;
201 
into_iter(self) -> TokenTreeIter202     fn into_iter(self) -> TokenTreeIter {
203         self.inner.into_iter()
204     }
205 }
206 
207 #[derive(Clone, PartialEq, Eq)]
208 pub(crate) struct SourceFile {
209     path: PathBuf,
210 }
211 
212 impl SourceFile {
213     /// Get the path to this source file as a string.
path(&self) -> PathBuf214     pub fn path(&self) -> PathBuf {
215         self.path.clone()
216     }
217 
is_real(&self) -> bool218     pub fn is_real(&self) -> bool {
219         // XXX(nika): Support real files in the future?
220         false
221     }
222 }
223 
224 impl fmt::Debug for SourceFile {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result225     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
226         f.debug_struct("SourceFile")
227             .field("path", &self.path())
228             .field("is_real", &self.is_real())
229             .finish()
230     }
231 }
232 
233 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
234 pub(crate) struct LineColumn {
235     pub line: usize,
236     pub column: usize,
237 }
238 
239 #[cfg(span_locations)]
240 thread_local! {
241     static SOURCE_MAP: RefCell<SourceMap> = RefCell::new(SourceMap {
242         // NOTE: We start with a single dummy file which all call_site() and
243         // def_site() spans reference.
244         files: vec![{
245             #[cfg(procmacro2_semver_exempt)]
246             {
247                 FileInfo {
248                     name: "<unspecified>".to_owned(),
249                     span: Span { lo: 0, hi: 0 },
250                     lines: vec![0],
251                 }
252             }
253 
254             #[cfg(not(procmacro2_semver_exempt))]
255             {
256                 FileInfo {
257                     span: Span { lo: 0, hi: 0 },
258                     lines: vec![0],
259                 }
260             }
261         }],
262     });
263 }
264 
265 #[cfg(span_locations)]
266 struct FileInfo {
267     #[cfg(procmacro2_semver_exempt)]
268     name: String,
269     span: Span,
270     lines: Vec<usize>,
271 }
272 
273 #[cfg(span_locations)]
274 impl FileInfo {
offset_line_column(&self, offset: usize) -> LineColumn275     fn offset_line_column(&self, offset: usize) -> LineColumn {
276         assert!(self.span_within(Span {
277             lo: offset as u32,
278             hi: offset as u32
279         }));
280         let offset = offset - self.span.lo as usize;
281         match self.lines.binary_search(&offset) {
282             Ok(found) => LineColumn {
283                 line: found + 1,
284                 column: 0,
285             },
286             Err(idx) => LineColumn {
287                 line: idx,
288                 column: offset - self.lines[idx - 1],
289             },
290         }
291     }
292 
span_within(&self, span: Span) -> bool293     fn span_within(&self, span: Span) -> bool {
294         span.lo >= self.span.lo && span.hi <= self.span.hi
295     }
296 }
297 
298 /// Computesthe offsets of each line in the given source string.
299 #[cfg(span_locations)]
lines_offsets(s: &str) -> Vec<usize>300 fn lines_offsets(s: &str) -> Vec<usize> {
301     let mut lines = vec![0];
302     let mut prev = 0;
303     while let Some(len) = s[prev..].find('\n') {
304         prev += len + 1;
305         lines.push(prev);
306     }
307     lines
308 }
309 
310 #[cfg(span_locations)]
311 struct SourceMap {
312     files: Vec<FileInfo>,
313 }
314 
315 #[cfg(span_locations)]
316 impl SourceMap {
next_start_pos(&self) -> u32317     fn next_start_pos(&self) -> u32 {
318         // Add 1 so there's always space between files.
319         //
320         // We'll always have at least 1 file, as we initialize our files list
321         // with a dummy file.
322         self.files.last().unwrap().span.hi + 1
323     }
324 
add_file(&mut self, name: &str, src: &str) -> Span325     fn add_file(&mut self, name: &str, src: &str) -> Span {
326         let lines = lines_offsets(src);
327         let lo = self.next_start_pos();
328         // XXX(nika): Shouild we bother doing a checked cast or checked add here?
329         let span = Span {
330             lo,
331             hi: lo + (src.len() as u32),
332         };
333 
334         #[cfg(procmacro2_semver_exempt)]
335         self.files.push(FileInfo {
336             name: name.to_owned(),
337             span,
338             lines,
339         });
340 
341         #[cfg(not(procmacro2_semver_exempt))]
342         self.files.push(FileInfo { span, lines });
343         let _ = name;
344 
345         span
346     }
347 
fileinfo(&self, span: Span) -> &FileInfo348     fn fileinfo(&self, span: Span) -> &FileInfo {
349         for file in &self.files {
350             if file.span_within(span) {
351                 return file;
352             }
353         }
354         panic!("Invalid span with no related FileInfo!");
355     }
356 }
357 
358 #[derive(Clone, Copy, PartialEq, Eq)]
359 pub(crate) struct Span {
360     #[cfg(span_locations)]
361     lo: u32,
362     #[cfg(span_locations)]
363     hi: u32,
364 }
365 
366 impl Span {
367     #[cfg(not(span_locations))]
call_site() -> Span368     pub fn call_site() -> Span {
369         Span {}
370     }
371 
372     #[cfg(span_locations)]
call_site() -> Span373     pub fn call_site() -> Span {
374         Span { lo: 0, hi: 0 }
375     }
376 
377     #[cfg(procmacro2_semver_exempt)]
def_site() -> Span378     pub fn def_site() -> Span {
379         Span::call_site()
380     }
381 
382     #[cfg(procmacro2_semver_exempt)]
resolved_at(&self, _other: Span) -> Span383     pub fn resolved_at(&self, _other: Span) -> Span {
384         // Stable spans consist only of line/column information, so
385         // `resolved_at` and `located_at` only select which span the
386         // caller wants line/column information from.
387         *self
388     }
389 
390     #[cfg(procmacro2_semver_exempt)]
located_at(&self, other: Span) -> Span391     pub fn located_at(&self, other: Span) -> Span {
392         other
393     }
394 
395     #[cfg(procmacro2_semver_exempt)]
source_file(&self) -> SourceFile396     pub fn source_file(&self) -> SourceFile {
397         SOURCE_MAP.with(|cm| {
398             let cm = cm.borrow();
399             let fi = cm.fileinfo(*self);
400             SourceFile {
401                 path: Path::new(&fi.name).to_owned(),
402             }
403         })
404     }
405 
406     #[cfg(span_locations)]
start(&self) -> LineColumn407     pub fn start(&self) -> LineColumn {
408         SOURCE_MAP.with(|cm| {
409             let cm = cm.borrow();
410             let fi = cm.fileinfo(*self);
411             fi.offset_line_column(self.lo as usize)
412         })
413     }
414 
415     #[cfg(span_locations)]
end(&self) -> LineColumn416     pub fn end(&self) -> LineColumn {
417         SOURCE_MAP.with(|cm| {
418             let cm = cm.borrow();
419             let fi = cm.fileinfo(*self);
420             fi.offset_line_column(self.hi as usize)
421         })
422     }
423 
424     #[cfg(not(span_locations))]
join(&self, _other: Span) -> Option<Span>425     pub fn join(&self, _other: Span) -> Option<Span> {
426         Some(Span {})
427     }
428 
429     #[cfg(span_locations)]
join(&self, other: Span) -> Option<Span>430     pub fn join(&self, other: Span) -> Option<Span> {
431         SOURCE_MAP.with(|cm| {
432             let cm = cm.borrow();
433             // If `other` is not within the same FileInfo as us, return None.
434             if !cm.fileinfo(*self).span_within(other) {
435                 return None;
436             }
437             Some(Span {
438                 lo: cmp::min(self.lo, other.lo),
439                 hi: cmp::max(self.hi, other.hi),
440             })
441         })
442     }
443 
444     #[cfg(not(span_locations))]
first_byte(self) -> Self445     fn first_byte(self) -> Self {
446         self
447     }
448 
449     #[cfg(span_locations)]
first_byte(self) -> Self450     fn first_byte(self) -> Self {
451         Span {
452             lo: self.lo,
453             hi: cmp::min(self.lo.saturating_add(1), self.hi),
454         }
455     }
456 
457     #[cfg(not(span_locations))]
last_byte(self) -> Self458     fn last_byte(self) -> Self {
459         self
460     }
461 
462     #[cfg(span_locations)]
last_byte(self) -> Self463     fn last_byte(self) -> Self {
464         Span {
465             lo: cmp::max(self.hi.saturating_sub(1), self.lo),
466             hi: self.hi,
467         }
468     }
469 }
470 
471 impl fmt::Debug for Span {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result472     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
473         #[cfg(procmacro2_semver_exempt)]
474         return write!(f, "bytes({}..{})", self.lo, self.hi);
475 
476         #[cfg(not(procmacro2_semver_exempt))]
477         write!(f, "Span")
478     }
479 }
480 
debug_span_field_if_nontrivial(debug: &mut fmt::DebugStruct, span: Span)481 pub(crate) fn debug_span_field_if_nontrivial(debug: &mut fmt::DebugStruct, span: Span) {
482     if cfg!(procmacro2_semver_exempt) {
483         debug.field("span", &span);
484     }
485 }
486 
487 #[derive(Clone)]
488 pub(crate) struct Group {
489     delimiter: Delimiter,
490     stream: TokenStream,
491     span: Span,
492 }
493 
494 impl Group {
new(delimiter: Delimiter, stream: TokenStream) -> Group495     pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group {
496         Group {
497             delimiter,
498             stream,
499             span: Span::call_site(),
500         }
501     }
502 
delimiter(&self) -> Delimiter503     pub fn delimiter(&self) -> Delimiter {
504         self.delimiter
505     }
506 
stream(&self) -> TokenStream507     pub fn stream(&self) -> TokenStream {
508         self.stream.clone()
509     }
510 
span(&self) -> Span511     pub fn span(&self) -> Span {
512         self.span
513     }
514 
span_open(&self) -> Span515     pub fn span_open(&self) -> Span {
516         self.span.first_byte()
517     }
518 
span_close(&self) -> Span519     pub fn span_close(&self) -> Span {
520         self.span.last_byte()
521     }
522 
set_span(&mut self, span: Span)523     pub fn set_span(&mut self, span: Span) {
524         self.span = span;
525     }
526 }
527 
528 impl fmt::Display for Group {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result529     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
530         let (left, right) = match self.delimiter {
531             Delimiter::Parenthesis => ("(", ")"),
532             Delimiter::Brace => ("{", "}"),
533             Delimiter::Bracket => ("[", "]"),
534             Delimiter::None => ("", ""),
535         };
536 
537         f.write_str(left)?;
538         self.stream.fmt(f)?;
539         f.write_str(right)?;
540 
541         Ok(())
542     }
543 }
544 
545 impl fmt::Debug for Group {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result546     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
547         let mut debug = fmt.debug_struct("Group");
548         debug.field("delimiter", &self.delimiter);
549         debug.field("stream", &self.stream);
550         #[cfg(procmacro2_semver_exempt)]
551         debug.field("span", &self.span);
552         debug.finish()
553     }
554 }
555 
556 #[derive(Clone)]
557 pub(crate) struct Ident {
558     sym: String,
559     span: Span,
560     raw: bool,
561 }
562 
563 impl Ident {
_new(string: &str, raw: bool, span: Span) -> Ident564     fn _new(string: &str, raw: bool, span: Span) -> Ident {
565         validate_ident(string);
566 
567         Ident {
568             sym: string.to_owned(),
569             span,
570             raw,
571         }
572     }
573 
new(string: &str, span: Span) -> Ident574     pub fn new(string: &str, span: Span) -> Ident {
575         Ident::_new(string, false, span)
576     }
577 
new_raw(string: &str, span: Span) -> Ident578     pub fn new_raw(string: &str, span: Span) -> Ident {
579         Ident::_new(string, true, span)
580     }
581 
span(&self) -> Span582     pub fn span(&self) -> Span {
583         self.span
584     }
585 
set_span(&mut self, span: Span)586     pub fn set_span(&mut self, span: Span) {
587         self.span = span;
588     }
589 }
590 
is_ident_start(c: char) -> bool591 fn is_ident_start(c: char) -> bool {
592     ('a' <= c && c <= 'z')
593         || ('A' <= c && c <= 'Z')
594         || c == '_'
595         || (c > '\x7f' && UnicodeXID::is_xid_start(c))
596 }
597 
is_ident_continue(c: char) -> bool598 fn is_ident_continue(c: char) -> bool {
599     ('a' <= c && c <= 'z')
600         || ('A' <= c && c <= 'Z')
601         || c == '_'
602         || ('0' <= c && c <= '9')
603         || (c > '\x7f' && UnicodeXID::is_xid_continue(c))
604 }
605 
validate_ident(string: &str)606 fn validate_ident(string: &str) {
607     let validate = string;
608     if validate.is_empty() {
609         panic!("Ident is not allowed to be empty; use Option<Ident>");
610     }
611 
612     if validate.bytes().all(|digit| digit >= b'0' && digit <= b'9') {
613         panic!("Ident cannot be a number; use Literal instead");
614     }
615 
616     fn ident_ok(string: &str) -> bool {
617         let mut chars = string.chars();
618         let first = chars.next().unwrap();
619         if !is_ident_start(first) {
620             return false;
621         }
622         for ch in chars {
623             if !is_ident_continue(ch) {
624                 return false;
625             }
626         }
627         true
628     }
629 
630     if !ident_ok(validate) {
631         panic!("{:?} is not a valid Ident", string);
632     }
633 }
634 
635 impl PartialEq for Ident {
eq(&self, other: &Ident) -> bool636     fn eq(&self, other: &Ident) -> bool {
637         self.sym == other.sym && self.raw == other.raw
638     }
639 }
640 
641 impl<T> PartialEq<T> for Ident
642 where
643     T: ?Sized + AsRef<str>,
644 {
eq(&self, other: &T) -> bool645     fn eq(&self, other: &T) -> bool {
646         let other = other.as_ref();
647         if self.raw {
648             other.starts_with("r#") && self.sym == other[2..]
649         } else {
650             self.sym == other
651         }
652     }
653 }
654 
655 impl fmt::Display for Ident {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result656     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
657         if self.raw {
658             "r#".fmt(f)?;
659         }
660         self.sym.fmt(f)
661     }
662 }
663 
664 impl fmt::Debug for Ident {
665     // Ident(proc_macro), Ident(r#union)
666     #[cfg(not(procmacro2_semver_exempt))]
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result667     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
668         let mut debug = f.debug_tuple("Ident");
669         debug.field(&format_args!("{}", self));
670         debug.finish()
671     }
672 
673     // Ident {
674     //     sym: proc_macro,
675     //     span: bytes(128..138)
676     // }
677     #[cfg(procmacro2_semver_exempt)]
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result678     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
679         let mut debug = f.debug_struct("Ident");
680         debug.field("sym", &format_args!("{}", self));
681         debug.field("span", &self.span);
682         debug.finish()
683     }
684 }
685 
686 #[derive(Clone)]
687 pub(crate) struct Literal {
688     text: String,
689     span: Span,
690 }
691 
692 macro_rules! suffixed_numbers {
693     ($($name:ident => $kind:ident,)*) => ($(
694         pub fn $name(n: $kind) -> Literal {
695             Literal::_new(format!(concat!("{}", stringify!($kind)), n))
696         }
697     )*)
698 }
699 
700 macro_rules! unsuffixed_numbers {
701     ($($name:ident => $kind:ident,)*) => ($(
702         pub fn $name(n: $kind) -> Literal {
703             Literal::_new(n.to_string())
704         }
705     )*)
706 }
707 
708 impl Literal {
_new(text: String) -> Literal709     fn _new(text: String) -> Literal {
710         Literal {
711             text,
712             span: Span::call_site(),
713         }
714     }
715 
716     suffixed_numbers! {
717         u8_suffixed => u8,
718         u16_suffixed => u16,
719         u32_suffixed => u32,
720         u64_suffixed => u64,
721         u128_suffixed => u128,
722         usize_suffixed => usize,
723         i8_suffixed => i8,
724         i16_suffixed => i16,
725         i32_suffixed => i32,
726         i64_suffixed => i64,
727         i128_suffixed => i128,
728         isize_suffixed => isize,
729 
730         f32_suffixed => f32,
731         f64_suffixed => f64,
732     }
733 
734     unsuffixed_numbers! {
735         u8_unsuffixed => u8,
736         u16_unsuffixed => u16,
737         u32_unsuffixed => u32,
738         u64_unsuffixed => u64,
739         u128_unsuffixed => u128,
740         usize_unsuffixed => usize,
741         i8_unsuffixed => i8,
742         i16_unsuffixed => i16,
743         i32_unsuffixed => i32,
744         i64_unsuffixed => i64,
745         i128_unsuffixed => i128,
746         isize_unsuffixed => isize,
747     }
748 
f32_unsuffixed(f: f32) -> Literal749     pub fn f32_unsuffixed(f: f32) -> Literal {
750         let mut s = f.to_string();
751         if !s.contains(".") {
752             s.push_str(".0");
753         }
754         Literal::_new(s)
755     }
756 
f64_unsuffixed(f: f64) -> Literal757     pub fn f64_unsuffixed(f: f64) -> Literal {
758         let mut s = f.to_string();
759         if !s.contains(".") {
760             s.push_str(".0");
761         }
762         Literal::_new(s)
763     }
764 
string(t: &str) -> Literal765     pub fn string(t: &str) -> Literal {
766         let mut text = String::with_capacity(t.len() + 2);
767         text.push('"');
768         for c in t.chars() {
769             if c == '\'' {
770                 // escape_debug turns this into "\'" which is unnecessary.
771                 text.push(c);
772             } else {
773                 text.extend(c.escape_debug());
774             }
775         }
776         text.push('"');
777         Literal::_new(text)
778     }
779 
character(t: char) -> Literal780     pub fn character(t: char) -> Literal {
781         let mut text = String::new();
782         text.push('\'');
783         if t == '"' {
784             // escape_debug turns this into '\"' which is unnecessary.
785             text.push(t);
786         } else {
787             text.extend(t.escape_debug());
788         }
789         text.push('\'');
790         Literal::_new(text)
791     }
792 
byte_string(bytes: &[u8]) -> Literal793     pub fn byte_string(bytes: &[u8]) -> Literal {
794         let mut escaped = "b\"".to_string();
795         for b in bytes {
796             match *b {
797                 b'\0' => escaped.push_str(r"\0"),
798                 b'\t' => escaped.push_str(r"\t"),
799                 b'\n' => escaped.push_str(r"\n"),
800                 b'\r' => escaped.push_str(r"\r"),
801                 b'"' => escaped.push_str("\\\""),
802                 b'\\' => escaped.push_str("\\\\"),
803                 b'\x20'..=b'\x7E' => escaped.push(*b as char),
804                 _ => escaped.push_str(&format!("\\x{:02X}", b)),
805             }
806         }
807         escaped.push('"');
808         Literal::_new(escaped)
809     }
810 
span(&self) -> Span811     pub fn span(&self) -> Span {
812         self.span
813     }
814 
set_span(&mut self, span: Span)815     pub fn set_span(&mut self, span: Span) {
816         self.span = span;
817     }
818 
subspan<R: RangeBounds<usize>>(&self, _range: R) -> Option<Span>819     pub fn subspan<R: RangeBounds<usize>>(&self, _range: R) -> Option<Span> {
820         None
821     }
822 }
823 
824 impl fmt::Display for Literal {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result825     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
826         self.text.fmt(f)
827     }
828 }
829 
830 impl fmt::Debug for Literal {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result831     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
832         let mut debug = fmt.debug_struct("Literal");
833         debug.field("lit", &format_args!("{}", self.text));
834         #[cfg(procmacro2_semver_exempt)]
835         debug.field("span", &self.span);
836         debug.finish()
837     }
838 }
839 
token_stream(mut input: Cursor) -> PResult<TokenStream>840 fn token_stream(mut input: Cursor) -> PResult<TokenStream> {
841     let mut trees = Vec::new();
842     loop {
843         let input_no_ws = skip_whitespace(input);
844         if input_no_ws.rest.len() == 0 {
845             break;
846         }
847         if let Ok((a, tokens)) = doc_comment(input_no_ws) {
848             input = a;
849             trees.extend(tokens);
850             continue;
851         }
852 
853         let (a, tt) = match token_tree(input_no_ws) {
854             Ok(p) => p,
855             Err(_) => break,
856         };
857         trees.push(tt);
858         input = a;
859     }
860     Ok((input, TokenStream { inner: trees }))
861 }
862 
863 #[cfg(not(span_locations))]
spanned<'a, T>( input: Cursor<'a>, f: fn(Cursor<'a>) -> PResult<'a, T>, ) -> PResult<'a, (T, crate::Span)>864 fn spanned<'a, T>(
865     input: Cursor<'a>,
866     f: fn(Cursor<'a>) -> PResult<'a, T>,
867 ) -> PResult<'a, (T, crate::Span)> {
868     let (a, b) = f(skip_whitespace(input))?;
869     Ok((a, ((b, crate::Span::_new_stable(Span::call_site())))))
870 }
871 
872 #[cfg(span_locations)]
spanned<'a, T>( input: Cursor<'a>, f: fn(Cursor<'a>) -> PResult<'a, T>, ) -> PResult<'a, (T, crate::Span)>873 fn spanned<'a, T>(
874     input: Cursor<'a>,
875     f: fn(Cursor<'a>) -> PResult<'a, T>,
876 ) -> PResult<'a, (T, crate::Span)> {
877     let input = skip_whitespace(input);
878     let lo = input.off;
879     let (a, b) = f(input)?;
880     let hi = a.off;
881     let span = crate::Span::_new_stable(Span { lo, hi });
882     Ok((a, (b, span)))
883 }
884 
token_tree(input: Cursor) -> PResult<TokenTree>885 fn token_tree(input: Cursor) -> PResult<TokenTree> {
886     let (rest, (mut tt, span)) = spanned(input, token_kind)?;
887     tt.set_span(span);
888     Ok((rest, tt))
889 }
890 
891 named!(token_kind -> TokenTree, alt!(
892     map!(group, |g| TokenTree::Group(crate::Group::_new_stable(g)))
893     |
894     map!(literal, |l| TokenTree::Literal(crate::Literal::_new_stable(l))) // must be before symbol
895     |
896     map!(op, TokenTree::Punct)
897     |
898     symbol_leading_ws
899 ));
900 
901 named!(group -> Group, alt!(
902     delimited!(
903         punct!("("),
904         token_stream,
905         punct!(")")
906     ) => { |ts| Group::new(Delimiter::Parenthesis, ts) }
907     |
908     delimited!(
909         punct!("["),
910         token_stream,
911         punct!("]")
912     ) => { |ts| Group::new(Delimiter::Bracket, ts) }
913     |
914     delimited!(
915         punct!("{"),
916         token_stream,
917         punct!("}")
918     ) => { |ts| Group::new(Delimiter::Brace, ts) }
919 ));
920 
symbol_leading_ws(input: Cursor) -> PResult<TokenTree>921 fn symbol_leading_ws(input: Cursor) -> PResult<TokenTree> {
922     symbol(skip_whitespace(input))
923 }
924 
symbol(input: Cursor) -> PResult<TokenTree>925 fn symbol(input: Cursor) -> PResult<TokenTree> {
926     let raw = input.starts_with("r#");
927     let rest = input.advance((raw as usize) << 1);
928 
929     let (rest, sym) = symbol_not_raw(rest)?;
930 
931     if !raw {
932         let ident = crate::Ident::new(sym, crate::Span::call_site());
933         return Ok((rest, ident.into()));
934     }
935 
936     if sym == "_" {
937         return Err(LexError);
938     }
939 
940     let ident = crate::Ident::_new_raw(sym, crate::Span::call_site());
941     Ok((rest, ident.into()))
942 }
943 
symbol_not_raw(input: Cursor) -> PResult<&str>944 fn symbol_not_raw(input: Cursor) -> PResult<&str> {
945     let mut chars = input.char_indices();
946 
947     match chars.next() {
948         Some((_, ch)) if is_ident_start(ch) => {}
949         _ => return Err(LexError),
950     }
951 
952     let mut end = input.len();
953     for (i, ch) in chars {
954         if !is_ident_continue(ch) {
955             end = i;
956             break;
957         }
958     }
959 
960     Ok((input.advance(end), &input.rest[..end]))
961 }
962 
literal(input: Cursor) -> PResult<Literal>963 fn literal(input: Cursor) -> PResult<Literal> {
964     let input_no_ws = skip_whitespace(input);
965 
966     match literal_nocapture(input_no_ws) {
967         Ok((a, ())) => {
968             let start = input.len() - input_no_ws.len();
969             let len = input_no_ws.len() - a.len();
970             let end = start + len;
971             Ok((a, Literal::_new(input.rest[start..end].to_string())))
972         }
973         Err(LexError) => Err(LexError),
974     }
975 }
976 
977 named!(literal_nocapture -> (), alt!(
978     string
979     |
980     byte_string
981     |
982     byte
983     |
984     character
985     |
986     float
987     |
988     int
989 ));
990 
991 named!(string -> (), alt!(
992     quoted_string
993     |
994     preceded!(
995         punct!("r"),
996         raw_string
997     ) => { |_| () }
998 ));
999 
1000 named!(quoted_string -> (), do_parse!(
1001     punct!("\"") >>
1002     cooked_string >>
1003     tag!("\"") >>
1004     option!(symbol_not_raw) >>
1005     (())
1006 ));
1007 
cooked_string(input: Cursor) -> PResult<()>1008 fn cooked_string(input: Cursor) -> PResult<()> {
1009     let mut chars = input.char_indices().peekable();
1010     while let Some((byte_offset, ch)) = chars.next() {
1011         match ch {
1012             '"' => {
1013                 return Ok((input.advance(byte_offset), ()));
1014             }
1015             '\r' => {
1016                 if let Some((_, '\n')) = chars.next() {
1017                     // ...
1018                 } else {
1019                     break;
1020                 }
1021             }
1022             '\\' => match chars.next() {
1023                 Some((_, 'x')) => {
1024                     if !backslash_x_char(&mut chars) {
1025                         break;
1026                     }
1027                 }
1028                 Some((_, 'n')) | Some((_, 'r')) | Some((_, 't')) | Some((_, '\\'))
1029                 | Some((_, '\'')) | Some((_, '"')) | Some((_, '0')) => {}
1030                 Some((_, 'u')) => {
1031                     if !backslash_u(&mut chars) {
1032                         break;
1033                     }
1034                 }
1035                 Some((_, '\n')) | Some((_, '\r')) => {
1036                     while let Some(&(_, ch)) = chars.peek() {
1037                         if ch.is_whitespace() {
1038                             chars.next();
1039                         } else {
1040                             break;
1041                         }
1042                     }
1043                 }
1044                 _ => break,
1045             },
1046             _ch => {}
1047         }
1048     }
1049     Err(LexError)
1050 }
1051 
1052 named!(byte_string -> (), alt!(
1053     delimited!(
1054         punct!("b\""),
1055         cooked_byte_string,
1056         tag!("\"")
1057     ) => { |_| () }
1058     |
1059     preceded!(
1060         punct!("br"),
1061         raw_string
1062     ) => { |_| () }
1063 ));
1064 
cooked_byte_string(mut input: Cursor) -> PResult<()>1065 fn cooked_byte_string(mut input: Cursor) -> PResult<()> {
1066     let mut bytes = input.bytes().enumerate();
1067     'outer: while let Some((offset, b)) = bytes.next() {
1068         match b {
1069             b'"' => {
1070                 return Ok((input.advance(offset), ()));
1071             }
1072             b'\r' => {
1073                 if let Some((_, b'\n')) = bytes.next() {
1074                     // ...
1075                 } else {
1076                     break;
1077                 }
1078             }
1079             b'\\' => match bytes.next() {
1080                 Some((_, b'x')) => {
1081                     if !backslash_x_byte(&mut bytes) {
1082                         break;
1083                     }
1084                 }
1085                 Some((_, b'n')) | Some((_, b'r')) | Some((_, b't')) | Some((_, b'\\'))
1086                 | Some((_, b'0')) | Some((_, b'\'')) | Some((_, b'"')) => {}
1087                 Some((newline, b'\n')) | Some((newline, b'\r')) => {
1088                     let rest = input.advance(newline + 1);
1089                     for (offset, ch) in rest.char_indices() {
1090                         if !ch.is_whitespace() {
1091                             input = rest.advance(offset);
1092                             bytes = input.bytes().enumerate();
1093                             continue 'outer;
1094                         }
1095                     }
1096                     break;
1097                 }
1098                 _ => break,
1099             },
1100             b if b < 0x80 => {}
1101             _ => break,
1102         }
1103     }
1104     Err(LexError)
1105 }
1106 
raw_string(input: Cursor) -> PResult<()>1107 fn raw_string(input: Cursor) -> PResult<()> {
1108     let mut chars = input.char_indices();
1109     let mut n = 0;
1110     while let Some((byte_offset, ch)) = chars.next() {
1111         match ch {
1112             '"' => {
1113                 n = byte_offset;
1114                 break;
1115             }
1116             '#' => {}
1117             _ => return Err(LexError),
1118         }
1119     }
1120     for (byte_offset, ch) in chars {
1121         match ch {
1122             '"' if input.advance(byte_offset + 1).starts_with(&input.rest[..n]) => {
1123                 let rest = input.advance(byte_offset + 1 + n);
1124                 return Ok((rest, ()));
1125             }
1126             '\r' => {}
1127             _ => {}
1128         }
1129     }
1130     Err(LexError)
1131 }
1132 
1133 named!(byte -> (), do_parse!(
1134     punct!("b") >>
1135     tag!("'") >>
1136     cooked_byte >>
1137     tag!("'") >>
1138     (())
1139 ));
1140 
cooked_byte(input: Cursor) -> PResult<()>1141 fn cooked_byte(input: Cursor) -> PResult<()> {
1142     let mut bytes = input.bytes().enumerate();
1143     let ok = match bytes.next().map(|(_, b)| b) {
1144         Some(b'\\') => match bytes.next().map(|(_, b)| b) {
1145             Some(b'x') => backslash_x_byte(&mut bytes),
1146             Some(b'n') | Some(b'r') | Some(b't') | Some(b'\\') | Some(b'0') | Some(b'\'')
1147             | Some(b'"') => true,
1148             _ => false,
1149         },
1150         b => b.is_some(),
1151     };
1152     if ok {
1153         match bytes.next() {
1154             Some((offset, _)) => {
1155                 if input.chars().as_str().is_char_boundary(offset) {
1156                     Ok((input.advance(offset), ()))
1157                 } else {
1158                     Err(LexError)
1159                 }
1160             }
1161             None => Ok((input.advance(input.len()), ())),
1162         }
1163     } else {
1164         Err(LexError)
1165     }
1166 }
1167 
1168 named!(character -> (), do_parse!(
1169     punct!("'") >>
1170     cooked_char >>
1171     tag!("'") >>
1172     (())
1173 ));
1174 
cooked_char(input: Cursor) -> PResult<()>1175 fn cooked_char(input: Cursor) -> PResult<()> {
1176     let mut chars = input.char_indices();
1177     let ok = match chars.next().map(|(_, ch)| ch) {
1178         Some('\\') => match chars.next().map(|(_, ch)| ch) {
1179             Some('x') => backslash_x_char(&mut chars),
1180             Some('u') => backslash_u(&mut chars),
1181             Some('n') | Some('r') | Some('t') | Some('\\') | Some('0') | Some('\'') | Some('"') => {
1182                 true
1183             }
1184             _ => false,
1185         },
1186         ch => ch.is_some(),
1187     };
1188     if ok {
1189         match chars.next() {
1190             Some((idx, _)) => Ok((input.advance(idx), ())),
1191             None => Ok((input.advance(input.len()), ())),
1192         }
1193     } else {
1194         Err(LexError)
1195     }
1196 }
1197 
1198 macro_rules! next_ch {
1199     ($chars:ident @ $pat:pat $(| $rest:pat)*) => {
1200         match $chars.next() {
1201             Some((_, ch)) => match ch {
1202                 $pat $(| $rest)*  => ch,
1203                 _ => return false,
1204             },
1205             None => return false
1206         }
1207     };
1208 }
1209 
backslash_x_char<I>(chars: &mut I) -> bool where I: Iterator<Item = (usize, char)>,1210 fn backslash_x_char<I>(chars: &mut I) -> bool
1211 where
1212     I: Iterator<Item = (usize, char)>,
1213 {
1214     next_ch!(chars @ '0'..='7');
1215     next_ch!(chars @ '0'..='9' | 'a'..='f' | 'A'..='F');
1216     true
1217 }
1218 
backslash_x_byte<I>(chars: &mut I) -> bool where I: Iterator<Item = (usize, u8)>,1219 fn backslash_x_byte<I>(chars: &mut I) -> bool
1220 where
1221     I: Iterator<Item = (usize, u8)>,
1222 {
1223     next_ch!(chars @ b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F');
1224     next_ch!(chars @ b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F');
1225     true
1226 }
1227 
backslash_u<I>(chars: &mut I) -> bool where I: Iterator<Item = (usize, char)>,1228 fn backslash_u<I>(chars: &mut I) -> bool
1229 where
1230     I: Iterator<Item = (usize, char)>,
1231 {
1232     next_ch!(chars @ '{');
1233     next_ch!(chars @ '0'..='9' | 'a'..='f' | 'A'..='F');
1234     loop {
1235         let c = next_ch!(chars @ '0'..='9' | 'a'..='f' | 'A'..='F' | '_' | '}');
1236         if c == '}' {
1237             return true;
1238         }
1239     }
1240 }
1241 
float(input: Cursor) -> PResult<()>1242 fn float(input: Cursor) -> PResult<()> {
1243     let (mut rest, ()) = float_digits(input)?;
1244     if let Some(ch) = rest.chars().next() {
1245         if is_ident_start(ch) {
1246             rest = symbol_not_raw(rest)?.0;
1247         }
1248     }
1249     word_break(rest)
1250 }
1251 
float_digits(input: Cursor) -> PResult<()>1252 fn float_digits(input: Cursor) -> PResult<()> {
1253     let mut chars = input.chars().peekable();
1254     match chars.next() {
1255         Some(ch) if ch >= '0' && ch <= '9' => {}
1256         _ => return Err(LexError),
1257     }
1258 
1259     let mut len = 1;
1260     let mut has_dot = false;
1261     let mut has_exp = false;
1262     while let Some(&ch) = chars.peek() {
1263         match ch {
1264             '0'..='9' | '_' => {
1265                 chars.next();
1266                 len += 1;
1267             }
1268             '.' => {
1269                 if has_dot {
1270                     break;
1271                 }
1272                 chars.next();
1273                 if chars
1274                     .peek()
1275                     .map(|&ch| ch == '.' || is_ident_start(ch))
1276                     .unwrap_or(false)
1277                 {
1278                     return Err(LexError);
1279                 }
1280                 len += 1;
1281                 has_dot = true;
1282             }
1283             'e' | 'E' => {
1284                 chars.next();
1285                 len += 1;
1286                 has_exp = true;
1287                 break;
1288             }
1289             _ => break,
1290         }
1291     }
1292 
1293     let rest = input.advance(len);
1294     if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
1295         return Err(LexError);
1296     }
1297 
1298     if has_exp {
1299         let mut has_exp_value = false;
1300         while let Some(&ch) = chars.peek() {
1301             match ch {
1302                 '+' | '-' => {
1303                     if has_exp_value {
1304                         break;
1305                     }
1306                     chars.next();
1307                     len += 1;
1308                 }
1309                 '0'..='9' => {
1310                     chars.next();
1311                     len += 1;
1312                     has_exp_value = true;
1313                 }
1314                 '_' => {
1315                     chars.next();
1316                     len += 1;
1317                 }
1318                 _ => break,
1319             }
1320         }
1321         if !has_exp_value {
1322             return Err(LexError);
1323         }
1324     }
1325 
1326     Ok((input.advance(len), ()))
1327 }
1328 
int(input: Cursor) -> PResult<()>1329 fn int(input: Cursor) -> PResult<()> {
1330     let (mut rest, ()) = digits(input)?;
1331     if let Some(ch) = rest.chars().next() {
1332         if is_ident_start(ch) {
1333             rest = symbol_not_raw(rest)?.0;
1334         }
1335     }
1336     word_break(rest)
1337 }
1338 
digits(mut input: Cursor) -> PResult<()>1339 fn digits(mut input: Cursor) -> PResult<()> {
1340     let base = if input.starts_with("0x") {
1341         input = input.advance(2);
1342         16
1343     } else if input.starts_with("0o") {
1344         input = input.advance(2);
1345         8
1346     } else if input.starts_with("0b") {
1347         input = input.advance(2);
1348         2
1349     } else {
1350         10
1351     };
1352 
1353     let mut len = 0;
1354     let mut empty = true;
1355     for b in input.bytes() {
1356         let digit = match b {
1357             b'0'..=b'9' => (b - b'0') as u64,
1358             b'a'..=b'f' => 10 + (b - b'a') as u64,
1359             b'A'..=b'F' => 10 + (b - b'A') as u64,
1360             b'_' => {
1361                 if empty && base == 10 {
1362                     return Err(LexError);
1363                 }
1364                 len += 1;
1365                 continue;
1366             }
1367             _ => break,
1368         };
1369         if digit >= base {
1370             return Err(LexError);
1371         }
1372         len += 1;
1373         empty = false;
1374     }
1375     if empty {
1376         Err(LexError)
1377     } else {
1378         Ok((input.advance(len), ()))
1379     }
1380 }
1381 
op(input: Cursor) -> PResult<Punct>1382 fn op(input: Cursor) -> PResult<Punct> {
1383     let input = skip_whitespace(input);
1384     match op_char(input) {
1385         Ok((rest, '\'')) => {
1386             symbol(rest)?;
1387             Ok((rest, Punct::new('\'', Spacing::Joint)))
1388         }
1389         Ok((rest, ch)) => {
1390             let kind = match op_char(rest) {
1391                 Ok(_) => Spacing::Joint,
1392                 Err(LexError) => Spacing::Alone,
1393             };
1394             Ok((rest, Punct::new(ch, kind)))
1395         }
1396         Err(LexError) => Err(LexError),
1397     }
1398 }
1399 
op_char(input: Cursor) -> PResult<char>1400 fn op_char(input: Cursor) -> PResult<char> {
1401     if input.starts_with("//") || input.starts_with("/*") {
1402         // Do not accept `/` of a comment as an op.
1403         return Err(LexError);
1404     }
1405 
1406     let mut chars = input.chars();
1407     let first = match chars.next() {
1408         Some(ch) => ch,
1409         None => {
1410             return Err(LexError);
1411         }
1412     };
1413     let recognized = "~!@#$%^&*-=+|;:,<.>/?'";
1414     if recognized.contains(first) {
1415         Ok((input.advance(first.len_utf8()), first))
1416     } else {
1417         Err(LexError)
1418     }
1419 }
1420 
doc_comment(input: Cursor) -> PResult<Vec<TokenTree>>1421 fn doc_comment(input: Cursor) -> PResult<Vec<TokenTree>> {
1422     let mut trees = Vec::new();
1423     let (rest, ((comment, inner), span)) = spanned(input, doc_comment_contents)?;
1424     trees.push(TokenTree::Punct(Punct::new('#', Spacing::Alone)));
1425     if inner {
1426         trees.push(Punct::new('!', Spacing::Alone).into());
1427     }
1428     let mut stream = vec![
1429         TokenTree::Ident(crate::Ident::new("doc", span)),
1430         TokenTree::Punct(Punct::new('=', Spacing::Alone)),
1431         TokenTree::Literal(crate::Literal::string(comment)),
1432     ];
1433     for tt in stream.iter_mut() {
1434         tt.set_span(span);
1435     }
1436     let group = Group::new(Delimiter::Bracket, stream.into_iter().collect());
1437     trees.push(crate::Group::_new_stable(group).into());
1438     for tt in trees.iter_mut() {
1439         tt.set_span(span);
1440     }
1441     Ok((rest, trees))
1442 }
1443 
1444 named!(doc_comment_contents -> (&str, bool), alt!(
1445     do_parse!(
1446         punct!("//!") >>
1447         s: take_until_newline_or_eof!() >>
1448         ((s, true))
1449     )
1450     |
1451     do_parse!(
1452         option!(whitespace) >>
1453         peek!(tag!("/*!")) >>
1454         s: block_comment >>
1455         ((s, true))
1456     )
1457     |
1458     do_parse!(
1459         punct!("///") >>
1460         not!(tag!("/")) >>
1461         s: take_until_newline_or_eof!() >>
1462         ((s, false))
1463     )
1464     |
1465     do_parse!(
1466         option!(whitespace) >>
1467         peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
1468         s: block_comment >>
1469         ((s, false))
1470     )
1471 ));
1472