|  | use crate::fallback::{ | 
|  | self, is_ident_continue, is_ident_start, Group, LexError, Literal, Span, TokenStream, | 
|  | TokenStreamBuilder, | 
|  | }; | 
|  | use crate::{Delimiter, Punct, Spacing, TokenTree}; | 
|  | use core::char; | 
|  | use core::str::{Bytes, CharIndices, Chars}; | 
|  |  | 
|  | #[derive(Copy, Clone, Eq, PartialEq)] | 
|  | pub(crate) struct Cursor<'a> { | 
|  | pub rest: &'a str, | 
|  | #[cfg(span_locations)] | 
|  | pub off: u32, | 
|  | } | 
|  |  | 
|  | impl<'a> Cursor<'a> { | 
|  | pub fn advance(&self, bytes: usize) -> Cursor<'a> { | 
|  | let (_front, rest) = self.rest.split_at(bytes); | 
|  | Cursor { | 
|  | rest, | 
|  | #[cfg(span_locations)] | 
|  | off: self.off + _front.chars().count() as u32, | 
|  | } | 
|  | } | 
|  |  | 
|  | pub fn starts_with(&self, s: &str) -> bool { | 
|  | self.rest.starts_with(s) | 
|  | } | 
|  |  | 
|  | pub fn starts_with_char(&self, ch: char) -> bool { | 
|  | self.rest.starts_with(ch) | 
|  | } | 
|  |  | 
|  | pub fn starts_with_fn<Pattern>(&self, f: Pattern) -> bool | 
|  | where | 
|  | Pattern: FnMut(char) -> bool, | 
|  | { | 
|  | self.rest.starts_with(f) | 
|  | } | 
|  |  | 
|  | pub fn is_empty(&self) -> bool { | 
|  | self.rest.is_empty() | 
|  | } | 
|  |  | 
|  | fn len(&self) -> usize { | 
|  | self.rest.len() | 
|  | } | 
|  |  | 
|  | fn as_bytes(&self) -> &'a [u8] { | 
|  | self.rest.as_bytes() | 
|  | } | 
|  |  | 
|  | fn bytes(&self) -> Bytes<'a> { | 
|  | self.rest.bytes() | 
|  | } | 
|  |  | 
|  | fn chars(&self) -> Chars<'a> { | 
|  | self.rest.chars() | 
|  | } | 
|  |  | 
|  | fn char_indices(&self) -> CharIndices<'a> { | 
|  | self.rest.char_indices() | 
|  | } | 
|  |  | 
|  | fn parse(&self, tag: &str) -> Result<Cursor<'a>, Reject> { | 
|  | if self.starts_with(tag) { | 
|  | Ok(self.advance(tag.len())) | 
|  | } else { | 
|  | Err(Reject) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | pub(crate) struct Reject; | 
|  | type PResult<'a, O> = Result<(Cursor<'a>, O), Reject>; | 
|  |  | 
|  | fn skip_whitespace(input: Cursor) -> Cursor { | 
|  | let mut s = input; | 
|  |  | 
|  | while !s.is_empty() { | 
|  | let byte = s.as_bytes()[0]; | 
|  | if byte == b'/' { | 
|  | if s.starts_with("//") | 
|  | && (!s.starts_with("///") || s.starts_with("////")) | 
|  | && !s.starts_with("//!") | 
|  | { | 
|  | let (cursor, _) = take_until_newline_or_eof(s); | 
|  | s = cursor; | 
|  | continue; | 
|  | } else if s.starts_with("/**/") { | 
|  | s = s.advance(4); | 
|  | continue; | 
|  | } else if s.starts_with("/*") | 
|  | && (!s.starts_with("/**") || s.starts_with("/***")) | 
|  | && !s.starts_with("/*!") | 
|  | { | 
|  | match block_comment(s) { | 
|  | Ok((rest, _)) => { | 
|  | s = rest; | 
|  | continue; | 
|  | } | 
|  | Err(Reject) => return s, | 
|  | } | 
|  | } | 
|  | } | 
|  | match byte { | 
|  | b' ' | 0x09..=0x0d => { | 
|  | s = s.advance(1); | 
|  | continue; | 
|  | } | 
|  | b if b.is_ascii() => {} | 
|  | _ => { | 
|  | let ch = s.chars().next().unwrap(); | 
|  | if is_whitespace(ch) { | 
|  | s = s.advance(ch.len_utf8()); | 
|  | continue; | 
|  | } | 
|  | } | 
|  | } | 
|  | return s; | 
|  | } | 
|  | s | 
|  | } | 
|  |  | 
|  | fn block_comment(input: Cursor) -> PResult<&str> { | 
|  | if !input.starts_with("/*") { | 
|  | return Err(Reject); | 
|  | } | 
|  |  | 
|  | let mut depth = 0usize; | 
|  | let bytes = input.as_bytes(); | 
|  | let mut i = 0usize; | 
|  | let upper = bytes.len() - 1; | 
|  |  | 
|  | while i < upper { | 
|  | if bytes[i] == b'/' && bytes[i + 1] == b'*' { | 
|  | depth += 1; | 
|  | i += 1; // eat '*' | 
|  | } else if bytes[i] == b'*' && bytes[i + 1] == b'/' { | 
|  | depth -= 1; | 
|  | if depth == 0 { | 
|  | return Ok((input.advance(i + 2), &input.rest[..i + 2])); | 
|  | } | 
|  | i += 1; // eat '/' | 
|  | } | 
|  | i += 1; | 
|  | } | 
|  |  | 
|  | Err(Reject) | 
|  | } | 
|  |  | 
|  | fn is_whitespace(ch: char) -> bool { | 
|  | // Rust treats left-to-right mark and right-to-left mark as whitespace | 
|  | ch.is_whitespace() || ch == '\u{200e}' || ch == '\u{200f}' | 
|  | } | 
|  |  | 
|  | fn word_break(input: Cursor) -> Result<Cursor, Reject> { | 
|  | match input.chars().next() { | 
|  | Some(ch) if is_ident_continue(ch) => Err(Reject), | 
|  | Some(_) | None => Ok(input), | 
|  | } | 
|  | } | 
|  |  | 
|  | // Rustc's representation of a macro expansion error in expression position or | 
|  | // type position. | 
|  | const ERROR: &str = "(/*ERROR*/)"; | 
|  |  | 
|  | pub(crate) fn token_stream(mut input: Cursor) -> Result<TokenStream, LexError> { | 
|  | let mut trees = TokenStreamBuilder::new(); | 
|  | let mut stack = Vec::new(); | 
|  |  | 
|  | loop { | 
|  | input = skip_whitespace(input); | 
|  |  | 
|  | if let Ok((rest, ())) = doc_comment(input, &mut trees) { | 
|  | input = rest; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | #[cfg(span_locations)] | 
|  | let lo = input.off; | 
|  |  | 
|  | let first = match input.bytes().next() { | 
|  | Some(first) => first, | 
|  | None => match stack.last() { | 
|  | None => return Ok(trees.build()), | 
|  | #[cfg(span_locations)] | 
|  | Some((lo, _frame)) => { | 
|  | return Err(LexError { | 
|  | span: Span { lo: *lo, hi: *lo }, | 
|  | }) | 
|  | } | 
|  | #[cfg(not(span_locations))] | 
|  | Some(_frame) => return Err(LexError { span: Span {} }), | 
|  | }, | 
|  | }; | 
|  |  | 
|  | if let Some(open_delimiter) = match first { | 
|  | b'(' if !input.starts_with(ERROR) => Some(Delimiter::Parenthesis), | 
|  | b'[' => Some(Delimiter::Bracket), | 
|  | b'{' => Some(Delimiter::Brace), | 
|  | _ => None, | 
|  | } { | 
|  | input = input.advance(1); | 
|  | let frame = (open_delimiter, trees); | 
|  | #[cfg(span_locations)] | 
|  | let frame = (lo, frame); | 
|  | stack.push(frame); | 
|  | trees = TokenStreamBuilder::new(); | 
|  | } else if let Some(close_delimiter) = match first { | 
|  | b')' => Some(Delimiter::Parenthesis), | 
|  | b']' => Some(Delimiter::Bracket), | 
|  | b'}' => Some(Delimiter::Brace), | 
|  | _ => None, | 
|  | } { | 
|  | let frame = match stack.pop() { | 
|  | Some(frame) => frame, | 
|  | None => return Err(lex_error(input)), | 
|  | }; | 
|  | #[cfg(span_locations)] | 
|  | let (lo, frame) = frame; | 
|  | let (open_delimiter, outer) = frame; | 
|  | if open_delimiter != close_delimiter { | 
|  | return Err(lex_error(input)); | 
|  | } | 
|  | input = input.advance(1); | 
|  | let mut g = Group::new(open_delimiter, trees.build()); | 
|  | g.set_span(Span { | 
|  | #[cfg(span_locations)] | 
|  | lo, | 
|  | #[cfg(span_locations)] | 
|  | hi: input.off, | 
|  | }); | 
|  | trees = outer; | 
|  | trees.push_token_from_parser(TokenTree::Group(crate::Group::_new_fallback(g))); | 
|  | } else { | 
|  | let (rest, mut tt) = match leaf_token(input) { | 
|  | Ok((rest, tt)) => (rest, tt), | 
|  | Err(Reject) => return Err(lex_error(input)), | 
|  | }; | 
|  | tt.set_span(crate::Span::_new_fallback(Span { | 
|  | #[cfg(span_locations)] | 
|  | lo, | 
|  | #[cfg(span_locations)] | 
|  | hi: rest.off, | 
|  | })); | 
|  | trees.push_token_from_parser(tt); | 
|  | input = rest; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | fn lex_error(cursor: Cursor) -> LexError { | 
|  | #[cfg(not(span_locations))] | 
|  | let _ = cursor; | 
|  | LexError { | 
|  | span: Span { | 
|  | #[cfg(span_locations)] | 
|  | lo: cursor.off, | 
|  | #[cfg(span_locations)] | 
|  | hi: cursor.off, | 
|  | }, | 
|  | } | 
|  | } | 
|  |  | 
|  | fn leaf_token(input: Cursor) -> PResult<TokenTree> { | 
|  | if let Ok((input, l)) = literal(input) { | 
|  | // must be parsed before ident | 
|  | Ok((input, TokenTree::Literal(crate::Literal::_new_fallback(l)))) | 
|  | } else if let Ok((input, p)) = punct(input) { | 
|  | Ok((input, TokenTree::Punct(p))) | 
|  | } else if let Ok((input, i)) = ident(input) { | 
|  | Ok((input, TokenTree::Ident(i))) | 
|  | } else if input.starts_with(ERROR) { | 
|  | let rest = input.advance(ERROR.len()); | 
|  | let repr = crate::Literal::_new_fallback(Literal::_new(ERROR.to_owned())); | 
|  | Ok((rest, TokenTree::Literal(repr))) | 
|  | } else { | 
|  | Err(Reject) | 
|  | } | 
|  | } | 
|  |  | 
|  | fn ident(input: Cursor) -> PResult<crate::Ident> { | 
|  | if [ | 
|  | "r\"", "r#\"", "r##", "b\"", "b\'", "br\"", "br#", "c\"", "cr\"", "cr#", | 
|  | ] | 
|  | .iter() | 
|  | .any(|prefix| input.starts_with(prefix)) | 
|  | { | 
|  | Err(Reject) | 
|  | } else { | 
|  | ident_any(input) | 
|  | } | 
|  | } | 
|  |  | 
|  | fn ident_any(input: Cursor) -> PResult<crate::Ident> { | 
|  | let raw = input.starts_with("r#"); | 
|  | let rest = input.advance((raw as usize) << 1); | 
|  |  | 
|  | let (rest, sym) = ident_not_raw(rest)?; | 
|  |  | 
|  | if !raw { | 
|  | let ident = crate::Ident::_new(crate::imp::Ident::new_unchecked( | 
|  | sym, | 
|  | fallback::Span::call_site(), | 
|  | )); | 
|  | return Ok((rest, ident)); | 
|  | } | 
|  |  | 
|  | match sym { | 
|  | "_" | "super" | "self" | "Self" | "crate" => return Err(Reject), | 
|  | _ => {} | 
|  | } | 
|  |  | 
|  | let ident = crate::Ident::_new(crate::imp::Ident::new_raw_unchecked( | 
|  | sym, | 
|  | fallback::Span::call_site(), | 
|  | )); | 
|  | Ok((rest, ident)) | 
|  | } | 
|  |  | 
|  | fn ident_not_raw(input: Cursor) -> PResult<&str> { | 
|  | let mut chars = input.char_indices(); | 
|  |  | 
|  | match chars.next() { | 
|  | Some((_, ch)) if is_ident_start(ch) => {} | 
|  | _ => return Err(Reject), | 
|  | } | 
|  |  | 
|  | let mut end = input.len(); | 
|  | for (i, ch) in chars { | 
|  | if !is_ident_continue(ch) { | 
|  | end = i; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | Ok((input.advance(end), &input.rest[..end])) | 
|  | } | 
|  |  | 
|  | pub(crate) fn literal(input: Cursor) -> PResult<Literal> { | 
|  | let rest = literal_nocapture(input)?; | 
|  | let end = input.len() - rest.len(); | 
|  | Ok((rest, Literal::_new(input.rest[..end].to_string()))) | 
|  | } | 
|  |  | 
|  | fn literal_nocapture(input: Cursor) -> Result<Cursor, Reject> { | 
|  | if let Ok(ok) = string(input) { | 
|  | Ok(ok) | 
|  | } else if let Ok(ok) = byte_string(input) { | 
|  | Ok(ok) | 
|  | } else if let Ok(ok) = c_string(input) { | 
|  | Ok(ok) | 
|  | } else if let Ok(ok) = byte(input) { | 
|  | Ok(ok) | 
|  | } else if let Ok(ok) = character(input) { | 
|  | Ok(ok) | 
|  | } else if let Ok(ok) = float(input) { | 
|  | Ok(ok) | 
|  | } else if let Ok(ok) = int(input) { | 
|  | Ok(ok) | 
|  | } else { | 
|  | Err(Reject) | 
|  | } | 
|  | } | 
|  |  | 
|  | fn literal_suffix(input: Cursor) -> Cursor { | 
|  | match ident_not_raw(input) { | 
|  | Ok((input, _)) => input, | 
|  | Err(Reject) => input, | 
|  | } | 
|  | } | 
|  |  | 
|  | fn string(input: Cursor) -> Result<Cursor, Reject> { | 
|  | if let Ok(input) = input.parse("\"") { | 
|  | cooked_string(input) | 
|  | } else if let Ok(input) = input.parse("r") { | 
|  | raw_string(input) | 
|  | } else { | 
|  | Err(Reject) | 
|  | } | 
|  | } | 
|  |  | 
|  | fn cooked_string(mut input: Cursor) -> Result<Cursor, Reject> { | 
|  | let mut chars = input.char_indices(); | 
|  |  | 
|  | while let Some((i, ch)) = chars.next() { | 
|  | match ch { | 
|  | '"' => { | 
|  | let input = input.advance(i + 1); | 
|  | return Ok(literal_suffix(input)); | 
|  | } | 
|  | '\r' => match chars.next() { | 
|  | Some((_, '\n')) => {} | 
|  | _ => break, | 
|  | }, | 
|  | '\\' => match chars.next() { | 
|  | Some((_, 'x')) => { | 
|  | backslash_x_char(&mut chars)?; | 
|  | } | 
|  | Some((_, 'n' | 'r' | 't' | '\\' | '\'' | '"' | '0')) => {} | 
|  | Some((_, 'u')) => { | 
|  | backslash_u(&mut chars)?; | 
|  | } | 
|  | Some((newline, ch @ ('\n' | '\r'))) => { | 
|  | input = input.advance(newline + 1); | 
|  | trailing_backslash(&mut input, ch as u8)?; | 
|  | chars = input.char_indices(); | 
|  | } | 
|  | _ => break, | 
|  | }, | 
|  | _ch => {} | 
|  | } | 
|  | } | 
|  | Err(Reject) | 
|  | } | 
|  |  | 
|  | fn raw_string(input: Cursor) -> Result<Cursor, Reject> { | 
|  | let (input, delimiter) = delimiter_of_raw_string(input)?; | 
|  | let mut bytes = input.bytes().enumerate(); | 
|  | while let Some((i, byte)) = bytes.next() { | 
|  | match byte { | 
|  | b'"' if input.rest[i + 1..].starts_with(delimiter) => { | 
|  | let rest = input.advance(i + 1 + delimiter.len()); | 
|  | return Ok(literal_suffix(rest)); | 
|  | } | 
|  | b'\r' => match bytes.next() { | 
|  | Some((_, b'\n')) => {} | 
|  | _ => break, | 
|  | }, | 
|  | _ => {} | 
|  | } | 
|  | } | 
|  | Err(Reject) | 
|  | } | 
|  |  | 
|  | fn byte_string(input: Cursor) -> Result<Cursor, Reject> { | 
|  | if let Ok(input) = input.parse("b\"") { | 
|  | cooked_byte_string(input) | 
|  | } else if let Ok(input) = input.parse("br") { | 
|  | raw_byte_string(input) | 
|  | } else { | 
|  | Err(Reject) | 
|  | } | 
|  | } | 
|  |  | 
|  | fn cooked_byte_string(mut input: Cursor) -> Result<Cursor, Reject> { | 
|  | let mut bytes = input.bytes().enumerate(); | 
|  | while let Some((offset, b)) = bytes.next() { | 
|  | match b { | 
|  | b'"' => { | 
|  | let input = input.advance(offset + 1); | 
|  | return Ok(literal_suffix(input)); | 
|  | } | 
|  | b'\r' => match bytes.next() { | 
|  | Some((_, b'\n')) => {} | 
|  | _ => break, | 
|  | }, | 
|  | b'\\' => match bytes.next() { | 
|  | Some((_, b'x')) => { | 
|  | backslash_x_byte(&mut bytes)?; | 
|  | } | 
|  | Some((_, b'n' | b'r' | b't' | b'\\' | b'0' | b'\'' | b'"')) => {} | 
|  | Some((newline, b @ (b'\n' | b'\r'))) => { | 
|  | input = input.advance(newline + 1); | 
|  | trailing_backslash(&mut input, b)?; | 
|  | bytes = input.bytes().enumerate(); | 
|  | } | 
|  | _ => break, | 
|  | }, | 
|  | b if b.is_ascii() => {} | 
|  | _ => break, | 
|  | } | 
|  | } | 
|  | Err(Reject) | 
|  | } | 
|  |  | 
|  | fn delimiter_of_raw_string(input: Cursor) -> PResult<&str> { | 
|  | for (i, byte) in input.bytes().enumerate() { | 
|  | match byte { | 
|  | b'"' => { | 
|  | if i > 255 { | 
|  | // https://github.com/rust-lang/rust/pull/95251 | 
|  | return Err(Reject); | 
|  | } | 
|  | return Ok((input.advance(i + 1), &input.rest[..i])); | 
|  | } | 
|  | b'#' => {} | 
|  | _ => break, | 
|  | } | 
|  | } | 
|  | Err(Reject) | 
|  | } | 
|  |  | 
|  | fn raw_byte_string(input: Cursor) -> Result<Cursor, Reject> { | 
|  | let (input, delimiter) = delimiter_of_raw_string(input)?; | 
|  | let mut bytes = input.bytes().enumerate(); | 
|  | while let Some((i, byte)) = bytes.next() { | 
|  | match byte { | 
|  | b'"' if input.rest[i + 1..].starts_with(delimiter) => { | 
|  | let rest = input.advance(i + 1 + delimiter.len()); | 
|  | return Ok(literal_suffix(rest)); | 
|  | } | 
|  | b'\r' => match bytes.next() { | 
|  | Some((_, b'\n')) => {} | 
|  | _ => break, | 
|  | }, | 
|  | other => { | 
|  | if !other.is_ascii() { | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | Err(Reject) | 
|  | } | 
|  |  | 
|  | fn c_string(input: Cursor) -> Result<Cursor, Reject> { | 
|  | if let Ok(input) = input.parse("c\"") { | 
|  | cooked_c_string(input) | 
|  | } else if let Ok(input) = input.parse("cr") { | 
|  | raw_c_string(input) | 
|  | } else { | 
|  | Err(Reject) | 
|  | } | 
|  | } | 
|  |  | 
|  | fn raw_c_string(input: Cursor) -> Result<Cursor, Reject> { | 
|  | let (input, delimiter) = delimiter_of_raw_string(input)?; | 
|  | let mut bytes = input.bytes().enumerate(); | 
|  | while let Some((i, byte)) = bytes.next() { | 
|  | match byte { | 
|  | b'"' if input.rest[i + 1..].starts_with(delimiter) => { | 
|  | let rest = input.advance(i + 1 + delimiter.len()); | 
|  | return Ok(literal_suffix(rest)); | 
|  | } | 
|  | b'\r' => match bytes.next() { | 
|  | Some((_, b'\n')) => {} | 
|  | _ => break, | 
|  | }, | 
|  | b'\0' => break, | 
|  | _ => {} | 
|  | } | 
|  | } | 
|  | Err(Reject) | 
|  | } | 
|  |  | 
|  | fn cooked_c_string(mut input: Cursor) -> Result<Cursor, Reject> { | 
|  | let mut chars = input.char_indices(); | 
|  |  | 
|  | while let Some((i, ch)) = chars.next() { | 
|  | match ch { | 
|  | '"' => { | 
|  | let input = input.advance(i + 1); | 
|  | return Ok(literal_suffix(input)); | 
|  | } | 
|  | '\r' => match chars.next() { | 
|  | Some((_, '\n')) => {} | 
|  | _ => break, | 
|  | }, | 
|  | '\\' => match chars.next() { | 
|  | Some((_, 'x')) => { | 
|  | backslash_x_nonzero(&mut chars)?; | 
|  | } | 
|  | Some((_, 'n' | 'r' | 't' | '\\' | '\'' | '"')) => {} | 
|  | Some((_, 'u')) => { | 
|  | if backslash_u(&mut chars)? == '\0' { | 
|  | break; | 
|  | } | 
|  | } | 
|  | Some((newline, ch @ ('\n' | '\r'))) => { | 
|  | input = input.advance(newline + 1); | 
|  | trailing_backslash(&mut input, ch as u8)?; | 
|  | chars = input.char_indices(); | 
|  | } | 
|  | _ => break, | 
|  | }, | 
|  | '\0' => break, | 
|  | _ch => {} | 
|  | } | 
|  | } | 
|  | Err(Reject) | 
|  | } | 
|  |  | 
|  | fn byte(input: Cursor) -> Result<Cursor, Reject> { | 
|  | let input = input.parse("b'")?; | 
|  | let mut bytes = input.bytes().enumerate(); | 
|  | let ok = match bytes.next().map(|(_, b)| b) { | 
|  | Some(b'\\') => match bytes.next().map(|(_, b)| b) { | 
|  | Some(b'x') => backslash_x_byte(&mut bytes).is_ok(), | 
|  | Some(b'n' | b'r' | b't' | b'\\' | b'0' | b'\'' | b'"') => true, | 
|  | _ => false, | 
|  | }, | 
|  | b => b.is_some(), | 
|  | }; | 
|  | if !ok { | 
|  | return Err(Reject); | 
|  | } | 
|  | let (offset, _) = bytes.next().ok_or(Reject)?; | 
|  | if !input.chars().as_str().is_char_boundary(offset) { | 
|  | return Err(Reject); | 
|  | } | 
|  | let input = input.advance(offset).parse("'")?; | 
|  | Ok(literal_suffix(input)) | 
|  | } | 
|  |  | 
|  | fn character(input: Cursor) -> Result<Cursor, Reject> { | 
|  | let input = input.parse("'")?; | 
|  | let mut chars = input.char_indices(); | 
|  | let ok = match chars.next().map(|(_, ch)| ch) { | 
|  | Some('\\') => match chars.next().map(|(_, ch)| ch) { | 
|  | Some('x') => backslash_x_char(&mut chars).is_ok(), | 
|  | Some('u') => backslash_u(&mut chars).is_ok(), | 
|  | Some('n' | 'r' | 't' | '\\' | '0' | '\'' | '"') => true, | 
|  | _ => false, | 
|  | }, | 
|  | ch => ch.is_some(), | 
|  | }; | 
|  | if !ok { | 
|  | return Err(Reject); | 
|  | } | 
|  | let (idx, _) = chars.next().ok_or(Reject)?; | 
|  | let input = input.advance(idx).parse("'")?; | 
|  | Ok(literal_suffix(input)) | 
|  | } | 
|  |  | 
|  | macro_rules! next_ch { | 
|  | ($chars:ident @ $pat:pat) => { | 
|  | match $chars.next() { | 
|  | Some((_, ch)) => match ch { | 
|  | $pat => ch, | 
|  | _ => return Err(Reject), | 
|  | }, | 
|  | None => return Err(Reject), | 
|  | } | 
|  | }; | 
|  | } | 
|  |  | 
|  | fn backslash_x_char<I>(chars: &mut I) -> Result<(), Reject> | 
|  | where | 
|  | I: Iterator<Item = (usize, char)>, | 
|  | { | 
|  | next_ch!(chars @ '0'..='7'); | 
|  | next_ch!(chars @ '0'..='9' | 'a'..='f' | 'A'..='F'); | 
|  | Ok(()) | 
|  | } | 
|  |  | 
|  | fn backslash_x_byte<I>(chars: &mut I) -> Result<(), Reject> | 
|  | where | 
|  | I: Iterator<Item = (usize, u8)>, | 
|  | { | 
|  | next_ch!(chars @ b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F'); | 
|  | next_ch!(chars @ b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F'); | 
|  | Ok(()) | 
|  | } | 
|  |  | 
|  | fn backslash_x_nonzero<I>(chars: &mut I) -> Result<(), Reject> | 
|  | where | 
|  | I: Iterator<Item = (usize, char)>, | 
|  | { | 
|  | let first = next_ch!(chars @ '0'..='9' | 'a'..='f' | 'A'..='F'); | 
|  | let second = next_ch!(chars @ '0'..='9' | 'a'..='f' | 'A'..='F'); | 
|  | if first == '0' && second == '0' { | 
|  | Err(Reject) | 
|  | } else { | 
|  | Ok(()) | 
|  | } | 
|  | } | 
|  |  | 
|  | fn backslash_u<I>(chars: &mut I) -> Result<char, Reject> | 
|  | where | 
|  | I: Iterator<Item = (usize, char)>, | 
|  | { | 
|  | next_ch!(chars @ '{'); | 
|  | let mut value = 0; | 
|  | let mut len = 0; | 
|  | for (_, ch) in chars { | 
|  | let digit = match ch { | 
|  | '0'..='9' => ch as u8 - b'0', | 
|  | 'a'..='f' => 10 + ch as u8 - b'a', | 
|  | 'A'..='F' => 10 + ch as u8 - b'A', | 
|  | '_' if len > 0 => continue, | 
|  | '}' if len > 0 => return char::from_u32(value).ok_or(Reject), | 
|  | _ => break, | 
|  | }; | 
|  | if len == 6 { | 
|  | break; | 
|  | } | 
|  | value *= 0x10; | 
|  | value += u32::from(digit); | 
|  | len += 1; | 
|  | } | 
|  | Err(Reject) | 
|  | } | 
|  |  | 
|  | fn trailing_backslash(input: &mut Cursor, mut last: u8) -> Result<(), Reject> { | 
|  | let mut whitespace = input.bytes().enumerate(); | 
|  | loop { | 
|  | if last == b'\r' && whitespace.next().map_or(true, |(_, b)| b != b'\n') { | 
|  | return Err(Reject); | 
|  | } | 
|  | match whitespace.next() { | 
|  | Some((_, b @ (b' ' | b'\t' | b'\n' | b'\r'))) => { | 
|  | last = b; | 
|  | } | 
|  | Some((offset, _)) => { | 
|  | *input = input.advance(offset); | 
|  | return Ok(()); | 
|  | } | 
|  | None => return Err(Reject), | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | fn float(input: Cursor) -> Result<Cursor, Reject> { | 
|  | let mut rest = float_digits(input)?; | 
|  | if let Some(ch) = rest.chars().next() { | 
|  | if is_ident_start(ch) { | 
|  | rest = ident_not_raw(rest)?.0; | 
|  | } | 
|  | } | 
|  | word_break(rest) | 
|  | } | 
|  |  | 
|  | fn float_digits(input: Cursor) -> Result<Cursor, Reject> { | 
|  | let mut chars = input.chars().peekable(); | 
|  | match chars.next() { | 
|  | Some(ch) if '0' <= ch && ch <= '9' => {} | 
|  | _ => return Err(Reject), | 
|  | } | 
|  |  | 
|  | let mut len = 1; | 
|  | let mut has_dot = false; | 
|  | let mut has_exp = false; | 
|  | while let Some(&ch) = chars.peek() { | 
|  | match ch { | 
|  | '0'..='9' | '_' => { | 
|  | chars.next(); | 
|  | len += 1; | 
|  | } | 
|  | '.' => { | 
|  | if has_dot { | 
|  | break; | 
|  | } | 
|  | chars.next(); | 
|  | if chars | 
|  | .peek() | 
|  | .map_or(false, |&ch| ch == '.' || is_ident_start(ch)) | 
|  | { | 
|  | return Err(Reject); | 
|  | } | 
|  | len += 1; | 
|  | has_dot = true; | 
|  | } | 
|  | 'e' | 'E' => { | 
|  | chars.next(); | 
|  | len += 1; | 
|  | has_exp = true; | 
|  | break; | 
|  | } | 
|  | _ => break, | 
|  | } | 
|  | } | 
|  |  | 
|  | if !(has_dot || has_exp) { | 
|  | return Err(Reject); | 
|  | } | 
|  |  | 
|  | if has_exp { | 
|  | let token_before_exp = if has_dot { | 
|  | Ok(input.advance(len - 1)) | 
|  | } else { | 
|  | Err(Reject) | 
|  | }; | 
|  | let mut has_sign = false; | 
|  | let mut has_exp_value = false; | 
|  | while let Some(&ch) = chars.peek() { | 
|  | match ch { | 
|  | '+' | '-' => { | 
|  | if has_exp_value { | 
|  | break; | 
|  | } | 
|  | if has_sign { | 
|  | return token_before_exp; | 
|  | } | 
|  | chars.next(); | 
|  | len += 1; | 
|  | has_sign = true; | 
|  | } | 
|  | '0'..='9' => { | 
|  | chars.next(); | 
|  | len += 1; | 
|  | has_exp_value = true; | 
|  | } | 
|  | '_' => { | 
|  | chars.next(); | 
|  | len += 1; | 
|  | } | 
|  | _ => break, | 
|  | } | 
|  | } | 
|  | if !has_exp_value { | 
|  | return token_before_exp; | 
|  | } | 
|  | } | 
|  |  | 
|  | Ok(input.advance(len)) | 
|  | } | 
|  |  | 
|  | fn int(input: Cursor) -> Result<Cursor, Reject> { | 
|  | let mut rest = digits(input)?; | 
|  | if let Some(ch) = rest.chars().next() { | 
|  | if is_ident_start(ch) { | 
|  | rest = ident_not_raw(rest)?.0; | 
|  | } | 
|  | } | 
|  | word_break(rest) | 
|  | } | 
|  |  | 
|  | fn digits(mut input: Cursor) -> Result<Cursor, Reject> { | 
|  | let base = if input.starts_with("0x") { | 
|  | input = input.advance(2); | 
|  | 16 | 
|  | } else if input.starts_with("0o") { | 
|  | input = input.advance(2); | 
|  | 8 | 
|  | } else if input.starts_with("0b") { | 
|  | input = input.advance(2); | 
|  | 2 | 
|  | } else { | 
|  | 10 | 
|  | }; | 
|  |  | 
|  | let mut len = 0; | 
|  | let mut empty = true; | 
|  | for b in input.bytes() { | 
|  | match b { | 
|  | b'0'..=b'9' => { | 
|  | let digit = (b - b'0') as u64; | 
|  | if digit >= base { | 
|  | return Err(Reject); | 
|  | } | 
|  | } | 
|  | b'a'..=b'f' => { | 
|  | let digit = 10 + (b - b'a') as u64; | 
|  | if digit >= base { | 
|  | break; | 
|  | } | 
|  | } | 
|  | b'A'..=b'F' => { | 
|  | let digit = 10 + (b - b'A') as u64; | 
|  | if digit >= base { | 
|  | break; | 
|  | } | 
|  | } | 
|  | b'_' => { | 
|  | if empty && base == 10 { | 
|  | return Err(Reject); | 
|  | } | 
|  | len += 1; | 
|  | continue; | 
|  | } | 
|  | _ => break, | 
|  | }; | 
|  | len += 1; | 
|  | empty = false; | 
|  | } | 
|  | if empty { | 
|  | Err(Reject) | 
|  | } else { | 
|  | Ok(input.advance(len)) | 
|  | } | 
|  | } | 
|  |  | 
|  | fn punct(input: Cursor) -> PResult<Punct> { | 
|  | let (rest, ch) = punct_char(input)?; | 
|  | if ch == '\'' { | 
|  | if ident_any(rest)?.0.starts_with_char('\'') { | 
|  | Err(Reject) | 
|  | } else { | 
|  | Ok((rest, Punct::new('\'', Spacing::Joint))) | 
|  | } | 
|  | } else { | 
|  | let kind = match punct_char(rest) { | 
|  | Ok(_) => Spacing::Joint, | 
|  | Err(Reject) => Spacing::Alone, | 
|  | }; | 
|  | Ok((rest, Punct::new(ch, kind))) | 
|  | } | 
|  | } | 
|  |  | 
|  | fn punct_char(input: Cursor) -> PResult<char> { | 
|  | if input.starts_with("//") || input.starts_with("/*") { | 
|  | // Do not accept `/` of a comment as a punct. | 
|  | return Err(Reject); | 
|  | } | 
|  |  | 
|  | let mut chars = input.chars(); | 
|  | let first = match chars.next() { | 
|  | Some(ch) => ch, | 
|  | None => { | 
|  | return Err(Reject); | 
|  | } | 
|  | }; | 
|  | let recognized = "~!@#$%^&*-=+|;:,<.>/?'"; | 
|  | if recognized.contains(first) { | 
|  | Ok((input.advance(first.len_utf8()), first)) | 
|  | } else { | 
|  | Err(Reject) | 
|  | } | 
|  | } | 
|  |  | 
|  | fn doc_comment<'a>(input: Cursor<'a>, trees: &mut TokenStreamBuilder) -> PResult<'a, ()> { | 
|  | #[cfg(span_locations)] | 
|  | let lo = input.off; | 
|  | let (rest, (comment, inner)) = doc_comment_contents(input)?; | 
|  | let fallback_span = Span { | 
|  | #[cfg(span_locations)] | 
|  | lo, | 
|  | #[cfg(span_locations)] | 
|  | hi: rest.off, | 
|  | }; | 
|  | let span = crate::Span::_new_fallback(fallback_span); | 
|  |  | 
|  | let mut scan_for_bare_cr = comment; | 
|  | while let Some(cr) = scan_for_bare_cr.find('\r') { | 
|  | let rest = &scan_for_bare_cr[cr + 1..]; | 
|  | if !rest.starts_with('\n') { | 
|  | return Err(Reject); | 
|  | } | 
|  | scan_for_bare_cr = rest; | 
|  | } | 
|  |  | 
|  | let mut pound = Punct::new('#', Spacing::Alone); | 
|  | pound.set_span(span); | 
|  | trees.push_token_from_parser(TokenTree::Punct(pound)); | 
|  |  | 
|  | if inner { | 
|  | let mut bang = Punct::new('!', Spacing::Alone); | 
|  | bang.set_span(span); | 
|  | trees.push_token_from_parser(TokenTree::Punct(bang)); | 
|  | } | 
|  |  | 
|  | let doc_ident = crate::Ident::_new(crate::imp::Ident::new_unchecked("doc", fallback_span)); | 
|  | let mut equal = Punct::new('=', Spacing::Alone); | 
|  | equal.set_span(span); | 
|  | let mut literal = crate::Literal::string(comment); | 
|  | literal.set_span(span); | 
|  | let mut bracketed = TokenStreamBuilder::with_capacity(3); | 
|  | bracketed.push_token_from_parser(TokenTree::Ident(doc_ident)); | 
|  | bracketed.push_token_from_parser(TokenTree::Punct(equal)); | 
|  | bracketed.push_token_from_parser(TokenTree::Literal(literal)); | 
|  | let group = Group::new(Delimiter::Bracket, bracketed.build()); | 
|  | let mut group = crate::Group::_new_fallback(group); | 
|  | group.set_span(span); | 
|  | trees.push_token_from_parser(TokenTree::Group(group)); | 
|  |  | 
|  | Ok((rest, ())) | 
|  | } | 
|  |  | 
|  | fn doc_comment_contents(input: Cursor) -> PResult<(&str, bool)> { | 
|  | if input.starts_with("//!") { | 
|  | let input = input.advance(3); | 
|  | let (input, s) = take_until_newline_or_eof(input); | 
|  | Ok((input, (s, true))) | 
|  | } else if input.starts_with("/*!") { | 
|  | let (input, s) = block_comment(input)?; | 
|  | Ok((input, (&s[3..s.len() - 2], true))) | 
|  | } else if input.starts_with("///") { | 
|  | let input = input.advance(3); | 
|  | if input.starts_with_char('/') { | 
|  | return Err(Reject); | 
|  | } | 
|  | let (input, s) = take_until_newline_or_eof(input); | 
|  | Ok((input, (s, false))) | 
|  | } else if input.starts_with("/**") && !input.rest[3..].starts_with('*') { | 
|  | let (input, s) = block_comment(input)?; | 
|  | Ok((input, (&s[3..s.len() - 2], false))) | 
|  | } else { | 
|  | Err(Reject) | 
|  | } | 
|  | } | 
|  |  | 
|  | fn take_until_newline_or_eof(input: Cursor) -> (Cursor, &str) { | 
|  | let chars = input.char_indices(); | 
|  |  | 
|  | for (i, ch) in chars { | 
|  | if ch == '\n' { | 
|  | return (input.advance(i), &input.rest[..i]); | 
|  | } else if ch == '\r' && input.rest[i + 1..].starts_with('\n') { | 
|  | return (input.advance(i + 1), &input.rest[..i]); | 
|  | } | 
|  | } | 
|  |  | 
|  | (input.advance(input.len()), input.rest) | 
|  | } |