diff options
author | Valentin Popov <valentin@popov.link> | 2024-07-19 15:37:58 +0300 |
---|---|---|
committer | Valentin Popov <valentin@popov.link> | 2024-07-19 15:37:58 +0300 |
commit | a990de90fe41456a23e58bd087d2f107d321f3a1 (patch) | |
tree | 15afc392522a9e85dc3332235e311b7d39352ea9 /vendor/proc-macro2/src/parse.rs | |
parent | 3d48cd3f81164bbfc1a755dc1d4a9a02f98c8ddd (diff) | |
download | fparkan-a990de90fe41456a23e58bd087d2f107d321f3a1.tar.xz fparkan-a990de90fe41456a23e58bd087d2f107d321f3a1.zip |
Deleted vendor folder
Diffstat (limited to 'vendor/proc-macro2/src/parse.rs')
-rw-r--r-- | vendor/proc-macro2/src/parse.rs | 996 |
1 files changed, 0 insertions, 996 deletions
diff --git a/vendor/proc-macro2/src/parse.rs b/vendor/proc-macro2/src/parse.rs deleted file mode 100644 index 07239bc..0000000 --- a/vendor/proc-macro2/src/parse.rs +++ /dev/null @@ -1,996 +0,0 @@ -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) -} |