// SPDX-License-Identifier: Apache-2.0 OR MIT use crate::fallback::{ self, is_ident_continue, is_ident_start, Group, Ident, 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(crate) rest: &'a str, #[cfg(span_locations)] pub(crate) off: u32,} impl<'a> Cursor<'a> { pub(crate) 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(crate) fn starts_with(&self, s: &str) -> bool { self.rest.starts_with(s) } pub(crate) fn starts_with_char(&self, ch: char) -> bool { self.rest.starts_with(ch) } pub(crate) fn starts_with_fn<Pattern>(&self, f: Pattern) -> bool where Pattern: FnMut(char) -> bool, { self.rest.starts_with(f) } pub(crate) 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_fallback(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_fallback(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));Lines 1–500 of 997. Load more
// SPDX-License-Identifier: Apache-2.0 OR MIT use crate::fallback::{ self, is_ident_continue, is_ident_start, Group, Ident, 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(crate) rest: &'a str, #[cfg(span_locations)] pub(crate) off: u32, } impl<'a> Cursor<'a> { pub(crate) 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(crate) fn starts_with(&self, s: &str) -> bool { self.rest.starts_with(s) } pub(crate) fn starts_with_char(&self, ch: char) -> bool { self.rest.starts_with(ch) } pub(crate) fn starts_with_fn<Pattern>(&self, f: Pattern) -> bool where Pattern: FnMut(char) -> bool, { self.rest.starts_with(f) } pub(crate) 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_fallback(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_fallback(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));