997 lines · 28.1 KB · Rust
RawDownload
// 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.