#![feature(staged_api)]
#![feature(allow_internal_unstable)]
#![feature(decl_macro)]
+#![feature(local_key_cell_methods)]
+#![feature(maybe_uninit_write_slice)]
#![feature(negative_impls)]
+#![feature(new_uninit)]
#![feature(restricted_std)]
#![feature(rustc_attrs)]
#![feature(min_specialization)]
+#![feature(strict_provenance)]
#![recursion_limit = "256"]
#[unstable(feature = "proc_macro_internals", issue = "27812")]
use std::ops::RangeBounds;
use std::path::PathBuf;
use std::str::FromStr;
-use std::{error, fmt, iter, mem};
+use std::{error, fmt, iter};
/// Determines whether proc_macro has been made accessible to the currently
/// running program.
/// inside of a procedural macro, false if invoked from any other binary.
#[stable(feature = "proc_macro_is_available", since = "1.57.0")]
pub fn is_available() -> bool {
- bridge::Bridge::is_available()
+ bridge::client::is_available()
}
/// The main type provided by this crate, representing an abstract stream of
/// and `#[proc_macro_derive]` definitions.
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
#[derive(Clone)]
-pub struct TokenStream(bridge::client::TokenStream);
+pub struct TokenStream(Option<bridge::client::TokenStream>);
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
impl !Send for TokenStream {}
/// Returns an empty `TokenStream` containing no token trees.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn new() -> TokenStream {
- TokenStream(bridge::client::TokenStream::new())
+ TokenStream(None)
}
/// Checks if this `TokenStream` is empty.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn is_empty(&self) -> bool {
- self.0.is_empty()
+ self.0.as_ref().map(|h| h.is_empty()).unwrap_or(true)
}
/// Parses this `TokenStream` as an expression and attempts to expand any
/// considered errors, is unspecified and may change in the future.
#[unstable(feature = "proc_macro_expand", issue = "90765")]
pub fn expand_expr(&self) -> Result<TokenStream, ExpandError> {
- match bridge::client::TokenStream::expand_expr(&self.0) {
- Ok(stream) => Ok(TokenStream(stream)),
+ let stream = self.0.as_ref().ok_or(ExpandError)?;
+ match bridge::client::TokenStream::expand_expr(stream) {
+ Ok(stream) => Ok(TokenStream(Some(stream))),
Err(_) => Err(ExpandError),
}
}
type Err = LexError;
fn from_str(src: &str) -> Result<TokenStream, LexError> {
- Ok(TokenStream(bridge::client::TokenStream::from_str(src)))
+ Ok(TokenStream(Some(bridge::client::TokenStream::from_str(src))))
}
}
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
impl ToString for TokenStream {
fn to_string(&self) -> String {
- self.0.to_string()
+ self.0.as_ref().map(|t| t.to_string()).unwrap_or_default()
}
}
#[unstable(feature = "proc_macro_quote", issue = "54722")]
pub use quote::{quote, quote_span};
+fn tree_to_bridge_tree(
+ tree: TokenTree,
+) -> bridge::TokenTree<
+ bridge::client::TokenStream,
+ bridge::client::Span,
+ bridge::client::Symbol,
+ bridge::client::Literal,
+> {
+ match tree {
+ TokenTree::Group(tt) => bridge::TokenTree::Group(tt.0),
+ TokenTree::Punct(tt) => bridge::TokenTree::Punct(tt.0),
+ TokenTree::Ident(tt) => bridge::TokenTree::Ident(tt.0),
+ TokenTree::Literal(tt) => bridge::TokenTree::Literal(tt.0),
+ }
+}
+
/// Creates a token stream containing a single token tree.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
impl From<TokenTree> for TokenStream {
fn from(tree: TokenTree) -> TokenStream {
- TokenStream(bridge::client::TokenStream::from_token_tree(match tree {
- TokenTree::Group(tt) => bridge::TokenTree::Group(tt.0),
- TokenTree::Punct(tt) => bridge::TokenTree::Punct(tt.0),
- TokenTree::Ident(tt) => bridge::TokenTree::Ident(tt.0),
- TokenTree::Literal(tt) => bridge::TokenTree::Literal(tt.0),
- }))
+ TokenStream(Some(bridge::client::TokenStream::from_token_tree(tree_to_bridge_tree(tree))))
+ }
+}
+
+/// Non-generic helper for implementing `FromIterator<TokenTree>` and
+/// `Extend<TokenTree>` with less monomorphization in calling crates.
+struct ConcatTreesHelper {
+ trees: Vec<
+ bridge::TokenTree<
+ bridge::client::TokenStream,
+ bridge::client::Span,
+ bridge::client::Symbol,
+ bridge::client::Literal,
+ >,
+ >,
+}
+
+impl ConcatTreesHelper {
+ fn new(capacity: usize) -> Self {
+ ConcatTreesHelper { trees: Vec::with_capacity(capacity) }
+ }
+
+ fn push(&mut self, tree: TokenTree) {
+ self.trees.push(tree_to_bridge_tree(tree));
+ }
+
+ fn build(self) -> TokenStream {
+ if self.trees.is_empty() {
+ TokenStream(None)
+ } else {
+ TokenStream(Some(bridge::client::TokenStream::concat_trees(None, self.trees)))
+ }
+ }
+
+ fn append_to(self, stream: &mut TokenStream) {
+ if self.trees.is_empty() {
+ return;
+ }
+ stream.0 = Some(bridge::client::TokenStream::concat_trees(stream.0.take(), self.trees))
+ }
+}
+
+/// Non-generic helper for implementing `FromIterator<TokenStream>` and
+/// `Extend<TokenStream>` with less monomorphization in calling crates.
+struct ConcatStreamsHelper {
+ streams: Vec<bridge::client::TokenStream>,
+}
+
+impl ConcatStreamsHelper {
+ fn new(capacity: usize) -> Self {
+ ConcatStreamsHelper { streams: Vec::with_capacity(capacity) }
+ }
+
+ fn push(&mut self, stream: TokenStream) {
+ if let Some(stream) = stream.0 {
+ self.streams.push(stream);
+ }
+ }
+
+ fn build(mut self) -> TokenStream {
+ if self.streams.len() <= 1 {
+ TokenStream(self.streams.pop())
+ } else {
+ TokenStream(Some(bridge::client::TokenStream::concat_streams(None, self.streams)))
+ }
+ }
+
+ fn append_to(mut self, stream: &mut TokenStream) {
+ if self.streams.is_empty() {
+ return;
+ }
+ let base = stream.0.take();
+ if base.is_none() && self.streams.len() == 1 {
+ stream.0 = self.streams.pop();
+ } else {
+ stream.0 = Some(bridge::client::TokenStream::concat_streams(base, self.streams));
+ }
}
}
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
impl iter::FromIterator<TokenTree> for TokenStream {
fn from_iter<I: IntoIterator<Item = TokenTree>>(trees: I) -> Self {
- trees.into_iter().map(TokenStream::from).collect()
+ let iter = trees.into_iter();
+ let mut builder = ConcatTreesHelper::new(iter.size_hint().0);
+ iter.for_each(|tree| builder.push(tree));
+ builder.build()
}
}
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
impl iter::FromIterator<TokenStream> for TokenStream {
fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self {
- let mut builder = bridge::client::TokenStreamBuilder::new();
- streams.into_iter().for_each(|stream| builder.push(stream.0));
- TokenStream(builder.build())
+ let iter = streams.into_iter();
+ let mut builder = ConcatStreamsHelper::new(iter.size_hint().0);
+ iter.for_each(|stream| builder.push(stream));
+ builder.build()
}
}
#[stable(feature = "token_stream_extend", since = "1.30.0")]
impl Extend<TokenTree> for TokenStream {
fn extend<I: IntoIterator<Item = TokenTree>>(&mut self, trees: I) {
- self.extend(trees.into_iter().map(TokenStream::from));
+ let iter = trees.into_iter();
+ let mut builder = ConcatTreesHelper::new(iter.size_hint().0);
+ iter.for_each(|tree| builder.push(tree));
+ builder.append_to(self);
}
}
#[stable(feature = "token_stream_extend", since = "1.30.0")]
impl Extend<TokenStream> for TokenStream {
fn extend<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I) {
- // FIXME(eddyb) Use an optimized implementation if/when possible.
- *self = iter::once(mem::replace(self, Self::new())).chain(streams).collect();
+ let iter = streams.into_iter();
+ let mut builder = ConcatStreamsHelper::new(iter.size_hint().0);
+ iter.for_each(|stream| builder.push(stream));
+ builder.append_to(self);
}
}
/// and returns whole groups as token trees.
#[derive(Clone)]
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
- pub struct IntoIter(bridge::client::TokenStreamIter);
+ pub struct IntoIter(
+ std::vec::IntoIter<
+ bridge::TokenTree<
+ bridge::client::TokenStream,
+ bridge::client::Span,
+ bridge::client::Symbol,
+ bridge::client::Literal,
+ >,
+ >,
+ );
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
impl Iterator for IntoIter {
type IntoIter = IntoIter;
fn into_iter(self) -> IntoIter {
- IntoIter(self.0.into_iter())
+ IntoIter(self.0.map(|v| v.into_trees()).unwrap_or_default().into_iter())
}
}
}
/// A `Group` internally contains a `TokenStream` which is surrounded by `Delimiter`s.
#[derive(Clone)]
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
-pub struct Group(bridge::client::Group);
+pub struct Group(bridge::Group<bridge::client::TokenStream, bridge::client::Span>);
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
impl !Send for Group {}
/// method below.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group {
- Group(bridge::client::Group::new(delimiter, stream.0))
+ Group(bridge::Group {
+ delimiter,
+ stream: stream.0,
+ span: bridge::DelimSpan::from_single(Span::call_site().0),
+ })
}
/// Returns the delimiter of this `Group`
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn delimiter(&self) -> Delimiter {
- self.0.delimiter()
+ self.0.delimiter
}
/// Returns the `TokenStream` of tokens that are delimited in this `Group`.
/// returned above.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn stream(&self) -> TokenStream {
- TokenStream(self.0.stream())
+ TokenStream(self.0.stream.clone())
}
/// Returns the span for the delimiters of this token stream, spanning the
/// ```
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn span(&self) -> Span {
- Span(self.0.span())
+ Span(self.0.span.entire)
}
/// Returns the span pointing to the opening delimiter of this group.
/// ```
#[stable(feature = "proc_macro_group_span", since = "1.55.0")]
pub fn span_open(&self) -> Span {
- Span(self.0.span_open())
+ Span(self.0.span.open)
}
/// Returns the span pointing to the closing delimiter of this group.
/// ```
#[stable(feature = "proc_macro_group_span", since = "1.55.0")]
pub fn span_close(&self) -> Span {
- Span(self.0.span_close())
+ Span(self.0.span.close)
}
/// Configures the span for this `Group`'s delimiters, but not its internal
/// tokens at the level of the `Group`.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn set_span(&mut self, span: Span) {
- self.0.set_span(span.0);
+ self.0.span = bridge::DelimSpan::from_single(span.0);
}
}
/// forms of `Spacing` returned.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
#[derive(Clone)]
-pub struct Punct(bridge::client::Punct);
+pub struct Punct(bridge::Punct<bridge::client::Span>);
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
impl !Send for Punct {}
/// which can be further configured with the `set_span` method below.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn new(ch: char, spacing: Spacing) -> Punct {
- Punct(bridge::client::Punct::new(ch, spacing))
+ const LEGAL_CHARS: &[char] = &[
+ '=', '<', '>', '!', '~', '+', '-', '*', '/', '%', '^', '&', '|', '@', '.', ',', ';',
+ ':', '#', '$', '?', '\'',
+ ];
+ if !LEGAL_CHARS.contains(&ch) {
+ panic!("unsupported character `{:?}`", ch);
+ }
+ Punct(bridge::Punct {
+ ch: ch as u8,
+ joint: spacing == Spacing::Joint,
+ span: Span::call_site().0,
+ })
}
/// Returns the value of this punctuation character as `char`.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn as_char(&self) -> char {
- self.0.as_char()
+ self.0.ch as char
}
/// Returns the spacing of this punctuation character, indicating whether it's immediately
/// (`Alone`) so the operator has certainly ended.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn spacing(&self) -> Spacing {
- self.0.spacing()
+ if self.0.joint { Spacing::Joint } else { Spacing::Alone }
}
/// Returns the span for this punctuation character.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn span(&self) -> Span {
- Span(self.0.span())
+ Span(self.0.span)
}
/// Configure the span for this punctuation character.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn set_span(&mut self, span: Span) {
- self.0 = self.0.with_span(span.0);
+ self.0.span = span.0;
}
}
-// N.B., the bridge only provides `to_string`, implement `fmt::Display`
-// based on it (the reverse of the usual relationship between the two).
-#[stable(feature = "proc_macro_lib", since = "1.15.0")]
+#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
impl ToString for Punct {
fn to_string(&self) -> String {
- TokenStream::from(TokenTree::from(self.clone())).to_string()
+ self.as_char().to_string()
}
}
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
impl fmt::Display for Punct {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_str(&self.to_string())
+ write!(f, "{}", self.as_char())
}
}
/// An identifier (`ident`).
#[derive(Clone)]
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
-pub struct Ident(bridge::client::Ident);
+pub struct Ident(bridge::Ident<bridge::client::Span, bridge::client::Symbol>);
impl Ident {
/// Creates a new `Ident` with the given `string` as well as the specified
/// tokens, requires a `Span` to be specified at construction.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn new(string: &str, span: Span) -> Ident {
- Ident(bridge::client::Ident::new(string, span.0, false))
+ Ident(bridge::Ident {
+ sym: bridge::client::Symbol::new_ident(string, false),
+ is_raw: false,
+ span: span.0,
+ })
}
/// Same as `Ident::new`, but creates a raw identifier (`r#ident`).
/// (e.g. `self`, `super`) are not supported, and will cause a panic.
#[stable(feature = "proc_macro_raw_ident", since = "1.47.0")]
pub fn new_raw(string: &str, span: Span) -> Ident {
- Ident(bridge::client::Ident::new(string, span.0, true))
+ Ident(bridge::Ident {
+ sym: bridge::client::Symbol::new_ident(string, true),
+ is_raw: true,
+ span: span.0,
+ })
}
/// Returns the span of this `Ident`, encompassing the entire string returned
- /// by [`to_string`](Self::to_string).
+ /// by [`to_string`](ToString::to_string).
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn span(&self) -> Span {
- Span(self.0.span())
+ Span(self.0.span)
}
/// Configures the span of this `Ident`, possibly changing its hygiene context.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn set_span(&mut self, span: Span) {
- self.0 = self.0.with_span(span.0);
+ self.0.span = span.0;
}
}
-// N.B., the bridge only provides `to_string`, implement `fmt::Display`
-// based on it (the reverse of the usual relationship between the two).
-#[stable(feature = "proc_macro_lib", since = "1.15.0")]
+/// Converts the identifier to a string that should be losslessly convertible
+/// back into the same identifier.
+#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
impl ToString for Ident {
fn to_string(&self) -> String {
- TokenStream::from(TokenTree::from(self.clone())).to_string()
+ self.0.sym.with(|sym| if self.0.is_raw { ["r#", sym].concat() } else { sym.to_owned() })
}
}
-/// Prints the identifier as a string that should be losslessly convertible
-/// back into the same identifier.
+/// Prints the identifier as a string that should be losslessly convertible back
+/// into the same identifier.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
impl fmt::Display for Ident {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_str(&self.to_string())
+ if self.0.is_raw {
+ f.write_str("r#")?;
+ }
+ fmt::Display::fmt(&self.0.sym, f)
}
}