xref: /linux/rust/proc-macro2/parse.rs (revision 784faa8eca8270671e0ed6d9d21f04bbb80fc5f7)
1*a9acfcebSMiguel Ojeda // SPDX-License-Identifier: Apache-2.0 OR MIT
2*a9acfcebSMiguel Ojeda 
33a8b546aSMiguel Ojeda use crate::fallback::{
43a8b546aSMiguel Ojeda     self, is_ident_continue, is_ident_start, Group, Ident, LexError, Literal, Span, TokenStream,
53a8b546aSMiguel Ojeda     TokenStreamBuilder,
63a8b546aSMiguel Ojeda };
73a8b546aSMiguel Ojeda use crate::{Delimiter, Punct, Spacing, TokenTree};
83a8b546aSMiguel Ojeda use core::char;
93a8b546aSMiguel Ojeda use core::str::{Bytes, CharIndices, Chars};
103a8b546aSMiguel Ojeda 
113a8b546aSMiguel Ojeda #[derive(Copy, Clone, Eq, PartialEq)]
123a8b546aSMiguel Ojeda pub(crate) struct Cursor<'a> {
133a8b546aSMiguel Ojeda     pub(crate) rest: &'a str,
143a8b546aSMiguel Ojeda     #[cfg(span_locations)]
153a8b546aSMiguel Ojeda     pub(crate) off: u32,
163a8b546aSMiguel Ojeda }
173a8b546aSMiguel Ojeda 
183a8b546aSMiguel Ojeda impl<'a> Cursor<'a> {
advance(&self, bytes: usize) -> Cursor<'a>193a8b546aSMiguel Ojeda     pub(crate) fn advance(&self, bytes: usize) -> Cursor<'a> {
203a8b546aSMiguel Ojeda         let (_front, rest) = self.rest.split_at(bytes);
213a8b546aSMiguel Ojeda         Cursor {
223a8b546aSMiguel Ojeda             rest,
233a8b546aSMiguel Ojeda             #[cfg(span_locations)]
243a8b546aSMiguel Ojeda             off: self.off + _front.chars().count() as u32,
253a8b546aSMiguel Ojeda         }
263a8b546aSMiguel Ojeda     }
273a8b546aSMiguel Ojeda 
starts_with(&self, s: &str) -> bool283a8b546aSMiguel Ojeda     pub(crate) fn starts_with(&self, s: &str) -> bool {
293a8b546aSMiguel Ojeda         self.rest.starts_with(s)
303a8b546aSMiguel Ojeda     }
313a8b546aSMiguel Ojeda 
starts_with_char(&self, ch: char) -> bool323a8b546aSMiguel Ojeda     pub(crate) fn starts_with_char(&self, ch: char) -> bool {
333a8b546aSMiguel Ojeda         self.rest.starts_with(ch)
343a8b546aSMiguel Ojeda     }
353a8b546aSMiguel Ojeda 
starts_with_fn<Pattern>(&self, f: Pattern) -> bool where Pattern: FnMut(char) -> bool,363a8b546aSMiguel Ojeda     pub(crate) fn starts_with_fn<Pattern>(&self, f: Pattern) -> bool
373a8b546aSMiguel Ojeda     where
383a8b546aSMiguel Ojeda         Pattern: FnMut(char) -> bool,
393a8b546aSMiguel Ojeda     {
403a8b546aSMiguel Ojeda         self.rest.starts_with(f)
413a8b546aSMiguel Ojeda     }
423a8b546aSMiguel Ojeda 
is_empty(&self) -> bool433a8b546aSMiguel Ojeda     pub(crate) fn is_empty(&self) -> bool {
443a8b546aSMiguel Ojeda         self.rest.is_empty()
453a8b546aSMiguel Ojeda     }
463a8b546aSMiguel Ojeda 
len(&self) -> usize473a8b546aSMiguel Ojeda     fn len(&self) -> usize {
483a8b546aSMiguel Ojeda         self.rest.len()
493a8b546aSMiguel Ojeda     }
503a8b546aSMiguel Ojeda 
as_bytes(&self) -> &'a [u8]513a8b546aSMiguel Ojeda     fn as_bytes(&self) -> &'a [u8] {
523a8b546aSMiguel Ojeda         self.rest.as_bytes()
533a8b546aSMiguel Ojeda     }
543a8b546aSMiguel Ojeda 
bytes(&self) -> Bytes<'a>553a8b546aSMiguel Ojeda     fn bytes(&self) -> Bytes<'a> {
563a8b546aSMiguel Ojeda         self.rest.bytes()
573a8b546aSMiguel Ojeda     }
583a8b546aSMiguel Ojeda 
chars(&self) -> Chars<'a>593a8b546aSMiguel Ojeda     fn chars(&self) -> Chars<'a> {
603a8b546aSMiguel Ojeda         self.rest.chars()
613a8b546aSMiguel Ojeda     }
623a8b546aSMiguel Ojeda 
char_indices(&self) -> CharIndices<'a>633a8b546aSMiguel Ojeda     fn char_indices(&self) -> CharIndices<'a> {
643a8b546aSMiguel Ojeda         self.rest.char_indices()
653a8b546aSMiguel Ojeda     }
663a8b546aSMiguel Ojeda 
parse(&self, tag: &str) -> Result<Cursor<'a>, Reject>673a8b546aSMiguel Ojeda     fn parse(&self, tag: &str) -> Result<Cursor<'a>, Reject> {
683a8b546aSMiguel Ojeda         if self.starts_with(tag) {
693a8b546aSMiguel Ojeda             Ok(self.advance(tag.len()))
703a8b546aSMiguel Ojeda         } else {
713a8b546aSMiguel Ojeda             Err(Reject)
723a8b546aSMiguel Ojeda         }
733a8b546aSMiguel Ojeda     }
743a8b546aSMiguel Ojeda }
753a8b546aSMiguel Ojeda 
763a8b546aSMiguel Ojeda pub(crate) struct Reject;
773a8b546aSMiguel Ojeda type PResult<'a, O> = Result<(Cursor<'a>, O), Reject>;
783a8b546aSMiguel Ojeda 
skip_whitespace(input: Cursor) -> Cursor793a8b546aSMiguel Ojeda fn skip_whitespace(input: Cursor) -> Cursor {
803a8b546aSMiguel Ojeda     let mut s = input;
813a8b546aSMiguel Ojeda 
823a8b546aSMiguel Ojeda     while !s.is_empty() {
833a8b546aSMiguel Ojeda         let byte = s.as_bytes()[0];
843a8b546aSMiguel Ojeda         if byte == b'/' {
853a8b546aSMiguel Ojeda             if s.starts_with("//")
863a8b546aSMiguel Ojeda                 && (!s.starts_with("///") || s.starts_with("////"))
873a8b546aSMiguel Ojeda                 && !s.starts_with("//!")
883a8b546aSMiguel Ojeda             {
893a8b546aSMiguel Ojeda                 let (cursor, _) = take_until_newline_or_eof(s);
903a8b546aSMiguel Ojeda                 s = cursor;
913a8b546aSMiguel Ojeda                 continue;
923a8b546aSMiguel Ojeda             } else if s.starts_with("/**/") {
933a8b546aSMiguel Ojeda                 s = s.advance(4);
943a8b546aSMiguel Ojeda                 continue;
953a8b546aSMiguel Ojeda             } else if s.starts_with("/*")
963a8b546aSMiguel Ojeda                 && (!s.starts_with("/**") || s.starts_with("/***"))
973a8b546aSMiguel Ojeda                 && !s.starts_with("/*!")
983a8b546aSMiguel Ojeda             {
993a8b546aSMiguel Ojeda                 match block_comment(s) {
1003a8b546aSMiguel Ojeda                     Ok((rest, _)) => {
1013a8b546aSMiguel Ojeda                         s = rest;
1023a8b546aSMiguel Ojeda                         continue;
1033a8b546aSMiguel Ojeda                     }
1043a8b546aSMiguel Ojeda                     Err(Reject) => return s,
1053a8b546aSMiguel Ojeda                 }
1063a8b546aSMiguel Ojeda             }
1073a8b546aSMiguel Ojeda         }
1083a8b546aSMiguel Ojeda         match byte {
1093a8b546aSMiguel Ojeda             b' ' | 0x09..=0x0d => {
1103a8b546aSMiguel Ojeda                 s = s.advance(1);
1113a8b546aSMiguel Ojeda                 continue;
1123a8b546aSMiguel Ojeda             }
1133a8b546aSMiguel Ojeda             b if b.is_ascii() => {}
1143a8b546aSMiguel Ojeda             _ => {
1153a8b546aSMiguel Ojeda                 let ch = s.chars().next().unwrap();
1163a8b546aSMiguel Ojeda                 if is_whitespace(ch) {
1173a8b546aSMiguel Ojeda                     s = s.advance(ch.len_utf8());
1183a8b546aSMiguel Ojeda                     continue;
1193a8b546aSMiguel Ojeda                 }
1203a8b546aSMiguel Ojeda             }
1213a8b546aSMiguel Ojeda         }
1223a8b546aSMiguel Ojeda         return s;
1233a8b546aSMiguel Ojeda     }
1243a8b546aSMiguel Ojeda     s
1253a8b546aSMiguel Ojeda }
1263a8b546aSMiguel Ojeda 
block_comment(input: Cursor) -> PResult<&str>1273a8b546aSMiguel Ojeda fn block_comment(input: Cursor) -> PResult<&str> {
1283a8b546aSMiguel Ojeda     if !input.starts_with("/*") {
1293a8b546aSMiguel Ojeda         return Err(Reject);
1303a8b546aSMiguel Ojeda     }
1313a8b546aSMiguel Ojeda 
1323a8b546aSMiguel Ojeda     let mut depth = 0usize;
1333a8b546aSMiguel Ojeda     let bytes = input.as_bytes();
1343a8b546aSMiguel Ojeda     let mut i = 0usize;
1353a8b546aSMiguel Ojeda     let upper = bytes.len() - 1;
1363a8b546aSMiguel Ojeda 
1373a8b546aSMiguel Ojeda     while i < upper {
1383a8b546aSMiguel Ojeda         if bytes[i] == b'/' && bytes[i + 1] == b'*' {
1393a8b546aSMiguel Ojeda             depth += 1;
1403a8b546aSMiguel Ojeda             i += 1; // eat '*'
1413a8b546aSMiguel Ojeda         } else if bytes[i] == b'*' && bytes[i + 1] == b'/' {
1423a8b546aSMiguel Ojeda             depth -= 1;
1433a8b546aSMiguel Ojeda             if depth == 0 {
1443a8b546aSMiguel Ojeda                 return Ok((input.advance(i + 2), &input.rest[..i + 2]));
1453a8b546aSMiguel Ojeda             }
1463a8b546aSMiguel Ojeda             i += 1; // eat '/'
1473a8b546aSMiguel Ojeda         }
1483a8b546aSMiguel Ojeda         i += 1;
1493a8b546aSMiguel Ojeda     }
1503a8b546aSMiguel Ojeda 
1513a8b546aSMiguel Ojeda     Err(Reject)
1523a8b546aSMiguel Ojeda }
1533a8b546aSMiguel Ojeda 
is_whitespace(ch: char) -> bool1543a8b546aSMiguel Ojeda fn is_whitespace(ch: char) -> bool {
1553a8b546aSMiguel Ojeda     // Rust treats left-to-right mark and right-to-left mark as whitespace
1563a8b546aSMiguel Ojeda     ch.is_whitespace() || ch == '\u{200e}' || ch == '\u{200f}'
1573a8b546aSMiguel Ojeda }
1583a8b546aSMiguel Ojeda 
word_break(input: Cursor) -> Result<Cursor, Reject>1593a8b546aSMiguel Ojeda fn word_break(input: Cursor) -> Result<Cursor, Reject> {
1603a8b546aSMiguel Ojeda     match input.chars().next() {
1613a8b546aSMiguel Ojeda         Some(ch) if is_ident_continue(ch) => Err(Reject),
1623a8b546aSMiguel Ojeda         Some(_) | None => Ok(input),
1633a8b546aSMiguel Ojeda     }
1643a8b546aSMiguel Ojeda }
1653a8b546aSMiguel Ojeda 
1663a8b546aSMiguel Ojeda // Rustc's representation of a macro expansion error in expression position or
1673a8b546aSMiguel Ojeda // type position.
1683a8b546aSMiguel Ojeda const ERROR: &str = "(/*ERROR*/)";
1693a8b546aSMiguel Ojeda 
token_stream(mut input: Cursor) -> Result<TokenStream, LexError>1703a8b546aSMiguel Ojeda pub(crate) fn token_stream(mut input: Cursor) -> Result<TokenStream, LexError> {
1713a8b546aSMiguel Ojeda     let mut trees = TokenStreamBuilder::new();
1723a8b546aSMiguel Ojeda     let mut stack = Vec::new();
1733a8b546aSMiguel Ojeda 
1743a8b546aSMiguel Ojeda     loop {
1753a8b546aSMiguel Ojeda         input = skip_whitespace(input);
1763a8b546aSMiguel Ojeda 
1773a8b546aSMiguel Ojeda         if let Ok((rest, ())) = doc_comment(input, &mut trees) {
1783a8b546aSMiguel Ojeda             input = rest;
1793a8b546aSMiguel Ojeda             continue;
1803a8b546aSMiguel Ojeda         }
1813a8b546aSMiguel Ojeda 
1823a8b546aSMiguel Ojeda         #[cfg(span_locations)]
1833a8b546aSMiguel Ojeda         let lo = input.off;
1843a8b546aSMiguel Ojeda 
1853a8b546aSMiguel Ojeda         let first = match input.bytes().next() {
1863a8b546aSMiguel Ojeda             Some(first) => first,
1873a8b546aSMiguel Ojeda             None => match stack.last() {
1883a8b546aSMiguel Ojeda                 None => return Ok(trees.build()),
1893a8b546aSMiguel Ojeda                 #[cfg(span_locations)]
1903a8b546aSMiguel Ojeda                 Some((lo, _frame)) => {
1913a8b546aSMiguel Ojeda                     return Err(LexError {
1923a8b546aSMiguel Ojeda                         span: Span { lo: *lo, hi: *lo },
1933a8b546aSMiguel Ojeda                     })
1943a8b546aSMiguel Ojeda                 }
1953a8b546aSMiguel Ojeda                 #[cfg(not(span_locations))]
1963a8b546aSMiguel Ojeda                 Some(_frame) => return Err(LexError { span: Span {} }),
1973a8b546aSMiguel Ojeda             },
1983a8b546aSMiguel Ojeda         };
1993a8b546aSMiguel Ojeda 
2003a8b546aSMiguel Ojeda         if let Some(open_delimiter) = match first {
2013a8b546aSMiguel Ojeda             b'(' if !input.starts_with(ERROR) => Some(Delimiter::Parenthesis),
2023a8b546aSMiguel Ojeda             b'[' => Some(Delimiter::Bracket),
2033a8b546aSMiguel Ojeda             b'{' => Some(Delimiter::Brace),
2043a8b546aSMiguel Ojeda             _ => None,
2053a8b546aSMiguel Ojeda         } {
2063a8b546aSMiguel Ojeda             input = input.advance(1);
2073a8b546aSMiguel Ojeda             let frame = (open_delimiter, trees);
2083a8b546aSMiguel Ojeda             #[cfg(span_locations)]
2093a8b546aSMiguel Ojeda             let frame = (lo, frame);
2103a8b546aSMiguel Ojeda             stack.push(frame);
2113a8b546aSMiguel Ojeda             trees = TokenStreamBuilder::new();
2123a8b546aSMiguel Ojeda         } else if let Some(close_delimiter) = match first {
2133a8b546aSMiguel Ojeda             b')' => Some(Delimiter::Parenthesis),
2143a8b546aSMiguel Ojeda             b']' => Some(Delimiter::Bracket),
2153a8b546aSMiguel Ojeda             b'}' => Some(Delimiter::Brace),
2163a8b546aSMiguel Ojeda             _ => None,
2173a8b546aSMiguel Ojeda         } {
2183a8b546aSMiguel Ojeda             let frame = match stack.pop() {
2193a8b546aSMiguel Ojeda                 Some(frame) => frame,
2203a8b546aSMiguel Ojeda                 None => return Err(lex_error(input)),
2213a8b546aSMiguel Ojeda             };
2223a8b546aSMiguel Ojeda             #[cfg(span_locations)]
2233a8b546aSMiguel Ojeda             let (lo, frame) = frame;
2243a8b546aSMiguel Ojeda             let (open_delimiter, outer) = frame;
2253a8b546aSMiguel Ojeda             if open_delimiter != close_delimiter {
2263a8b546aSMiguel Ojeda                 return Err(lex_error(input));
2273a8b546aSMiguel Ojeda             }
2283a8b546aSMiguel Ojeda             input = input.advance(1);
2293a8b546aSMiguel Ojeda             let mut g = Group::new(open_delimiter, trees.build());
2303a8b546aSMiguel Ojeda             g.set_span(Span {
2313a8b546aSMiguel Ojeda                 #[cfg(span_locations)]
2323a8b546aSMiguel Ojeda                 lo,
2333a8b546aSMiguel Ojeda                 #[cfg(span_locations)]
2343a8b546aSMiguel Ojeda                 hi: input.off,
2353a8b546aSMiguel Ojeda             });
2363a8b546aSMiguel Ojeda             trees = outer;
2373a8b546aSMiguel Ojeda             trees.push_token_from_parser(TokenTree::Group(crate::Group::_new_fallback(g)));
2383a8b546aSMiguel Ojeda         } else {
2393a8b546aSMiguel Ojeda             let (rest, mut tt) = match leaf_token(input) {
2403a8b546aSMiguel Ojeda                 Ok((rest, tt)) => (rest, tt),
2413a8b546aSMiguel Ojeda                 Err(Reject) => return Err(lex_error(input)),
2423a8b546aSMiguel Ojeda             };
2433a8b546aSMiguel Ojeda             tt.set_span(crate::Span::_new_fallback(Span {
2443a8b546aSMiguel Ojeda                 #[cfg(span_locations)]
2453a8b546aSMiguel Ojeda                 lo,
2463a8b546aSMiguel Ojeda                 #[cfg(span_locations)]
2473a8b546aSMiguel Ojeda                 hi: rest.off,
2483a8b546aSMiguel Ojeda             }));
2493a8b546aSMiguel Ojeda             trees.push_token_from_parser(tt);
2503a8b546aSMiguel Ojeda             input = rest;
2513a8b546aSMiguel Ojeda         }
2523a8b546aSMiguel Ojeda     }
2533a8b546aSMiguel Ojeda }
2543a8b546aSMiguel Ojeda 
lex_error(cursor: Cursor) -> LexError2553a8b546aSMiguel Ojeda fn lex_error(cursor: Cursor) -> LexError {
2563a8b546aSMiguel Ojeda     #[cfg(not(span_locations))]
2573a8b546aSMiguel Ojeda     let _ = cursor;
2583a8b546aSMiguel Ojeda     LexError {
2593a8b546aSMiguel Ojeda         span: Span {
2603a8b546aSMiguel Ojeda             #[cfg(span_locations)]
2613a8b546aSMiguel Ojeda             lo: cursor.off,
2623a8b546aSMiguel Ojeda             #[cfg(span_locations)]
2633a8b546aSMiguel Ojeda             hi: cursor.off,
2643a8b546aSMiguel Ojeda         },
2653a8b546aSMiguel Ojeda     }
2663a8b546aSMiguel Ojeda }
2673a8b546aSMiguel Ojeda 
leaf_token(input: Cursor) -> PResult<TokenTree>2683a8b546aSMiguel Ojeda fn leaf_token(input: Cursor) -> PResult<TokenTree> {
2693a8b546aSMiguel Ojeda     if let Ok((input, l)) = literal(input) {
2703a8b546aSMiguel Ojeda         // must be parsed before ident
2713a8b546aSMiguel Ojeda         Ok((input, TokenTree::Literal(crate::Literal::_new_fallback(l))))
2723a8b546aSMiguel Ojeda     } else if let Ok((input, p)) = punct(input) {
2733a8b546aSMiguel Ojeda         Ok((input, TokenTree::Punct(p)))
2743a8b546aSMiguel Ojeda     } else if let Ok((input, i)) = ident(input) {
2753a8b546aSMiguel Ojeda         Ok((input, TokenTree::Ident(i)))
2763a8b546aSMiguel Ojeda     } else if input.starts_with(ERROR) {
2773a8b546aSMiguel Ojeda         let rest = input.advance(ERROR.len());
2783a8b546aSMiguel Ojeda         let repr = crate::Literal::_new_fallback(Literal::_new(ERROR.to_owned()));
2793a8b546aSMiguel Ojeda         Ok((rest, TokenTree::Literal(repr)))
2803a8b546aSMiguel Ojeda     } else {
2813a8b546aSMiguel Ojeda         Err(Reject)
2823a8b546aSMiguel Ojeda     }
2833a8b546aSMiguel Ojeda }
2843a8b546aSMiguel Ojeda 
ident(input: Cursor) -> PResult<crate::Ident>2853a8b546aSMiguel Ojeda fn ident(input: Cursor) -> PResult<crate::Ident> {
2863a8b546aSMiguel Ojeda     if [
2873a8b546aSMiguel Ojeda         "r\"", "r#\"", "r##", "b\"", "b\'", "br\"", "br#", "c\"", "cr\"", "cr#",
2883a8b546aSMiguel Ojeda     ]
2893a8b546aSMiguel Ojeda     .iter()
2903a8b546aSMiguel Ojeda     .any(|prefix| input.starts_with(prefix))
2913a8b546aSMiguel Ojeda     {
2923a8b546aSMiguel Ojeda         Err(Reject)
2933a8b546aSMiguel Ojeda     } else {
2943a8b546aSMiguel Ojeda         ident_any(input)
2953a8b546aSMiguel Ojeda     }
2963a8b546aSMiguel Ojeda }
2973a8b546aSMiguel Ojeda 
ident_any(input: Cursor) -> PResult<crate::Ident>2983a8b546aSMiguel Ojeda fn ident_any(input: Cursor) -> PResult<crate::Ident> {
2993a8b546aSMiguel Ojeda     let raw = input.starts_with("r#");
3003a8b546aSMiguel Ojeda     let rest = input.advance((raw as usize) << 1);
3013a8b546aSMiguel Ojeda 
3023a8b546aSMiguel Ojeda     let (rest, sym) = ident_not_raw(rest)?;
3033a8b546aSMiguel Ojeda 
3043a8b546aSMiguel Ojeda     if !raw {
3053a8b546aSMiguel Ojeda         let ident =
3063a8b546aSMiguel Ojeda             crate::Ident::_new_fallback(Ident::new_unchecked(sym, fallback::Span::call_site()));
3073a8b546aSMiguel Ojeda         return Ok((rest, ident));
3083a8b546aSMiguel Ojeda     }
3093a8b546aSMiguel Ojeda 
3103a8b546aSMiguel Ojeda     match sym {
3113a8b546aSMiguel Ojeda         "_" | "super" | "self" | "Self" | "crate" => return Err(Reject),
3123a8b546aSMiguel Ojeda         _ => {}
3133a8b546aSMiguel Ojeda     }
3143a8b546aSMiguel Ojeda 
3153a8b546aSMiguel Ojeda     let ident =
3163a8b546aSMiguel Ojeda         crate::Ident::_new_fallback(Ident::new_raw_unchecked(sym, fallback::Span::call_site()));
3173a8b546aSMiguel Ojeda     Ok((rest, ident))
3183a8b546aSMiguel Ojeda }
3193a8b546aSMiguel Ojeda 
ident_not_raw(input: Cursor) -> PResult<&str>3203a8b546aSMiguel Ojeda fn ident_not_raw(input: Cursor) -> PResult<&str> {
3213a8b546aSMiguel Ojeda     let mut chars = input.char_indices();
3223a8b546aSMiguel Ojeda 
3233a8b546aSMiguel Ojeda     match chars.next() {
3243a8b546aSMiguel Ojeda         Some((_, ch)) if is_ident_start(ch) => {}
3253a8b546aSMiguel Ojeda         _ => return Err(Reject),
3263a8b546aSMiguel Ojeda     }
3273a8b546aSMiguel Ojeda 
3283a8b546aSMiguel Ojeda     let mut end = input.len();
3293a8b546aSMiguel Ojeda     for (i, ch) in chars {
3303a8b546aSMiguel Ojeda         if !is_ident_continue(ch) {
3313a8b546aSMiguel Ojeda             end = i;
3323a8b546aSMiguel Ojeda             break;
3333a8b546aSMiguel Ojeda         }
3343a8b546aSMiguel Ojeda     }
3353a8b546aSMiguel Ojeda 
3363a8b546aSMiguel Ojeda     Ok((input.advance(end), &input.rest[..end]))
3373a8b546aSMiguel Ojeda }
3383a8b546aSMiguel Ojeda 
literal(input: Cursor) -> PResult<Literal>3393a8b546aSMiguel Ojeda pub(crate) fn literal(input: Cursor) -> PResult<Literal> {
3403a8b546aSMiguel Ojeda     let rest = literal_nocapture(input)?;
3413a8b546aSMiguel Ojeda     let end = input.len() - rest.len();
3423a8b546aSMiguel Ojeda     Ok((rest, Literal::_new(input.rest[..end].to_string())))
3433a8b546aSMiguel Ojeda }
3443a8b546aSMiguel Ojeda 
literal_nocapture(input: Cursor) -> Result<Cursor, Reject>3453a8b546aSMiguel Ojeda fn literal_nocapture(input: Cursor) -> Result<Cursor, Reject> {
3463a8b546aSMiguel Ojeda     if let Ok(ok) = string(input) {
3473a8b546aSMiguel Ojeda         Ok(ok)
3483a8b546aSMiguel Ojeda     } else if let Ok(ok) = byte_string(input) {
3493a8b546aSMiguel Ojeda         Ok(ok)
3503a8b546aSMiguel Ojeda     } else if let Ok(ok) = c_string(input) {
3513a8b546aSMiguel Ojeda         Ok(ok)
3523a8b546aSMiguel Ojeda     } else if let Ok(ok) = byte(input) {
3533a8b546aSMiguel Ojeda         Ok(ok)
3543a8b546aSMiguel Ojeda     } else if let Ok(ok) = character(input) {
3553a8b546aSMiguel Ojeda         Ok(ok)
3563a8b546aSMiguel Ojeda     } else if let Ok(ok) = float(input) {
3573a8b546aSMiguel Ojeda         Ok(ok)
3583a8b546aSMiguel Ojeda     } else if let Ok(ok) = int(input) {
3593a8b546aSMiguel Ojeda         Ok(ok)
3603a8b546aSMiguel Ojeda     } else {
3613a8b546aSMiguel Ojeda         Err(Reject)
3623a8b546aSMiguel Ojeda     }
3633a8b546aSMiguel Ojeda }
3643a8b546aSMiguel Ojeda 
literal_suffix(input: Cursor) -> Cursor3653a8b546aSMiguel Ojeda fn literal_suffix(input: Cursor) -> Cursor {
3663a8b546aSMiguel Ojeda     match ident_not_raw(input) {
3673a8b546aSMiguel Ojeda         Ok((input, _)) => input,
3683a8b546aSMiguel Ojeda         Err(Reject) => input,
3693a8b546aSMiguel Ojeda     }
3703a8b546aSMiguel Ojeda }
3713a8b546aSMiguel Ojeda 
string(input: Cursor) -> Result<Cursor, Reject>3723a8b546aSMiguel Ojeda fn string(input: Cursor) -> Result<Cursor, Reject> {
3733a8b546aSMiguel Ojeda     if let Ok(input) = input.parse("\"") {
3743a8b546aSMiguel Ojeda         cooked_string(input)
3753a8b546aSMiguel Ojeda     } else if let Ok(input) = input.parse("r") {
3763a8b546aSMiguel Ojeda         raw_string(input)
3773a8b546aSMiguel Ojeda     } else {
3783a8b546aSMiguel Ojeda         Err(Reject)
3793a8b546aSMiguel Ojeda     }
3803a8b546aSMiguel Ojeda }
3813a8b546aSMiguel Ojeda 
cooked_string(mut input: Cursor) -> Result<Cursor, Reject>3823a8b546aSMiguel Ojeda fn cooked_string(mut input: Cursor) -> Result<Cursor, Reject> {
3833a8b546aSMiguel Ojeda     let mut chars = input.char_indices();
3843a8b546aSMiguel Ojeda 
3853a8b546aSMiguel Ojeda     while let Some((i, ch)) = chars.next() {
3863a8b546aSMiguel Ojeda         match ch {
3873a8b546aSMiguel Ojeda             '"' => {
3883a8b546aSMiguel Ojeda                 let input = input.advance(i + 1);
3893a8b546aSMiguel Ojeda                 return Ok(literal_suffix(input));
3903a8b546aSMiguel Ojeda             }
3913a8b546aSMiguel Ojeda             '\r' => match chars.next() {
3923a8b546aSMiguel Ojeda                 Some((_, '\n')) => {}
3933a8b546aSMiguel Ojeda                 _ => break,
3943a8b546aSMiguel Ojeda             },
3953a8b546aSMiguel Ojeda             '\\' => match chars.next() {
3963a8b546aSMiguel Ojeda                 Some((_, 'x')) => {
3973a8b546aSMiguel Ojeda                     backslash_x_char(&mut chars)?;
3983a8b546aSMiguel Ojeda                 }
3993a8b546aSMiguel Ojeda                 Some((_, 'n' | 'r' | 't' | '\\' | '\'' | '"' | '0')) => {}
4003a8b546aSMiguel Ojeda                 Some((_, 'u')) => {
4013a8b546aSMiguel Ojeda                     backslash_u(&mut chars)?;
4023a8b546aSMiguel Ojeda                 }
4033a8b546aSMiguel Ojeda                 Some((newline, ch @ ('\n' | '\r'))) => {
4043a8b546aSMiguel Ojeda                     input = input.advance(newline + 1);
4053a8b546aSMiguel Ojeda                     trailing_backslash(&mut input, ch as u8)?;
4063a8b546aSMiguel Ojeda                     chars = input.char_indices();
4073a8b546aSMiguel Ojeda                 }
4083a8b546aSMiguel Ojeda                 _ => break,
4093a8b546aSMiguel Ojeda             },
4103a8b546aSMiguel Ojeda             _ch => {}
4113a8b546aSMiguel Ojeda         }
4123a8b546aSMiguel Ojeda     }
4133a8b546aSMiguel Ojeda     Err(Reject)
4143a8b546aSMiguel Ojeda }
4153a8b546aSMiguel Ojeda 
raw_string(input: Cursor) -> Result<Cursor, Reject>4163a8b546aSMiguel Ojeda fn raw_string(input: Cursor) -> Result<Cursor, Reject> {
4173a8b546aSMiguel Ojeda     let (input, delimiter) = delimiter_of_raw_string(input)?;
4183a8b546aSMiguel Ojeda     let mut bytes = input.bytes().enumerate();
4193a8b546aSMiguel Ojeda     while let Some((i, byte)) = bytes.next() {
4203a8b546aSMiguel Ojeda         match byte {
4213a8b546aSMiguel Ojeda             b'"' if input.rest[i + 1..].starts_with(delimiter) => {
4223a8b546aSMiguel Ojeda                 let rest = input.advance(i + 1 + delimiter.len());
4233a8b546aSMiguel Ojeda                 return Ok(literal_suffix(rest));
4243a8b546aSMiguel Ojeda             }
4253a8b546aSMiguel Ojeda             b'\r' => match bytes.next() {
4263a8b546aSMiguel Ojeda                 Some((_, b'\n')) => {}
4273a8b546aSMiguel Ojeda                 _ => break,
4283a8b546aSMiguel Ojeda             },
4293a8b546aSMiguel Ojeda             _ => {}
4303a8b546aSMiguel Ojeda         }
4313a8b546aSMiguel Ojeda     }
4323a8b546aSMiguel Ojeda     Err(Reject)
4333a8b546aSMiguel Ojeda }
4343a8b546aSMiguel Ojeda 
byte_string(input: Cursor) -> Result<Cursor, Reject>4353a8b546aSMiguel Ojeda fn byte_string(input: Cursor) -> Result<Cursor, Reject> {
4363a8b546aSMiguel Ojeda     if let Ok(input) = input.parse("b\"") {
4373a8b546aSMiguel Ojeda         cooked_byte_string(input)
4383a8b546aSMiguel Ojeda     } else if let Ok(input) = input.parse("br") {
4393a8b546aSMiguel Ojeda         raw_byte_string(input)
4403a8b546aSMiguel Ojeda     } else {
4413a8b546aSMiguel Ojeda         Err(Reject)
4423a8b546aSMiguel Ojeda     }
4433a8b546aSMiguel Ojeda }
4443a8b546aSMiguel Ojeda 
cooked_byte_string(mut input: Cursor) -> Result<Cursor, Reject>4453a8b546aSMiguel Ojeda fn cooked_byte_string(mut input: Cursor) -> Result<Cursor, Reject> {
4463a8b546aSMiguel Ojeda     let mut bytes = input.bytes().enumerate();
4473a8b546aSMiguel Ojeda     while let Some((offset, b)) = bytes.next() {
4483a8b546aSMiguel Ojeda         match b {
4493a8b546aSMiguel Ojeda             b'"' => {
4503a8b546aSMiguel Ojeda                 let input = input.advance(offset + 1);
4513a8b546aSMiguel Ojeda                 return Ok(literal_suffix(input));
4523a8b546aSMiguel Ojeda             }
4533a8b546aSMiguel Ojeda             b'\r' => match bytes.next() {
4543a8b546aSMiguel Ojeda                 Some((_, b'\n')) => {}
4553a8b546aSMiguel Ojeda                 _ => break,
4563a8b546aSMiguel Ojeda             },
4573a8b546aSMiguel Ojeda             b'\\' => match bytes.next() {
4583a8b546aSMiguel Ojeda                 Some((_, b'x')) => {
4593a8b546aSMiguel Ojeda                     backslash_x_byte(&mut bytes)?;
4603a8b546aSMiguel Ojeda                 }
4613a8b546aSMiguel Ojeda                 Some((_, b'n' | b'r' | b't' | b'\\' | b'0' | b'\'' | b'"')) => {}
4623a8b546aSMiguel Ojeda                 Some((newline, b @ (b'\n' | b'\r'))) => {
4633a8b546aSMiguel Ojeda                     input = input.advance(newline + 1);
4643a8b546aSMiguel Ojeda                     trailing_backslash(&mut input, b)?;
4653a8b546aSMiguel Ojeda                     bytes = input.bytes().enumerate();
4663a8b546aSMiguel Ojeda                 }
4673a8b546aSMiguel Ojeda                 _ => break,
4683a8b546aSMiguel Ojeda             },
4693a8b546aSMiguel Ojeda             b if b.is_ascii() => {}
4703a8b546aSMiguel Ojeda             _ => break,
4713a8b546aSMiguel Ojeda         }
4723a8b546aSMiguel Ojeda     }
4733a8b546aSMiguel Ojeda     Err(Reject)
4743a8b546aSMiguel Ojeda }
4753a8b546aSMiguel Ojeda 
delimiter_of_raw_string(input: Cursor) -> PResult<&str>4763a8b546aSMiguel Ojeda fn delimiter_of_raw_string(input: Cursor) -> PResult<&str> {
4773a8b546aSMiguel Ojeda     for (i, byte) in input.bytes().enumerate() {
4783a8b546aSMiguel Ojeda         match byte {
4793a8b546aSMiguel Ojeda             b'"' => {
4803a8b546aSMiguel Ojeda                 if i > 255 {
4813a8b546aSMiguel Ojeda                     // https://github.com/rust-lang/rust/pull/95251
4823a8b546aSMiguel Ojeda                     return Err(Reject);
4833a8b546aSMiguel Ojeda                 }
4843a8b546aSMiguel Ojeda                 return Ok((input.advance(i + 1), &input.rest[..i]));
4853a8b546aSMiguel Ojeda             }
4863a8b546aSMiguel Ojeda             b'#' => {}
4873a8b546aSMiguel Ojeda             _ => break,
4883a8b546aSMiguel Ojeda         }
4893a8b546aSMiguel Ojeda     }
4903a8b546aSMiguel Ojeda     Err(Reject)
4913a8b546aSMiguel Ojeda }
4923a8b546aSMiguel Ojeda 
raw_byte_string(input: Cursor) -> Result<Cursor, Reject>4933a8b546aSMiguel Ojeda fn raw_byte_string(input: Cursor) -> Result<Cursor, Reject> {
4943a8b546aSMiguel Ojeda     let (input, delimiter) = delimiter_of_raw_string(input)?;
4953a8b546aSMiguel Ojeda     let mut bytes = input.bytes().enumerate();
4963a8b546aSMiguel Ojeda     while let Some((i, byte)) = bytes.next() {
4973a8b546aSMiguel Ojeda         match byte {
4983a8b546aSMiguel Ojeda             b'"' if input.rest[i + 1..].starts_with(delimiter) => {
4993a8b546aSMiguel Ojeda                 let rest = input.advance(i + 1 + delimiter.len());
5003a8b546aSMiguel Ojeda                 return Ok(literal_suffix(rest));
5013a8b546aSMiguel Ojeda             }
5023a8b546aSMiguel Ojeda             b'\r' => match bytes.next() {
5033a8b546aSMiguel Ojeda                 Some((_, b'\n')) => {}
5043a8b546aSMiguel Ojeda                 _ => break,
5053a8b546aSMiguel Ojeda             },
5063a8b546aSMiguel Ojeda             other => {
5073a8b546aSMiguel Ojeda                 if !other.is_ascii() {
5083a8b546aSMiguel Ojeda                     break;
5093a8b546aSMiguel Ojeda                 }
5103a8b546aSMiguel Ojeda             }
5113a8b546aSMiguel Ojeda         }
5123a8b546aSMiguel Ojeda     }
5133a8b546aSMiguel Ojeda     Err(Reject)
5143a8b546aSMiguel Ojeda }
5153a8b546aSMiguel Ojeda 
c_string(input: Cursor) -> Result<Cursor, Reject>5163a8b546aSMiguel Ojeda fn c_string(input: Cursor) -> Result<Cursor, Reject> {
5173a8b546aSMiguel Ojeda     if let Ok(input) = input.parse("c\"") {
5183a8b546aSMiguel Ojeda         cooked_c_string(input)
5193a8b546aSMiguel Ojeda     } else if let Ok(input) = input.parse("cr") {
5203a8b546aSMiguel Ojeda         raw_c_string(input)
5213a8b546aSMiguel Ojeda     } else {
5223a8b546aSMiguel Ojeda         Err(Reject)
5233a8b546aSMiguel Ojeda     }
5243a8b546aSMiguel Ojeda }
5253a8b546aSMiguel Ojeda 
raw_c_string(input: Cursor) -> Result<Cursor, Reject>5263a8b546aSMiguel Ojeda fn raw_c_string(input: Cursor) -> Result<Cursor, Reject> {
5273a8b546aSMiguel Ojeda     let (input, delimiter) = delimiter_of_raw_string(input)?;
5283a8b546aSMiguel Ojeda     let mut bytes = input.bytes().enumerate();
5293a8b546aSMiguel Ojeda     while let Some((i, byte)) = bytes.next() {
5303a8b546aSMiguel Ojeda         match byte {
5313a8b546aSMiguel Ojeda             b'"' if input.rest[i + 1..].starts_with(delimiter) => {
5323a8b546aSMiguel Ojeda                 let rest = input.advance(i + 1 + delimiter.len());
5333a8b546aSMiguel Ojeda                 return Ok(literal_suffix(rest));
5343a8b546aSMiguel Ojeda             }
5353a8b546aSMiguel Ojeda             b'\r' => match bytes.next() {
5363a8b546aSMiguel Ojeda                 Some((_, b'\n')) => {}
5373a8b546aSMiguel Ojeda                 _ => break,
5383a8b546aSMiguel Ojeda             },
5393a8b546aSMiguel Ojeda             b'\0' => break,
5403a8b546aSMiguel Ojeda             _ => {}
5413a8b546aSMiguel Ojeda         }
5423a8b546aSMiguel Ojeda     }
5433a8b546aSMiguel Ojeda     Err(Reject)
5443a8b546aSMiguel Ojeda }
5453a8b546aSMiguel Ojeda 
cooked_c_string(mut input: Cursor) -> Result<Cursor, Reject>5463a8b546aSMiguel Ojeda fn cooked_c_string(mut input: Cursor) -> Result<Cursor, Reject> {
5473a8b546aSMiguel Ojeda     let mut chars = input.char_indices();
5483a8b546aSMiguel Ojeda 
5493a8b546aSMiguel Ojeda     while let Some((i, ch)) = chars.next() {
5503a8b546aSMiguel Ojeda         match ch {
5513a8b546aSMiguel Ojeda             '"' => {
5523a8b546aSMiguel Ojeda                 let input = input.advance(i + 1);
5533a8b546aSMiguel Ojeda                 return Ok(literal_suffix(input));
5543a8b546aSMiguel Ojeda             }
5553a8b546aSMiguel Ojeda             '\r' => match chars.next() {
5563a8b546aSMiguel Ojeda                 Some((_, '\n')) => {}
5573a8b546aSMiguel Ojeda                 _ => break,
5583a8b546aSMiguel Ojeda             },
5593a8b546aSMiguel Ojeda             '\\' => match chars.next() {
5603a8b546aSMiguel Ojeda                 Some((_, 'x')) => {
5613a8b546aSMiguel Ojeda                     backslash_x_nonzero(&mut chars)?;
5623a8b546aSMiguel Ojeda                 }
5633a8b546aSMiguel Ojeda                 Some((_, 'n' | 'r' | 't' | '\\' | '\'' | '"')) => {}
5643a8b546aSMiguel Ojeda                 Some((_, 'u')) => {
5653a8b546aSMiguel Ojeda                     if backslash_u(&mut chars)? == '\0' {
5663a8b546aSMiguel Ojeda                         break;
5673a8b546aSMiguel Ojeda                     }
5683a8b546aSMiguel Ojeda                 }
5693a8b546aSMiguel Ojeda                 Some((newline, ch @ ('\n' | '\r'))) => {
5703a8b546aSMiguel Ojeda                     input = input.advance(newline + 1);
5713a8b546aSMiguel Ojeda                     trailing_backslash(&mut input, ch as u8)?;
5723a8b546aSMiguel Ojeda                     chars = input.char_indices();
5733a8b546aSMiguel Ojeda                 }
5743a8b546aSMiguel Ojeda                 _ => break,
5753a8b546aSMiguel Ojeda             },
5763a8b546aSMiguel Ojeda             '\0' => break,
5773a8b546aSMiguel Ojeda             _ch => {}
5783a8b546aSMiguel Ojeda         }
5793a8b546aSMiguel Ojeda     }
5803a8b546aSMiguel Ojeda     Err(Reject)
5813a8b546aSMiguel Ojeda }
5823a8b546aSMiguel Ojeda 
byte(input: Cursor) -> Result<Cursor, Reject>5833a8b546aSMiguel Ojeda fn byte(input: Cursor) -> Result<Cursor, Reject> {
5843a8b546aSMiguel Ojeda     let input = input.parse("b'")?;
5853a8b546aSMiguel Ojeda     let mut bytes = input.bytes().enumerate();
5863a8b546aSMiguel Ojeda     let ok = match bytes.next().map(|(_, b)| b) {
5873a8b546aSMiguel Ojeda         Some(b'\\') => match bytes.next().map(|(_, b)| b) {
5883a8b546aSMiguel Ojeda             Some(b'x') => backslash_x_byte(&mut bytes).is_ok(),
5893a8b546aSMiguel Ojeda             Some(b'n' | b'r' | b't' | b'\\' | b'0' | b'\'' | b'"') => true,
5903a8b546aSMiguel Ojeda             _ => false,
5913a8b546aSMiguel Ojeda         },
5923a8b546aSMiguel Ojeda         b => b.is_some(),
5933a8b546aSMiguel Ojeda     };
5943a8b546aSMiguel Ojeda     if !ok {
5953a8b546aSMiguel Ojeda         return Err(Reject);
5963a8b546aSMiguel Ojeda     }
5973a8b546aSMiguel Ojeda     let (offset, _) = bytes.next().ok_or(Reject)?;
5983a8b546aSMiguel Ojeda     if !input.chars().as_str().is_char_boundary(offset) {
5993a8b546aSMiguel Ojeda         return Err(Reject);
6003a8b546aSMiguel Ojeda     }
6013a8b546aSMiguel Ojeda     let input = input.advance(offset).parse("'")?;
6023a8b546aSMiguel Ojeda     Ok(literal_suffix(input))
6033a8b546aSMiguel Ojeda }
6043a8b546aSMiguel Ojeda 
character(input: Cursor) -> Result<Cursor, Reject>6053a8b546aSMiguel Ojeda fn character(input: Cursor) -> Result<Cursor, Reject> {
6063a8b546aSMiguel Ojeda     let input = input.parse("'")?;
6073a8b546aSMiguel Ojeda     let mut chars = input.char_indices();
6083a8b546aSMiguel Ojeda     let ok = match chars.next().map(|(_, ch)| ch) {
6093a8b546aSMiguel Ojeda         Some('\\') => match chars.next().map(|(_, ch)| ch) {
6103a8b546aSMiguel Ojeda             Some('x') => backslash_x_char(&mut chars).is_ok(),
6113a8b546aSMiguel Ojeda             Some('u') => backslash_u(&mut chars).is_ok(),
6123a8b546aSMiguel Ojeda             Some('n' | 'r' | 't' | '\\' | '0' | '\'' | '"') => true,
6133a8b546aSMiguel Ojeda             _ => false,
6143a8b546aSMiguel Ojeda         },
6153a8b546aSMiguel Ojeda         ch => ch.is_some(),
6163a8b546aSMiguel Ojeda     };
6173a8b546aSMiguel Ojeda     if !ok {
6183a8b546aSMiguel Ojeda         return Err(Reject);
6193a8b546aSMiguel Ojeda     }
6203a8b546aSMiguel Ojeda     let (idx, _) = chars.next().ok_or(Reject)?;
6213a8b546aSMiguel Ojeda     let input = input.advance(idx).parse("'")?;
6223a8b546aSMiguel Ojeda     Ok(literal_suffix(input))
6233a8b546aSMiguel Ojeda }
6243a8b546aSMiguel Ojeda 
6253a8b546aSMiguel Ojeda macro_rules! next_ch {
6263a8b546aSMiguel Ojeda     ($chars:ident @ $pat:pat) => {
6273a8b546aSMiguel Ojeda         match $chars.next() {
6283a8b546aSMiguel Ojeda             Some((_, ch)) => match ch {
6293a8b546aSMiguel Ojeda                 $pat => ch,
6303a8b546aSMiguel Ojeda                 _ => return Err(Reject),
6313a8b546aSMiguel Ojeda             },
6323a8b546aSMiguel Ojeda             None => return Err(Reject),
6333a8b546aSMiguel Ojeda         }
6343a8b546aSMiguel Ojeda     };
6353a8b546aSMiguel Ojeda }
6363a8b546aSMiguel Ojeda 
backslash_x_char<I>(chars: &mut I) -> Result<(), Reject> where I: Iterator<Item = (usize, char)>,6373a8b546aSMiguel Ojeda fn backslash_x_char<I>(chars: &mut I) -> Result<(), Reject>
6383a8b546aSMiguel Ojeda where
6393a8b546aSMiguel Ojeda     I: Iterator<Item = (usize, char)>,
6403a8b546aSMiguel Ojeda {
6413a8b546aSMiguel Ojeda     next_ch!(chars @ '0'..='7');
6423a8b546aSMiguel Ojeda     next_ch!(chars @ '0'..='9' | 'a'..='f' | 'A'..='F');
6433a8b546aSMiguel Ojeda     Ok(())
6443a8b546aSMiguel Ojeda }
6453a8b546aSMiguel Ojeda 
backslash_x_byte<I>(chars: &mut I) -> Result<(), Reject> where I: Iterator<Item = (usize, u8)>,6463a8b546aSMiguel Ojeda fn backslash_x_byte<I>(chars: &mut I) -> Result<(), Reject>
6473a8b546aSMiguel Ojeda where
6483a8b546aSMiguel Ojeda     I: Iterator<Item = (usize, u8)>,
6493a8b546aSMiguel Ojeda {
6503a8b546aSMiguel Ojeda     next_ch!(chars @ b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F');
6513a8b546aSMiguel Ojeda     next_ch!(chars @ b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F');
6523a8b546aSMiguel Ojeda     Ok(())
6533a8b546aSMiguel Ojeda }
6543a8b546aSMiguel Ojeda 
backslash_x_nonzero<I>(chars: &mut I) -> Result<(), Reject> where I: Iterator<Item = (usize, char)>,6553a8b546aSMiguel Ojeda fn backslash_x_nonzero<I>(chars: &mut I) -> Result<(), Reject>
6563a8b546aSMiguel Ojeda where
6573a8b546aSMiguel Ojeda     I: Iterator<Item = (usize, char)>,
6583a8b546aSMiguel Ojeda {
6593a8b546aSMiguel Ojeda     let first = next_ch!(chars @ '0'..='9' | 'a'..='f' | 'A'..='F');
6603a8b546aSMiguel Ojeda     let second = next_ch!(chars @ '0'..='9' | 'a'..='f' | 'A'..='F');
6613a8b546aSMiguel Ojeda     if first == '0' && second == '0' {
6623a8b546aSMiguel Ojeda         Err(Reject)
6633a8b546aSMiguel Ojeda     } else {
6643a8b546aSMiguel Ojeda         Ok(())
6653a8b546aSMiguel Ojeda     }
6663a8b546aSMiguel Ojeda }
6673a8b546aSMiguel Ojeda 
backslash_u<I>(chars: &mut I) -> Result<char, Reject> where I: Iterator<Item = (usize, char)>,6683a8b546aSMiguel Ojeda fn backslash_u<I>(chars: &mut I) -> Result<char, Reject>
6693a8b546aSMiguel Ojeda where
6703a8b546aSMiguel Ojeda     I: Iterator<Item = (usize, char)>,
6713a8b546aSMiguel Ojeda {
6723a8b546aSMiguel Ojeda     next_ch!(chars @ '{');
6733a8b546aSMiguel Ojeda     let mut value = 0;
6743a8b546aSMiguel Ojeda     let mut len = 0;
6753a8b546aSMiguel Ojeda     for (_, ch) in chars {
6763a8b546aSMiguel Ojeda         let digit = match ch {
6773a8b546aSMiguel Ojeda             '0'..='9' => ch as u8 - b'0',
6783a8b546aSMiguel Ojeda             'a'..='f' => 10 + ch as u8 - b'a',
6793a8b546aSMiguel Ojeda             'A'..='F' => 10 + ch as u8 - b'A',
6803a8b546aSMiguel Ojeda             '_' if len > 0 => continue,
6813a8b546aSMiguel Ojeda             '}' if len > 0 => return char::from_u32(value).ok_or(Reject),
6823a8b546aSMiguel Ojeda             _ => break,
6833a8b546aSMiguel Ojeda         };
6843a8b546aSMiguel Ojeda         if len == 6 {
6853a8b546aSMiguel Ojeda             break;
6863a8b546aSMiguel Ojeda         }
6873a8b546aSMiguel Ojeda         value *= 0x10;
6883a8b546aSMiguel Ojeda         value += u32::from(digit);
6893a8b546aSMiguel Ojeda         len += 1;
6903a8b546aSMiguel Ojeda     }
6913a8b546aSMiguel Ojeda     Err(Reject)
6923a8b546aSMiguel Ojeda }
6933a8b546aSMiguel Ojeda 
trailing_backslash(input: &mut Cursor, mut last: u8) -> Result<(), Reject>6943a8b546aSMiguel Ojeda fn trailing_backslash(input: &mut Cursor, mut last: u8) -> Result<(), Reject> {
6953a8b546aSMiguel Ojeda     let mut whitespace = input.bytes().enumerate();
6963a8b546aSMiguel Ojeda     loop {
6973a8b546aSMiguel Ojeda         if last == b'\r' && whitespace.next().map_or(true, |(_, b)| b != b'\n') {
6983a8b546aSMiguel Ojeda             return Err(Reject);
6993a8b546aSMiguel Ojeda         }
7003a8b546aSMiguel Ojeda         match whitespace.next() {
7013a8b546aSMiguel Ojeda             Some((_, b @ (b' ' | b'\t' | b'\n' | b'\r'))) => {
7023a8b546aSMiguel Ojeda                 last = b;
7033a8b546aSMiguel Ojeda             }
7043a8b546aSMiguel Ojeda             Some((offset, _)) => {
7053a8b546aSMiguel Ojeda                 *input = input.advance(offset);
7063a8b546aSMiguel Ojeda                 return Ok(());
7073a8b546aSMiguel Ojeda             }
7083a8b546aSMiguel Ojeda             None => return Err(Reject),
7093a8b546aSMiguel Ojeda         }
7103a8b546aSMiguel Ojeda     }
7113a8b546aSMiguel Ojeda }
7123a8b546aSMiguel Ojeda 
float(input: Cursor) -> Result<Cursor, Reject>7133a8b546aSMiguel Ojeda fn float(input: Cursor) -> Result<Cursor, Reject> {
7143a8b546aSMiguel Ojeda     let mut rest = float_digits(input)?;
7153a8b546aSMiguel Ojeda     if let Some(ch) = rest.chars().next() {
7163a8b546aSMiguel Ojeda         if is_ident_start(ch) {
7173a8b546aSMiguel Ojeda             rest = ident_not_raw(rest)?.0;
7183a8b546aSMiguel Ojeda         }
7193a8b546aSMiguel Ojeda     }
7203a8b546aSMiguel Ojeda     word_break(rest)
7213a8b546aSMiguel Ojeda }
7223a8b546aSMiguel Ojeda 
float_digits(input: Cursor) -> Result<Cursor, Reject>7233a8b546aSMiguel Ojeda fn float_digits(input: Cursor) -> Result<Cursor, Reject> {
7243a8b546aSMiguel Ojeda     let mut chars = input.chars().peekable();
7253a8b546aSMiguel Ojeda     match chars.next() {
7263a8b546aSMiguel Ojeda         Some(ch) if '0' <= ch && ch <= '9' => {}
7273a8b546aSMiguel Ojeda         _ => return Err(Reject),
7283a8b546aSMiguel Ojeda     }
7293a8b546aSMiguel Ojeda 
7303a8b546aSMiguel Ojeda     let mut len = 1;
7313a8b546aSMiguel Ojeda     let mut has_dot = false;
7323a8b546aSMiguel Ojeda     let mut has_exp = false;
7333a8b546aSMiguel Ojeda     while let Some(&ch) = chars.peek() {
7343a8b546aSMiguel Ojeda         match ch {
7353a8b546aSMiguel Ojeda             '0'..='9' | '_' => {
7363a8b546aSMiguel Ojeda                 chars.next();
7373a8b546aSMiguel Ojeda                 len += 1;
7383a8b546aSMiguel Ojeda             }
7393a8b546aSMiguel Ojeda             '.' => {
7403a8b546aSMiguel Ojeda                 if has_dot {
7413a8b546aSMiguel Ojeda                     break;
7423a8b546aSMiguel Ojeda                 }
7433a8b546aSMiguel Ojeda                 chars.next();
7443a8b546aSMiguel Ojeda                 if chars
7453a8b546aSMiguel Ojeda                     .peek()
7463a8b546aSMiguel Ojeda                     .map_or(false, |&ch| ch == '.' || is_ident_start(ch))
7473a8b546aSMiguel Ojeda                 {
7483a8b546aSMiguel Ojeda                     return Err(Reject);
7493a8b546aSMiguel Ojeda                 }
7503a8b546aSMiguel Ojeda                 len += 1;
7513a8b546aSMiguel Ojeda                 has_dot = true;
7523a8b546aSMiguel Ojeda             }
7533a8b546aSMiguel Ojeda             'e' | 'E' => {
7543a8b546aSMiguel Ojeda                 chars.next();
7553a8b546aSMiguel Ojeda                 len += 1;
7563a8b546aSMiguel Ojeda                 has_exp = true;
7573a8b546aSMiguel Ojeda                 break;
7583a8b546aSMiguel Ojeda             }
7593a8b546aSMiguel Ojeda             _ => break,
7603a8b546aSMiguel Ojeda         }
7613a8b546aSMiguel Ojeda     }
7623a8b546aSMiguel Ojeda 
7633a8b546aSMiguel Ojeda     if !(has_dot || has_exp) {
7643a8b546aSMiguel Ojeda         return Err(Reject);
7653a8b546aSMiguel Ojeda     }
7663a8b546aSMiguel Ojeda 
7673a8b546aSMiguel Ojeda     if has_exp {
7683a8b546aSMiguel Ojeda         let token_before_exp = if has_dot {
7693a8b546aSMiguel Ojeda             Ok(input.advance(len - 1))
7703a8b546aSMiguel Ojeda         } else {
7713a8b546aSMiguel Ojeda             Err(Reject)
7723a8b546aSMiguel Ojeda         };
7733a8b546aSMiguel Ojeda         let mut has_sign = false;
7743a8b546aSMiguel Ojeda         let mut has_exp_value = false;
7753a8b546aSMiguel Ojeda         while let Some(&ch) = chars.peek() {
7763a8b546aSMiguel Ojeda             match ch {
7773a8b546aSMiguel Ojeda                 '+' | '-' => {
7783a8b546aSMiguel Ojeda                     if has_exp_value {
7793a8b546aSMiguel Ojeda                         break;
7803a8b546aSMiguel Ojeda                     }
7813a8b546aSMiguel Ojeda                     if has_sign {
7823a8b546aSMiguel Ojeda                         return token_before_exp;
7833a8b546aSMiguel Ojeda                     }
7843a8b546aSMiguel Ojeda                     chars.next();
7853a8b546aSMiguel Ojeda                     len += 1;
7863a8b546aSMiguel Ojeda                     has_sign = true;
7873a8b546aSMiguel Ojeda                 }
7883a8b546aSMiguel Ojeda                 '0'..='9' => {
7893a8b546aSMiguel Ojeda                     chars.next();
7903a8b546aSMiguel Ojeda                     len += 1;
7913a8b546aSMiguel Ojeda                     has_exp_value = true;
7923a8b546aSMiguel Ojeda                 }
7933a8b546aSMiguel Ojeda                 '_' => {
7943a8b546aSMiguel Ojeda                     chars.next();
7953a8b546aSMiguel Ojeda                     len += 1;
7963a8b546aSMiguel Ojeda                 }
7973a8b546aSMiguel Ojeda                 _ => break,
7983a8b546aSMiguel Ojeda             }
7993a8b546aSMiguel Ojeda         }
8003a8b546aSMiguel Ojeda         if !has_exp_value {
8013a8b546aSMiguel Ojeda             return token_before_exp;
8023a8b546aSMiguel Ojeda         }
8033a8b546aSMiguel Ojeda     }
8043a8b546aSMiguel Ojeda 
8053a8b546aSMiguel Ojeda     Ok(input.advance(len))
8063a8b546aSMiguel Ojeda }
8073a8b546aSMiguel Ojeda 
int(input: Cursor) -> Result<Cursor, Reject>8083a8b546aSMiguel Ojeda fn int(input: Cursor) -> Result<Cursor, Reject> {
8093a8b546aSMiguel Ojeda     let mut rest = digits(input)?;
8103a8b546aSMiguel Ojeda     if let Some(ch) = rest.chars().next() {
8113a8b546aSMiguel Ojeda         if is_ident_start(ch) {
8123a8b546aSMiguel Ojeda             rest = ident_not_raw(rest)?.0;
8133a8b546aSMiguel Ojeda         }
8143a8b546aSMiguel Ojeda     }
8153a8b546aSMiguel Ojeda     word_break(rest)
8163a8b546aSMiguel Ojeda }
8173a8b546aSMiguel Ojeda 
digits(mut input: Cursor) -> Result<Cursor, Reject>8183a8b546aSMiguel Ojeda fn digits(mut input: Cursor) -> Result<Cursor, Reject> {
8193a8b546aSMiguel Ojeda     let base = if input.starts_with("0x") {
8203a8b546aSMiguel Ojeda         input = input.advance(2);
8213a8b546aSMiguel Ojeda         16
8223a8b546aSMiguel Ojeda     } else if input.starts_with("0o") {
8233a8b546aSMiguel Ojeda         input = input.advance(2);
8243a8b546aSMiguel Ojeda         8
8253a8b546aSMiguel Ojeda     } else if input.starts_with("0b") {
8263a8b546aSMiguel Ojeda         input = input.advance(2);
8273a8b546aSMiguel Ojeda         2
8283a8b546aSMiguel Ojeda     } else {
8293a8b546aSMiguel Ojeda         10
8303a8b546aSMiguel Ojeda     };
8313a8b546aSMiguel Ojeda 
8323a8b546aSMiguel Ojeda     let mut len = 0;
8333a8b546aSMiguel Ojeda     let mut empty = true;
8343a8b546aSMiguel Ojeda     for b in input.bytes() {
8353a8b546aSMiguel Ojeda         match b {
8363a8b546aSMiguel Ojeda             b'0'..=b'9' => {
8373a8b546aSMiguel Ojeda                 let digit = (b - b'0') as u64;
8383a8b546aSMiguel Ojeda                 if digit >= base {
8393a8b546aSMiguel Ojeda                     return Err(Reject);
8403a8b546aSMiguel Ojeda                 }
8413a8b546aSMiguel Ojeda             }
8423a8b546aSMiguel Ojeda             b'a'..=b'f' => {
8433a8b546aSMiguel Ojeda                 let digit = 10 + (b - b'a') as u64;
8443a8b546aSMiguel Ojeda                 if digit >= base {
8453a8b546aSMiguel Ojeda                     break;
8463a8b546aSMiguel Ojeda                 }
8473a8b546aSMiguel Ojeda             }
8483a8b546aSMiguel Ojeda             b'A'..=b'F' => {
8493a8b546aSMiguel Ojeda                 let digit = 10 + (b - b'A') as u64;
8503a8b546aSMiguel Ojeda                 if digit >= base {
8513a8b546aSMiguel Ojeda                     break;
8523a8b546aSMiguel Ojeda                 }
8533a8b546aSMiguel Ojeda             }
8543a8b546aSMiguel Ojeda             b'_' => {
8553a8b546aSMiguel Ojeda                 if empty && base == 10 {
8563a8b546aSMiguel Ojeda                     return Err(Reject);
8573a8b546aSMiguel Ojeda                 }
8583a8b546aSMiguel Ojeda                 len += 1;
8593a8b546aSMiguel Ojeda                 continue;
8603a8b546aSMiguel Ojeda             }
8613a8b546aSMiguel Ojeda             _ => break,
8623a8b546aSMiguel Ojeda         }
8633a8b546aSMiguel Ojeda         len += 1;
8643a8b546aSMiguel Ojeda         empty = false;
8653a8b546aSMiguel Ojeda     }
8663a8b546aSMiguel Ojeda     if empty {
8673a8b546aSMiguel Ojeda         Err(Reject)
8683a8b546aSMiguel Ojeda     } else {
8693a8b546aSMiguel Ojeda         Ok(input.advance(len))
8703a8b546aSMiguel Ojeda     }
8713a8b546aSMiguel Ojeda }
8723a8b546aSMiguel Ojeda 
punct(input: Cursor) -> PResult<Punct>8733a8b546aSMiguel Ojeda fn punct(input: Cursor) -> PResult<Punct> {
8743a8b546aSMiguel Ojeda     let (rest, ch) = punct_char(input)?;
8753a8b546aSMiguel Ojeda     if ch == '\'' {
8763a8b546aSMiguel Ojeda         let (after_lifetime, _ident) = ident_any(rest)?;
8773a8b546aSMiguel Ojeda         if after_lifetime.starts_with_char('\'')
8783a8b546aSMiguel Ojeda             || (after_lifetime.starts_with_char('#') && !rest.starts_with("r#"))
8793a8b546aSMiguel Ojeda         {
8803a8b546aSMiguel Ojeda             Err(Reject)
8813a8b546aSMiguel Ojeda         } else {
8823a8b546aSMiguel Ojeda             Ok((rest, Punct::new('\'', Spacing::Joint)))
8833a8b546aSMiguel Ojeda         }
8843a8b546aSMiguel Ojeda     } else {
8853a8b546aSMiguel Ojeda         let kind = match punct_char(rest) {
8863a8b546aSMiguel Ojeda             Ok(_) => Spacing::Joint,
8873a8b546aSMiguel Ojeda             Err(Reject) => Spacing::Alone,
8883a8b546aSMiguel Ojeda         };
8893a8b546aSMiguel Ojeda         Ok((rest, Punct::new(ch, kind)))
8903a8b546aSMiguel Ojeda     }
8913a8b546aSMiguel Ojeda }
8923a8b546aSMiguel Ojeda 
punct_char(input: Cursor) -> PResult<char>8933a8b546aSMiguel Ojeda fn punct_char(input: Cursor) -> PResult<char> {
8943a8b546aSMiguel Ojeda     if input.starts_with("//") || input.starts_with("/*") {
8953a8b546aSMiguel Ojeda         // Do not accept `/` of a comment as a punct.
8963a8b546aSMiguel Ojeda         return Err(Reject);
8973a8b546aSMiguel Ojeda     }
8983a8b546aSMiguel Ojeda 
8993a8b546aSMiguel Ojeda     let mut chars = input.chars();
9003a8b546aSMiguel Ojeda     let first = match chars.next() {
9013a8b546aSMiguel Ojeda         Some(ch) => ch,
9023a8b546aSMiguel Ojeda         None => {
9033a8b546aSMiguel Ojeda             return Err(Reject);
9043a8b546aSMiguel Ojeda         }
9053a8b546aSMiguel Ojeda     };
9063a8b546aSMiguel Ojeda     let recognized = "~!@#$%^&*-=+|;:,<.>/?'";
9073a8b546aSMiguel Ojeda     if recognized.contains(first) {
9083a8b546aSMiguel Ojeda         Ok((input.advance(first.len_utf8()), first))
9093a8b546aSMiguel Ojeda     } else {
9103a8b546aSMiguel Ojeda         Err(Reject)
9113a8b546aSMiguel Ojeda     }
9123a8b546aSMiguel Ojeda }
9133a8b546aSMiguel Ojeda 
doc_comment<'a>(input: Cursor<'a>, trees: &mut TokenStreamBuilder) -> PResult<'a, ()>9143a8b546aSMiguel Ojeda fn doc_comment<'a>(input: Cursor<'a>, trees: &mut TokenStreamBuilder) -> PResult<'a, ()> {
9153a8b546aSMiguel Ojeda     #[cfg(span_locations)]
9163a8b546aSMiguel Ojeda     let lo = input.off;
9173a8b546aSMiguel Ojeda     let (rest, (comment, inner)) = doc_comment_contents(input)?;
9183a8b546aSMiguel Ojeda     let fallback_span = Span {
9193a8b546aSMiguel Ojeda         #[cfg(span_locations)]
9203a8b546aSMiguel Ojeda         lo,
9213a8b546aSMiguel Ojeda         #[cfg(span_locations)]
9223a8b546aSMiguel Ojeda         hi: rest.off,
9233a8b546aSMiguel Ojeda     };
9243a8b546aSMiguel Ojeda     let span = crate::Span::_new_fallback(fallback_span);
9253a8b546aSMiguel Ojeda 
9263a8b546aSMiguel Ojeda     let mut scan_for_bare_cr = comment;
9273a8b546aSMiguel Ojeda     while let Some(cr) = scan_for_bare_cr.find('\r') {
9283a8b546aSMiguel Ojeda         let rest = &scan_for_bare_cr[cr + 1..];
9293a8b546aSMiguel Ojeda         if !rest.starts_with('\n') {
9303a8b546aSMiguel Ojeda             return Err(Reject);
9313a8b546aSMiguel Ojeda         }
9323a8b546aSMiguel Ojeda         scan_for_bare_cr = rest;
9333a8b546aSMiguel Ojeda     }
9343a8b546aSMiguel Ojeda 
9353a8b546aSMiguel Ojeda     let mut pound = Punct::new('#', Spacing::Alone);
9363a8b546aSMiguel Ojeda     pound.set_span(span);
9373a8b546aSMiguel Ojeda     trees.push_token_from_parser(TokenTree::Punct(pound));
9383a8b546aSMiguel Ojeda 
9393a8b546aSMiguel Ojeda     if inner {
9403a8b546aSMiguel Ojeda         let mut bang = Punct::new('!', Spacing::Alone);
9413a8b546aSMiguel Ojeda         bang.set_span(span);
9423a8b546aSMiguel Ojeda         trees.push_token_from_parser(TokenTree::Punct(bang));
9433a8b546aSMiguel Ojeda     }
9443a8b546aSMiguel Ojeda 
9453a8b546aSMiguel Ojeda     let doc_ident = crate::Ident::_new_fallback(Ident::new_unchecked("doc", fallback_span));
9463a8b546aSMiguel Ojeda     let mut equal = Punct::new('=', Spacing::Alone);
9473a8b546aSMiguel Ojeda     equal.set_span(span);
9483a8b546aSMiguel Ojeda     let mut literal = crate::Literal::_new_fallback(Literal::string(comment));
9493a8b546aSMiguel Ojeda     literal.set_span(span);
9503a8b546aSMiguel Ojeda     let mut bracketed = TokenStreamBuilder::with_capacity(3);
9513a8b546aSMiguel Ojeda     bracketed.push_token_from_parser(TokenTree::Ident(doc_ident));
9523a8b546aSMiguel Ojeda     bracketed.push_token_from_parser(TokenTree::Punct(equal));
9533a8b546aSMiguel Ojeda     bracketed.push_token_from_parser(TokenTree::Literal(literal));
9543a8b546aSMiguel Ojeda     let group = Group::new(Delimiter::Bracket, bracketed.build());
9553a8b546aSMiguel Ojeda     let mut group = crate::Group::_new_fallback(group);
9563a8b546aSMiguel Ojeda     group.set_span(span);
9573a8b546aSMiguel Ojeda     trees.push_token_from_parser(TokenTree::Group(group));
9583a8b546aSMiguel Ojeda 
9593a8b546aSMiguel Ojeda     Ok((rest, ()))
9603a8b546aSMiguel Ojeda }
9613a8b546aSMiguel Ojeda 
doc_comment_contents(input: Cursor) -> PResult<(&str, bool)>9623a8b546aSMiguel Ojeda fn doc_comment_contents(input: Cursor) -> PResult<(&str, bool)> {
9633a8b546aSMiguel Ojeda     if input.starts_with("//!") {
9643a8b546aSMiguel Ojeda         let input = input.advance(3);
9653a8b546aSMiguel Ojeda         let (input, s) = take_until_newline_or_eof(input);
9663a8b546aSMiguel Ojeda         Ok((input, (s, true)))
9673a8b546aSMiguel Ojeda     } else if input.starts_with("/*!") {
9683a8b546aSMiguel Ojeda         let (input, s) = block_comment(input)?;
9693a8b546aSMiguel Ojeda         Ok((input, (&s[3..s.len() - 2], true)))
9703a8b546aSMiguel Ojeda     } else if input.starts_with("///") {
9713a8b546aSMiguel Ojeda         let input = input.advance(3);
9723a8b546aSMiguel Ojeda         if input.starts_with_char('/') {
9733a8b546aSMiguel Ojeda             return Err(Reject);
9743a8b546aSMiguel Ojeda         }
9753a8b546aSMiguel Ojeda         let (input, s) = take_until_newline_or_eof(input);
9763a8b546aSMiguel Ojeda         Ok((input, (s, false)))
9773a8b546aSMiguel Ojeda     } else if input.starts_with("/**") && !input.rest[3..].starts_with('*') {
9783a8b546aSMiguel Ojeda         let (input, s) = block_comment(input)?;
9793a8b546aSMiguel Ojeda         Ok((input, (&s[3..s.len() - 2], false)))
9803a8b546aSMiguel Ojeda     } else {
9813a8b546aSMiguel Ojeda         Err(Reject)
9823a8b546aSMiguel Ojeda     }
9833a8b546aSMiguel Ojeda }
9843a8b546aSMiguel Ojeda 
take_until_newline_or_eof(input: Cursor) -> (Cursor, &str)9853a8b546aSMiguel Ojeda fn take_until_newline_or_eof(input: Cursor) -> (Cursor, &str) {
9863a8b546aSMiguel Ojeda     let chars = input.char_indices();
9873a8b546aSMiguel Ojeda 
9883a8b546aSMiguel Ojeda     for (i, ch) in chars {
9893a8b546aSMiguel Ojeda         if ch == '\n' {
9903a8b546aSMiguel Ojeda             return (input.advance(i), &input.rest[..i]);
9913a8b546aSMiguel Ojeda         } else if ch == '\r' && input.rest[i + 1..].starts_with('\n') {
9923a8b546aSMiguel Ojeda             return (input.advance(i + 1), &input.rest[..i]);
9933a8b546aSMiguel Ojeda         }
9943a8b546aSMiguel Ojeda     }
9953a8b546aSMiguel Ojeda 
9963a8b546aSMiguel Ojeda     (input.advance(input.len()), input.rest)
9973a8b546aSMiguel Ojeda }
998