1258 lines · 33.5 KB · Rust
RawDownload
// SPDX-License-Identifier: Apache-2.0 OR MIT #[cfg(wrap_proc_macro)]use crate::imp;#[cfg(span_locations)]use crate::location::LineColumn;use crate::parse::{self, Cursor};use crate::rcvec::{RcVec, RcVecBuilder, RcVecIntoIter, RcVecMut};use crate::{Delimiter, Spacing, TokenTree};#[cfg(all(span_locations, not(fuzzing)))]use alloc::collections::BTreeMap;#[cfg(all(span_locations, not(fuzzing)))]use core::cell::RefCell;#[cfg(span_locations)]use core::cmp;#[cfg(all(span_locations, not(fuzzing)))]use core::cmp::Ordering;use core::fmt::{self, Debug, Display, Write};use core::mem::ManuallyDrop;#[cfg(span_locations)]use core::ops::Range;use core::ops::RangeBounds;use core::ptr;use core::str;#[cfg(feature = "proc-macro")]use core::str::FromStr;use std::ffi::CStr;#[cfg(wrap_proc_macro)]use std::panic;#[cfg(span_locations)]use std::path::PathBuf; /// Force use of proc-macro2's fallback implementation of the API for now, even/// if the compiler's implementation is available.pub fn force() {    #[cfg(wrap_proc_macro)]    crate::detection::force_fallback();} /// Resume using the compiler's implementation of the proc macro API if it is/// available.pub fn unforce() {    #[cfg(wrap_proc_macro)]    crate::detection::unforce_fallback();} #[derive(Clone)]pub(crate) struct TokenStream {    inner: RcVec<TokenTree>,} #[derive(Debug)]pub(crate) struct LexError {    pub(crate) span: Span,} impl LexError {    pub(crate) fn span(&self) -> Span {        self.span    }     pub(crate) fn call_site() -> Self {        LexError {            span: Span::call_site(),        }    }} impl TokenStream {    pub(crate) fn new() -> Self {        TokenStream {            inner: RcVecBuilder::new().build(),        }    }     pub(crate) fn from_str_checked(src: &str) -> Result<Self, LexError> {        // Create a dummy file & add it to the source map        let mut cursor = get_cursor(src);         // Strip a byte order mark if present        const BYTE_ORDER_MARK: &str = "\u{feff}";        if cursor.starts_with(BYTE_ORDER_MARK) {            cursor = cursor.advance(BYTE_ORDER_MARK.len());        }         parse::token_stream(cursor)    }     #[cfg(feature = "proc-macro")]    pub(crate) fn from_str_unchecked(src: &str) -> Self {        Self::from_str_checked(src).unwrap()    }     pub(crate) fn is_empty(&self) -> bool {        self.inner.len() == 0    }     fn take_inner(self) -> RcVecBuilder<TokenTree> {        let nodrop = ManuallyDrop::new(self);        unsafe { ptr::read(&nodrop.inner) }.make_owned()    }} fn push_token_from_proc_macro(mut vec: RcVecMut<TokenTree>, token: TokenTree) {    // https://github.com/dtolnay/proc-macro2/issues/235    match token {        TokenTree::Literal(crate::Literal {            #[cfg(wrap_proc_macro)]                inner: crate::imp::Literal::Fallback(literal),            #[cfg(not(wrap_proc_macro))]                inner: literal,            ..        }) if literal.repr.starts_with('-') => {            push_negative_literal(vec, literal);        }        _ => vec.push(token),    }     #[cold]    fn push_negative_literal(mut vec: RcVecMut<TokenTree>, mut literal: Literal) {        literal.repr.remove(0);        let mut punct = crate::Punct::new('-', Spacing::Alone);        punct.set_span(crate::Span::_new_fallback(literal.span));        vec.push(TokenTree::Punct(punct));        vec.push(TokenTree::Literal(crate::Literal::_new_fallback(literal)));    }} // Nonrecursive to prevent stack overflow.impl Drop for TokenStream {    fn drop(&mut self) {        let mut stack = Vec::new();        let mut current = match self.inner.get_mut() {            Some(inner) => inner.take().into_iter(),            None => return,        };        loop {            while let Some(token) = current.next() {                let group = match token {                    TokenTree::Group(group) => group.inner,                    _ => continue,                };                #[cfg(wrap_proc_macro)]                let group = match group {                    crate::imp::Group::Fallback(group) => group,                    crate::imp::Group::Compiler(_) => continue,                };                let mut group = group;                if let Some(inner) = group.stream.inner.get_mut() {                    stack.push(current);                    current = inner.take().into_iter();                }            }            match stack.pop() {                Some(next) => current = next,                None => return,            }        }    }} pub(crate) struct TokenStreamBuilder {    inner: RcVecBuilder<TokenTree>,} impl TokenStreamBuilder {    pub(crate) fn new() -> Self {        TokenStreamBuilder {            inner: RcVecBuilder::new(),        }    }     pub(crate) fn with_capacity(cap: usize) -> Self {        TokenStreamBuilder {            inner: RcVecBuilder::with_capacity(cap),        }    }     pub(crate) fn push_token_from_parser(&mut self, tt: TokenTree) {        self.inner.push(tt);    }     pub(crate) fn build(self) -> TokenStream {        TokenStream {            inner: self.inner.build(),        }    }} #[cfg(span_locations)]fn get_cursor(src: &str) -> Cursor {    #[cfg(fuzzing)]    return Cursor { rest: src, off: 1 };     // Create a dummy file & add it to the source map    #[cfg(not(fuzzing))]    SOURCE_MAP.with(|sm| {        let mut sm = sm.borrow_mut();        let span = sm.add_file(src);        Cursor {            rest: src,            off: span.lo,        }    })} #[cfg(not(span_locations))]fn get_cursor(src: &str) -> Cursor {    Cursor { rest: src }} impl Display for LexError {    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {        f.write_str("cannot parse string into token stream")    }} impl Display for TokenStream {    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {        let mut joint = false;        for (i, tt) in self.inner.iter().enumerate() {            if i != 0 && !joint {                write!(f, " ")?;            }            joint = false;            match tt {                TokenTree::Group(tt) => Display::fmt(tt, f),                TokenTree::Ident(tt) => Display::fmt(tt, f),                TokenTree::Punct(tt) => {                    joint = tt.spacing() == Spacing::Joint;                    Display::fmt(tt, f)                }                TokenTree::Literal(tt) => Display::fmt(tt, f),            }?;        }         Ok(())    }} impl Debug for TokenStream {    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {        f.write_str("TokenStream ")?;        f.debug_list().entries(self.clone()).finish()    }} #[cfg(feature = "proc-macro")]impl From<proc_macro::TokenStream> for TokenStream {    fn from(inner: proc_macro::TokenStream) -> Self {        TokenStream::from_str_unchecked(&inner.to_string())    }} #[cfg(feature = "proc-macro")]impl From<TokenStream> for proc_macro::TokenStream {    fn from(inner: TokenStream) -> Self {        proc_macro::TokenStream::from_str_unchecked(&inner.to_string())    }} impl From<TokenTree> for TokenStream {    fn from(tree: TokenTree) -> Self {        let mut stream = RcVecBuilder::new();        push_token_from_proc_macro(stream.as_mut(), tree);        TokenStream {            inner: stream.build(),        }    }} impl FromIterator<TokenTree> for TokenStream {    fn from_iter<I: IntoIterator<Item = TokenTree>>(tokens: I) -> Self {        let mut stream = TokenStream::new();        stream.extend(tokens);        stream    }} impl FromIterator<TokenStream> for TokenStream {    fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self {        let mut v = RcVecBuilder::new();         for stream in streams {            v.extend(stream.take_inner());        }         TokenStream { inner: v.build() }    }} impl Extend<TokenTree> for TokenStream {    fn extend<I: IntoIterator<Item = TokenTree>>(&mut self, tokens: I) {        let mut vec = self.inner.make_mut();        tokens            .into_iter()            .for_each(|token| push_token_from_proc_macro(vec.as_mut(), token));    }} impl Extend<TokenStream> for TokenStream {    fn extend<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I) {        self.inner.make_mut().extend(streams.into_iter().flatten());    }} pub(crate) type TokenTreeIter = RcVecIntoIter<TokenTree>; impl IntoIterator for TokenStream {    type Item = TokenTree;    type IntoIter = TokenTreeIter;     fn into_iter(self) -> TokenTreeIter {        self.take_inner().into_iter()    }} #[cfg(all(span_locations, not(fuzzing)))]thread_local! {    static SOURCE_MAP: RefCell<SourceMap> = RefCell::new(SourceMap {        // Start with a single dummy file which all call_site() and def_site()        // spans reference.        files: vec![FileInfo {            source_text: String::new(),            span: Span { lo: 0, hi: 0 },            lines: vec![0],            char_index_to_byte_offset: BTreeMap::new(),        }],    });} #[cfg(span_locations)]pub(crate) fn invalidate_current_thread_spans() {    #[cfg(not(fuzzing))]    SOURCE_MAP.with(|sm| sm.borrow_mut().files.truncate(1));} #[cfg(all(span_locations, not(fuzzing)))]struct FileInfo {    source_text: String,    span: Span,    lines: Vec<usize>,    char_index_to_byte_offset: BTreeMap<usize, usize>,} #[cfg(all(span_locations, not(fuzzing)))]impl FileInfo {    fn offset_line_column(&self, offset: usize) -> LineColumn {        assert!(self.span_within(Span {            lo: offset as u32,            hi: offset as u32,        }));        let offset = offset - self.span.lo as usize;        match self.lines.binary_search(&offset) {            Ok(found) => LineColumn {                line: found + 1,                column: 0,            },            Err(idx) => LineColumn {                line: idx,                column: offset - self.lines[idx - 1],            },        }    }     fn span_within(&self, span: Span) -> bool {        span.lo >= self.span.lo && span.hi <= self.span.hi    }     fn byte_range(&mut self, span: Span) -> Range<usize> {        let lo_char = (span.lo - self.span.lo) as usize;         // Look up offset of the largest already-computed char index that is        // less than or equal to the current requested one. We resume counting        // chars from that point.        let (&last_char_index, &last_byte_offset) = self            .char_index_to_byte_offset            .range(..=lo_char)            .next_back()            .unwrap_or((&0, &0));         let lo_byte = if last_char_index == lo_char {            last_byte_offset        } else {            let total_byte_offset = match self.source_text[last_byte_offset..]                .char_indices()                .nth(lo_char - last_char_index)            {                Some((additional_offset, _ch)) => last_byte_offset + additional_offset,                None => self.source_text.len(),            };            self.char_index_to_byte_offset                .insert(lo_char, total_byte_offset);            total_byte_offset        };         let trunc_lo = &self.source_text[lo_byte..];        let char_len = (span.hi - span.lo) as usize;        lo_byte..match trunc_lo.char_indices().nth(char_len) {            Some((offset, _ch)) => lo_byte + offset,            None => self.source_text.len(),        }    }     fn source_text(&mut self, span: Span) -> String {        let byte_range = self.byte_range(span);        self.source_text[byte_range].to_owned()    }} /// Computes the offsets of each line in the given source string/// and the total number of characters#[cfg(all(span_locations, not(fuzzing)))]fn lines_offsets(s: &str) -> (usize, Vec<usize>) {    let mut lines = vec![0];    let mut total = 0;     for ch in s.chars() {        total += 1;        if ch == '\n' {            lines.push(total);        }    }     (total, lines)} #[cfg(all(span_locations, not(fuzzing)))]struct SourceMap {    files: Vec<FileInfo>,} #[cfg(all(span_locations, not(fuzzing)))]impl SourceMap {    fn next_start_pos(&self) -> u32 {        // Add 1 so there's always space between files.        //        // We'll always have at least 1 file, as we initialize our files list        // with a dummy file.        self.files.last().unwrap().span.hi + 1    }     fn add_file(&mut self, src: &str) -> Span {        let (len, lines) = lines_offsets(src);        let lo = self.next_start_pos();        let span = Span {            lo,            hi: lo + (len as u32),        };         self.files.push(FileInfo {            source_text: src.to_owned(),            span,            lines,            // Populated lazily by source_text().            char_index_to_byte_offset: BTreeMap::new(),        });         span    }     fn find(&self, span: Span) -> usize {        match self.files.binary_search_by(|file| {            if file.span.hi < span.lo {                Ordering::Less            } else if file.span.lo > span.hi {                Ordering::Greater            } else {                assert!(file.span_within(span));                Ordering::Equal            }        }) {            Ok(i) => i,            Err(_) => unreachable!("Invalid span with no related FileInfo!"),        }    }     fn filepath(&self, span: Span) -> String {        let i = self.find(span);        if i == 0 {            "<unspecified>".to_owned()        } else {            format!("<parsed string {}>", i)        }    }     fn fileinfo(&self, span: Span) -> &FileInfo {        let i = self.find(span);        &self.files[i]    }     fn fileinfo_mut(&mut self, span: Span) -> &mut FileInfo {        let i = self.find(span);        &mut self.files[i]    }} #[derive(Clone, Copy, PartialEq, Eq)]pub(crate) struct Span {    #[cfg(span_locations)]

Lines 1–500 of 1258.