• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::fallback::{
2     is_ident_continue, is_ident_start, Group, LexError, Literal, Span, TokenStream,
3 };
4 use crate::{Delimiter, Punct, Spacing, TokenTree};
5 use std::char;
6 use std::str::{Bytes, CharIndices, Chars};
7 
8 #[derive(Copy, Clone, Eq, PartialEq)]
9 pub(crate) struct Cursor<'a> {
10     pub rest: &'a str,
11     #[cfg(span_locations)]
12     pub off: u32,
13 }
14 
15 impl<'a> Cursor<'a> {
advance(&self, bytes: usize) -> Cursor<'a>16     fn advance(&self, bytes: usize) -> Cursor<'a> {
17         let (_front, rest) = self.rest.split_at(bytes);
18         Cursor {
19             rest,
20             #[cfg(span_locations)]
21             off: self.off + _front.chars().count() as u32,
22         }
23     }
24 
starts_with(&self, s: &str) -> bool25     fn starts_with(&self, s: &str) -> bool {
26         self.rest.starts_with(s)
27     }
28 
is_empty(&self) -> bool29     fn is_empty(&self) -> bool {
30         self.rest.is_empty()
31     }
32 
len(&self) -> usize33     fn len(&self) -> usize {
34         self.rest.len()
35     }
36 
as_bytes(&self) -> &'a [u8]37     fn as_bytes(&self) -> &'a [u8] {
38         self.rest.as_bytes()
39     }
40 
bytes(&self) -> Bytes<'a>41     fn bytes(&self) -> Bytes<'a> {
42         self.rest.bytes()
43     }
44 
chars(&self) -> Chars<'a>45     fn chars(&self) -> Chars<'a> {
46         self.rest.chars()
47     }
48 
char_indices(&self) -> CharIndices<'a>49     fn char_indices(&self) -> CharIndices<'a> {
50         self.rest.char_indices()
51     }
52 
parse(&self, tag: &str) -> Result<Cursor<'a>, Reject>53     fn parse(&self, tag: &str) -> Result<Cursor<'a>, Reject> {
54         if self.starts_with(tag) {
55             Ok(self.advance(tag.len()))
56         } else {
57             Err(Reject)
58         }
59     }
60 }
61 
62 struct Reject;
63 type PResult<'a, O> = Result<(Cursor<'a>, O), Reject>;
64 
skip_whitespace(input: Cursor) -> Cursor65 fn skip_whitespace(input: Cursor) -> Cursor {
66     let mut s = input;
67 
68     while !s.is_empty() {
69         let byte = s.as_bytes()[0];
70         if byte == b'/' {
71             if s.starts_with("//")
72                 && (!s.starts_with("///") || s.starts_with("////"))
73                 && !s.starts_with("//!")
74             {
75                 let (cursor, _) = take_until_newline_or_eof(s);
76                 s = cursor;
77                 continue;
78             } else if s.starts_with("/**/") {
79                 s = s.advance(4);
80                 continue;
81             } else if s.starts_with("/*")
82                 && (!s.starts_with("/**") || s.starts_with("/***"))
83                 && !s.starts_with("/*!")
84             {
85                 match block_comment(s) {
86                     Ok((rest, _)) => {
87                         s = rest;
88                         continue;
89                     }
90                     Err(Reject) => return s,
91                 }
92             }
93         }
94         match byte {
95             b' ' | 0x09..=0x0d => {
96                 s = s.advance(1);
97                 continue;
98             }
99             b if b <= 0x7f => {}
100             _ => {
101                 let ch = s.chars().next().unwrap();
102                 if is_whitespace(ch) {
103                     s = s.advance(ch.len_utf8());
104                     continue;
105                 }
106             }
107         }
108         return s;
109     }
110     s
111 }
112 
block_comment(input: Cursor) -> PResult<&str>113 fn block_comment(input: Cursor) -> PResult<&str> {
114     if !input.starts_with("/*") {
115         return Err(Reject);
116     }
117 
118     let mut depth = 0;
119     let bytes = input.as_bytes();
120     let mut i = 0;
121     let upper = bytes.len() - 1;
122 
123     while i < upper {
124         if bytes[i] == b'/' && bytes[i + 1] == b'*' {
125             depth += 1;
126             i += 1; // eat '*'
127         } else if bytes[i] == b'*' && bytes[i + 1] == b'/' {
128             depth -= 1;
129             if depth == 0 {
130                 return Ok((input.advance(i + 2), &input.rest[..i + 2]));
131             }
132             i += 1; // eat '/'
133         }
134         i += 1;
135     }
136 
137     Err(Reject)
138 }
139 
is_whitespace(ch: char) -> bool140 fn is_whitespace(ch: char) -> bool {
141     // Rust treats left-to-right mark and right-to-left mark as whitespace
142     ch.is_whitespace() || ch == '\u{200e}' || ch == '\u{200f}'
143 }
144 
word_break(input: Cursor) -> Result<Cursor, Reject>145 fn word_break(input: Cursor) -> Result<Cursor, Reject> {
146     match input.chars().next() {
147         Some(ch) if is_ident_continue(ch) => Err(Reject),
148         Some(_) | None => Ok(input),
149     }
150 }
151 
token_stream(mut input: Cursor) -> Result<TokenStream, LexError>152 pub(crate) fn token_stream(mut input: Cursor) -> Result<TokenStream, LexError> {
153     let mut trees = Vec::new();
154     let mut stack = Vec::new();
155 
156     loop {
157         input = skip_whitespace(input);
158 
159         if let Ok((rest, tt)) = doc_comment(input) {
160             trees.extend(tt);
161             input = rest;
162             continue;
163         }
164 
165         #[cfg(span_locations)]
166         let lo = input.off;
167 
168         let first = match input.bytes().next() {
169             Some(first) => first,
170             None => match stack.last() {
171                 None => return Ok(TokenStream { inner: trees }),
172                 #[cfg(span_locations)]
173                 Some((lo, _frame)) => {
174                     return Err(LexError {
175                         span: Span { lo: *lo, hi: *lo },
176                     })
177                 }
178                 #[cfg(not(span_locations))]
179                 Some(_frame) => return Err(LexError { span: Span {} }),
180             },
181         };
182 
183         if let Some(open_delimiter) = match first {
184             b'(' => Some(Delimiter::Parenthesis),
185             b'[' => Some(Delimiter::Bracket),
186             b'{' => Some(Delimiter::Brace),
187             _ => None,
188         } {
189             input = input.advance(1);
190             let frame = (open_delimiter, trees);
191             #[cfg(span_locations)]
192             let frame = (lo, frame);
193             stack.push(frame);
194             trees = Vec::new();
195         } else if let Some(close_delimiter) = match first {
196             b')' => Some(Delimiter::Parenthesis),
197             b']' => Some(Delimiter::Bracket),
198             b'}' => Some(Delimiter::Brace),
199             _ => None,
200         } {
201             let frame = match stack.pop() {
202                 Some(frame) => frame,
203                 None => return Err(lex_error(input)),
204             };
205             #[cfg(span_locations)]
206             let (lo, frame) = frame;
207             let (open_delimiter, outer) = frame;
208             if open_delimiter != close_delimiter {
209                 return Err(lex_error(input));
210             }
211             input = input.advance(1);
212             let mut g = Group::new(open_delimiter, TokenStream { inner: trees });
213             g.set_span(Span {
214                 #[cfg(span_locations)]
215                 lo,
216                 #[cfg(span_locations)]
217                 hi: input.off,
218             });
219             trees = outer;
220             trees.push(TokenTree::Group(crate::Group::_new_stable(g)));
221         } else {
222             let (rest, mut tt) = match leaf_token(input) {
223                 Ok((rest, tt)) => (rest, tt),
224                 Err(Reject) => return Err(lex_error(input)),
225             };
226             tt.set_span(crate::Span::_new_stable(Span {
227                 #[cfg(span_locations)]
228                 lo,
229                 #[cfg(span_locations)]
230                 hi: rest.off,
231             }));
232             trees.push(tt);
233             input = rest;
234         }
235     }
236 }
237 
lex_error(cursor: Cursor) -> LexError238 fn lex_error(cursor: Cursor) -> LexError {
239     #[cfg(not(span_locations))]
240     let _ = cursor;
241     LexError {
242         span: Span {
243             #[cfg(span_locations)]
244             lo: cursor.off,
245             #[cfg(span_locations)]
246             hi: cursor.off,
247         },
248     }
249 }
250 
leaf_token(input: Cursor) -> PResult<TokenTree>251 fn leaf_token(input: Cursor) -> PResult<TokenTree> {
252     if let Ok((input, l)) = literal(input) {
253         // must be parsed before ident
254         Ok((input, TokenTree::Literal(crate::Literal::_new_stable(l))))
255     } else if let Ok((input, p)) = punct(input) {
256         Ok((input, TokenTree::Punct(p)))
257     } else if let Ok((input, i)) = ident(input) {
258         Ok((input, TokenTree::Ident(i)))
259     } else {
260         Err(Reject)
261     }
262 }
263 
ident(input: Cursor) -> PResult<crate::Ident>264 fn ident(input: Cursor) -> PResult<crate::Ident> {
265     if ["r\"", "r#\"", "r##", "b\"", "b\'", "br\"", "br#"]
266         .iter()
267         .any(|prefix| input.starts_with(prefix))
268     {
269         Err(Reject)
270     } else {
271         ident_any(input)
272     }
273 }
274 
ident_any(input: Cursor) -> PResult<crate::Ident>275 fn ident_any(input: Cursor) -> PResult<crate::Ident> {
276     let raw = input.starts_with("r#");
277     let rest = input.advance((raw as usize) << 1);
278 
279     let (rest, sym) = ident_not_raw(rest)?;
280 
281     if !raw {
282         let ident = crate::Ident::new(sym, crate::Span::call_site());
283         return Ok((rest, ident));
284     }
285 
286     if sym == "_" {
287         return Err(Reject);
288     }
289 
290     let ident = crate::Ident::_new_raw(sym, crate::Span::call_site());
291     Ok((rest, ident))
292 }
293 
ident_not_raw(input: Cursor) -> PResult<&str>294 fn ident_not_raw(input: Cursor) -> PResult<&str> {
295     let mut chars = input.char_indices();
296 
297     match chars.next() {
298         Some((_, ch)) if is_ident_start(ch) => {}
299         _ => return Err(Reject),
300     }
301 
302     let mut end = input.len();
303     for (i, ch) in chars {
304         if !is_ident_continue(ch) {
305             end = i;
306             break;
307         }
308     }
309 
310     Ok((input.advance(end), &input.rest[..end]))
311 }
312 
literal(input: Cursor) -> PResult<Literal>313 fn literal(input: Cursor) -> PResult<Literal> {
314     let rest = literal_nocapture(input)?;
315     let end = input.len() - rest.len();
316     Ok((rest, Literal::_new(input.rest[..end].to_string())))
317 }
318 
literal_nocapture(input: Cursor) -> Result<Cursor, Reject>319 fn literal_nocapture(input: Cursor) -> Result<Cursor, Reject> {
320     if let Ok(ok) = string(input) {
321         Ok(ok)
322     } else if let Ok(ok) = byte_string(input) {
323         Ok(ok)
324     } else if let Ok(ok) = byte(input) {
325         Ok(ok)
326     } else if let Ok(ok) = character(input) {
327         Ok(ok)
328     } else if let Ok(ok) = float(input) {
329         Ok(ok)
330     } else if let Ok(ok) = int(input) {
331         Ok(ok)
332     } else {
333         Err(Reject)
334     }
335 }
336 
literal_suffix(input: Cursor) -> Cursor337 fn literal_suffix(input: Cursor) -> Cursor {
338     match ident_not_raw(input) {
339         Ok((input, _)) => input,
340         Err(Reject) => input,
341     }
342 }
343 
string(input: Cursor) -> Result<Cursor, Reject>344 fn string(input: Cursor) -> Result<Cursor, Reject> {
345     if let Ok(input) = input.parse("\"") {
346         cooked_string(input)
347     } else if let Ok(input) = input.parse("r") {
348         raw_string(input)
349     } else {
350         Err(Reject)
351     }
352 }
353 
cooked_string(input: Cursor) -> Result<Cursor, Reject>354 fn cooked_string(input: Cursor) -> Result<Cursor, Reject> {
355     let mut chars = input.char_indices().peekable();
356 
357     while let Some((i, ch)) = chars.next() {
358         match ch {
359             '"' => {
360                 let input = input.advance(i + 1);
361                 return Ok(literal_suffix(input));
362             }
363             '\r' => match chars.next() {
364                 Some((_, '\n')) => {}
365                 _ => break,
366             },
367             '\\' => match chars.next() {
368                 Some((_, 'x')) => {
369                     if !backslash_x_char(&mut chars) {
370                         break;
371                     }
372                 }
373                 Some((_, 'n')) | Some((_, 'r')) | Some((_, 't')) | Some((_, '\\'))
374                 | Some((_, '\'')) | Some((_, '"')) | Some((_, '0')) => {}
375                 Some((_, 'u')) => {
376                     if !backslash_u(&mut chars) {
377                         break;
378                     }
379                 }
380                 Some((_, ch @ '\n')) | Some((_, ch @ '\r')) => {
381                     let mut last = ch;
382                     loop {
383                         if last == '\r' && chars.next().map_or(true, |(_, ch)| ch != '\n') {
384                             return Err(Reject);
385                         }
386                         match chars.peek() {
387                             Some((_, ch)) if ch.is_whitespace() => {
388                                 last = *ch;
389                                 chars.next();
390                             }
391                             _ => break,
392                         }
393                     }
394                 }
395                 _ => break,
396             },
397             _ch => {}
398         }
399     }
400     Err(Reject)
401 }
402 
byte_string(input: Cursor) -> Result<Cursor, Reject>403 fn byte_string(input: Cursor) -> Result<Cursor, Reject> {
404     if let Ok(input) = input.parse("b\"") {
405         cooked_byte_string(input)
406     } else if let Ok(input) = input.parse("br") {
407         raw_string(input)
408     } else {
409         Err(Reject)
410     }
411 }
412 
cooked_byte_string(mut input: Cursor) -> Result<Cursor, Reject>413 fn cooked_byte_string(mut input: Cursor) -> Result<Cursor, Reject> {
414     let mut bytes = input.bytes().enumerate();
415     while let Some((offset, b)) = bytes.next() {
416         match b {
417             b'"' => {
418                 let input = input.advance(offset + 1);
419                 return Ok(literal_suffix(input));
420             }
421             b'\r' => match bytes.next() {
422                 Some((_, b'\n')) => {}
423                 _ => break,
424             },
425             b'\\' => match bytes.next() {
426                 Some((_, b'x')) => {
427                     if !backslash_x_byte(&mut bytes) {
428                         break;
429                     }
430                 }
431                 Some((_, b'n')) | Some((_, b'r')) | Some((_, b't')) | Some((_, b'\\'))
432                 | Some((_, b'0')) | Some((_, b'\'')) | Some((_, b'"')) => {}
433                 Some((newline, b @ b'\n')) | Some((newline, b @ b'\r')) => {
434                     let mut last = b as char;
435                     let rest = input.advance(newline + 1);
436                     let mut chars = rest.char_indices();
437                     loop {
438                         if last == '\r' && chars.next().map_or(true, |(_, ch)| ch != '\n') {
439                             return Err(Reject);
440                         }
441                         match chars.next() {
442                             Some((_, ch)) if ch.is_whitespace() => last = ch,
443                             Some((offset, _)) => {
444                                 input = rest.advance(offset);
445                                 bytes = input.bytes().enumerate();
446                                 break;
447                             }
448                             None => return Err(Reject),
449                         }
450                     }
451                 }
452                 _ => break,
453             },
454             b if b < 0x80 => {}
455             _ => break,
456         }
457     }
458     Err(Reject)
459 }
460 
raw_string(input: Cursor) -> Result<Cursor, Reject>461 fn raw_string(input: Cursor) -> Result<Cursor, Reject> {
462     let mut chars = input.char_indices();
463     let mut n = 0;
464     while let Some((i, ch)) = chars.next() {
465         match ch {
466             '"' => {
467                 n = i;
468                 break;
469             }
470             '#' => {}
471             _ => return Err(Reject),
472         }
473     }
474     while let Some((i, ch)) = chars.next() {
475         match ch {
476             '"' if input.rest[i + 1..].starts_with(&input.rest[..n]) => {
477                 let rest = input.advance(i + 1 + n);
478                 return Ok(literal_suffix(rest));
479             }
480             '\r' => match chars.next() {
481                 Some((_, '\n')) => {}
482                 _ => break,
483             },
484             _ => {}
485         }
486     }
487     Err(Reject)
488 }
489 
byte(input: Cursor) -> Result<Cursor, Reject>490 fn byte(input: Cursor) -> Result<Cursor, Reject> {
491     let input = input.parse("b'")?;
492     let mut bytes = input.bytes().enumerate();
493     let ok = match bytes.next().map(|(_, b)| b) {
494         Some(b'\\') => match bytes.next().map(|(_, b)| b) {
495             Some(b'x') => backslash_x_byte(&mut bytes),
496             Some(b'n') | Some(b'r') | Some(b't') | Some(b'\\') | Some(b'0') | Some(b'\'')
497             | Some(b'"') => true,
498             _ => false,
499         },
500         b => b.is_some(),
501     };
502     if !ok {
503         return Err(Reject);
504     }
505     let (offset, _) = bytes.next().ok_or(Reject)?;
506     if !input.chars().as_str().is_char_boundary(offset) {
507         return Err(Reject);
508     }
509     let input = input.advance(offset).parse("'")?;
510     Ok(literal_suffix(input))
511 }
512 
character(input: Cursor) -> Result<Cursor, Reject>513 fn character(input: Cursor) -> Result<Cursor, Reject> {
514     let input = input.parse("'")?;
515     let mut chars = input.char_indices();
516     let ok = match chars.next().map(|(_, ch)| ch) {
517         Some('\\') => match chars.next().map(|(_, ch)| ch) {
518             Some('x') => backslash_x_char(&mut chars),
519             Some('u') => backslash_u(&mut chars),
520             Some('n') | Some('r') | Some('t') | Some('\\') | Some('0') | Some('\'') | Some('"') => {
521                 true
522             }
523             _ => false,
524         },
525         ch => ch.is_some(),
526     };
527     if !ok {
528         return Err(Reject);
529     }
530     let (idx, _) = chars.next().ok_or(Reject)?;
531     let input = input.advance(idx).parse("'")?;
532     Ok(literal_suffix(input))
533 }
534 
535 macro_rules! next_ch {
536     ($chars:ident @ $pat:pat $(| $rest:pat)*) => {
537         match $chars.next() {
538             Some((_, ch)) => match ch {
539                 $pat $(| $rest)* => ch,
540                 _ => return false,
541             },
542             None => return false,
543         }
544     };
545 }
546 
backslash_x_char<I>(chars: &mut I) -> bool where I: Iterator<Item = (usize, char)>,547 fn backslash_x_char<I>(chars: &mut I) -> bool
548 where
549     I: Iterator<Item = (usize, char)>,
550 {
551     next_ch!(chars @ '0'..='7');
552     next_ch!(chars @ '0'..='9' | 'a'..='f' | 'A'..='F');
553     true
554 }
555 
backslash_x_byte<I>(chars: &mut I) -> bool where I: Iterator<Item = (usize, u8)>,556 fn backslash_x_byte<I>(chars: &mut I) -> bool
557 where
558     I: Iterator<Item = (usize, u8)>,
559 {
560     next_ch!(chars @ b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F');
561     next_ch!(chars @ b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F');
562     true
563 }
564 
backslash_u<I>(chars: &mut I) -> bool where I: Iterator<Item = (usize, char)>,565 fn backslash_u<I>(chars: &mut I) -> bool
566 where
567     I: Iterator<Item = (usize, char)>,
568 {
569     next_ch!(chars @ '{');
570     let mut value = 0;
571     let mut len = 0;
572     for (_, ch) in chars {
573         let digit = match ch {
574             '0'..='9' => ch as u8 - b'0',
575             'a'..='f' => 10 + ch as u8 - b'a',
576             'A'..='F' => 10 + ch as u8 - b'A',
577             '_' if len > 0 => continue,
578             '}' if len > 0 => return char::from_u32(value).is_some(),
579             _ => return false,
580         };
581         if len == 6 {
582             return false;
583         }
584         value *= 0x10;
585         value += u32::from(digit);
586         len += 1;
587     }
588     false
589 }
590 
float(input: Cursor) -> Result<Cursor, Reject>591 fn float(input: Cursor) -> Result<Cursor, Reject> {
592     let mut rest = float_digits(input)?;
593     if let Some(ch) = rest.chars().next() {
594         if is_ident_start(ch) {
595             rest = ident_not_raw(rest)?.0;
596         }
597     }
598     word_break(rest)
599 }
600 
float_digits(input: Cursor) -> Result<Cursor, Reject>601 fn float_digits(input: Cursor) -> Result<Cursor, Reject> {
602     let mut chars = input.chars().peekable();
603     match chars.next() {
604         Some(ch) if ch >= '0' && ch <= '9' => {}
605         _ => return Err(Reject),
606     }
607 
608     let mut len = 1;
609     let mut has_dot = false;
610     let mut has_exp = false;
611     while let Some(&ch) = chars.peek() {
612         match ch {
613             '0'..='9' | '_' => {
614                 chars.next();
615                 len += 1;
616             }
617             '.' => {
618                 if has_dot {
619                     break;
620                 }
621                 chars.next();
622                 if chars
623                     .peek()
624                     .map(|&ch| ch == '.' || is_ident_start(ch))
625                     .unwrap_or(false)
626                 {
627                     return Err(Reject);
628                 }
629                 len += 1;
630                 has_dot = true;
631             }
632             'e' | 'E' => {
633                 chars.next();
634                 len += 1;
635                 has_exp = true;
636                 break;
637             }
638             _ => break,
639         }
640     }
641 
642     if !(has_dot || has_exp) {
643         return Err(Reject);
644     }
645 
646     if has_exp {
647         let token_before_exp = if has_dot {
648             Ok(input.advance(len - 1))
649         } else {
650             Err(Reject)
651         };
652         let mut has_sign = false;
653         let mut has_exp_value = false;
654         while let Some(&ch) = chars.peek() {
655             match ch {
656                 '+' | '-' => {
657                     if has_exp_value {
658                         break;
659                     }
660                     if has_sign {
661                         return token_before_exp;
662                     }
663                     chars.next();
664                     len += 1;
665                     has_sign = true;
666                 }
667                 '0'..='9' => {
668                     chars.next();
669                     len += 1;
670                     has_exp_value = true;
671                 }
672                 '_' => {
673                     chars.next();
674                     len += 1;
675                 }
676                 _ => break,
677             }
678         }
679         if !has_exp_value {
680             return token_before_exp;
681         }
682     }
683 
684     Ok(input.advance(len))
685 }
686 
int(input: Cursor) -> Result<Cursor, Reject>687 fn int(input: Cursor) -> Result<Cursor, Reject> {
688     let mut rest = digits(input)?;
689     if let Some(ch) = rest.chars().next() {
690         if is_ident_start(ch) {
691             rest = ident_not_raw(rest)?.0;
692         }
693     }
694     word_break(rest)
695 }
696 
digits(mut input: Cursor) -> Result<Cursor, Reject>697 fn digits(mut input: Cursor) -> Result<Cursor, Reject> {
698     let base = if input.starts_with("0x") {
699         input = input.advance(2);
700         16
701     } else if input.starts_with("0o") {
702         input = input.advance(2);
703         8
704     } else if input.starts_with("0b") {
705         input = input.advance(2);
706         2
707     } else {
708         10
709     };
710 
711     let mut len = 0;
712     let mut empty = true;
713     for b in input.bytes() {
714         match b {
715             b'0'..=b'9' => {
716                 let digit = (b - b'0') as u64;
717                 if digit >= base {
718                     return Err(Reject);
719                 }
720             }
721             b'a'..=b'f' => {
722                 let digit = 10 + (b - b'a') as u64;
723                 if digit >= base {
724                     break;
725                 }
726             }
727             b'A'..=b'F' => {
728                 let digit = 10 + (b - b'A') as u64;
729                 if digit >= base {
730                     break;
731                 }
732             }
733             b'_' => {
734                 if empty && base == 10 {
735                     return Err(Reject);
736                 }
737                 len += 1;
738                 continue;
739             }
740             _ => break,
741         };
742         len += 1;
743         empty = false;
744     }
745     if empty {
746         Err(Reject)
747     } else {
748         Ok(input.advance(len))
749     }
750 }
751 
punct(input: Cursor) -> PResult<Punct>752 fn punct(input: Cursor) -> PResult<Punct> {
753     let (rest, ch) = punct_char(input)?;
754     if ch == '\'' {
755         if ident_any(rest)?.0.starts_with("'") {
756             Err(Reject)
757         } else {
758             Ok((rest, Punct::new('\'', Spacing::Joint)))
759         }
760     } else {
761         let kind = match punct_char(rest) {
762             Ok(_) => Spacing::Joint,
763             Err(Reject) => Spacing::Alone,
764         };
765         Ok((rest, Punct::new(ch, kind)))
766     }
767 }
768 
punct_char(input: Cursor) -> PResult<char>769 fn punct_char(input: Cursor) -> PResult<char> {
770     if input.starts_with("//") || input.starts_with("/*") {
771         // Do not accept `/` of a comment as a punct.
772         return Err(Reject);
773     }
774 
775     let mut chars = input.chars();
776     let first = match chars.next() {
777         Some(ch) => ch,
778         None => {
779             return Err(Reject);
780         }
781     };
782     let recognized = "~!@#$%^&*-=+|;:,<.>/?'";
783     if recognized.contains(first) {
784         Ok((input.advance(first.len_utf8()), first))
785     } else {
786         Err(Reject)
787     }
788 }
789 
doc_comment(input: Cursor) -> PResult<Vec<TokenTree>>790 fn doc_comment(input: Cursor) -> PResult<Vec<TokenTree>> {
791     #[cfg(span_locations)]
792     let lo = input.off;
793     let (rest, (comment, inner)) = doc_comment_contents(input)?;
794     let span = crate::Span::_new_stable(Span {
795         #[cfg(span_locations)]
796         lo,
797         #[cfg(span_locations)]
798         hi: rest.off,
799     });
800 
801     let mut scan_for_bare_cr = comment;
802     while let Some(cr) = scan_for_bare_cr.find('\r') {
803         let rest = &scan_for_bare_cr[cr + 1..];
804         if !rest.starts_with('\n') {
805             return Err(Reject);
806         }
807         scan_for_bare_cr = rest;
808     }
809 
810     let mut trees = Vec::new();
811     trees.push(TokenTree::Punct(Punct::new('#', Spacing::Alone)));
812     if inner {
813         trees.push(Punct::new('!', Spacing::Alone).into());
814     }
815     let mut stream = vec![
816         TokenTree::Ident(crate::Ident::new("doc", span)),
817         TokenTree::Punct(Punct::new('=', Spacing::Alone)),
818         TokenTree::Literal(crate::Literal::string(comment)),
819     ];
820     for tt in stream.iter_mut() {
821         tt.set_span(span);
822     }
823     let group = Group::new(Delimiter::Bracket, stream.into_iter().collect());
824     trees.push(crate::Group::_new_stable(group).into());
825     for tt in trees.iter_mut() {
826         tt.set_span(span);
827     }
828     Ok((rest, trees))
829 }
830 
doc_comment_contents(input: Cursor) -> PResult<(&str, bool)>831 fn doc_comment_contents(input: Cursor) -> PResult<(&str, bool)> {
832     if input.starts_with("//!") {
833         let input = input.advance(3);
834         let (input, s) = take_until_newline_or_eof(input);
835         Ok((input, (s, true)))
836     } else if input.starts_with("/*!") {
837         let (input, s) = block_comment(input)?;
838         Ok((input, (&s[3..s.len() - 2], true)))
839     } else if input.starts_with("///") {
840         let input = input.advance(3);
841         if input.starts_with("/") {
842             return Err(Reject);
843         }
844         let (input, s) = take_until_newline_or_eof(input);
845         Ok((input, (s, false)))
846     } else if input.starts_with("/**") && !input.rest[3..].starts_with('*') {
847         let (input, s) = block_comment(input)?;
848         Ok((input, (&s[3..s.len() - 2], false)))
849     } else {
850         Err(Reject)
851     }
852 }
853 
take_until_newline_or_eof(input: Cursor) -> (Cursor, &str)854 fn take_until_newline_or_eof(input: Cursor) -> (Cursor, &str) {
855     let chars = input.char_indices();
856 
857     for (i, ch) in chars {
858         if ch == '\n' {
859             return (input.advance(i), &input.rest[..i]);
860         } else if ch == '\r' && input.rest[i + 1..].starts_with('\n') {
861             return (input.advance(i + 1), &input.rest[..i]);
862         }
863     }
864 
865     (input.advance(input.len()), input.rest)
866 }
867