From b2844917ad29e967043bea4e187421a6a3f61682 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Sat, 4 Apr 2020 16:04:01 +0800 Subject: Add proc_macro mod (copy from lib_proc_macro) --- .../ra_proc_macro_srv/src/proc_macro/bridge/mod.rs | 404 +++++++++++++++++++++ 1 file changed, 404 insertions(+) create mode 100644 crates/ra_proc_macro_srv/src/proc_macro/bridge/mod.rs (limited to 'crates/ra_proc_macro_srv/src/proc_macro/bridge/mod.rs') diff --git a/crates/ra_proc_macro_srv/src/proc_macro/bridge/mod.rs b/crates/ra_proc_macro_srv/src/proc_macro/bridge/mod.rs new file mode 100644 index 000000000..6ae3926b2 --- /dev/null +++ b/crates/ra_proc_macro_srv/src/proc_macro/bridge/mod.rs @@ -0,0 +1,404 @@ +//! lib-proc-macro Internal interface for communicating between a `proc_macro` client +//! +//! Copy from https://github.com/rust-lang/rust/blob/6050e523bae6de61de4e060facc43dc512adaccd/src/libproc_macro/bridge/mod.rs +//! augmented with removing unstable features +//! +//! Internal interface for communicating between a `proc_macro` client +//! (a proc macro crate) and a `proc_macro` server (a compiler front-end). +//! +//! Serialization (with C ABI buffers) and unique integer handles are employed +//! to allow safely interfacing between two copies of `proc_macro` built +//! (from the same source) by different compilers with potentially mismatching +//! Rust ABIs (e.g., stage0/bin/rustc vs stage1/bin/rustc during bootstrap). + +#![deny(unsafe_code)] + +pub use crate::proc_macro::{Delimiter, Level, LineColumn, Spacing}; +use std::fmt; +use std::hash::Hash; +use std::marker; +use std::mem; +use std::ops::Bound; +use std::panic; +use std::sync::atomic::AtomicUsize; +use std::sync::Once; +use std::thread; + +/// Higher-order macro describing the server RPC API, allowing automatic +/// generation of type-safe Rust APIs, both client-side and server-side. +/// +/// `with_api!(MySelf, my_self, my_macro)` expands to: +/// ```rust,ignore (pseudo-code) +/// my_macro! { +/// // ... +/// Literal { +/// // ... +/// fn character(ch: char) -> MySelf::Literal; +/// // ... +/// fn span(my_self: &MySelf::Literal) -> MySelf::Span; +/// fn set_span(my_self: &mut MySelf::Literal, span: MySelf::Span); +/// }, +/// // ... +/// } +/// ``` +/// +/// The first two arguments serve to customize the arguments names +/// and argument/return types, to enable several different usecases: +/// +/// If `my_self` is just `self`, then each `fn` signature can be used +/// as-is for a method. If it's anything else (`self_` in practice), +/// then the signatures don't have a special `self` argument, and +/// can, therefore, have a different one introduced. +/// +/// If `MySelf` is just `Self`, then the types are only valid inside +/// a trait or a trait impl, where the trait has associated types +/// for each of the API types. If non-associated types are desired, +/// a module name (`self` in practice) can be used instead of `Self`. +macro_rules! with_api { + ($S:ident, $self:ident, $m:ident) => { + $m! { + TokenStream { + fn drop($self: $S::TokenStream); + fn clone($self: &$S::TokenStream) -> $S::TokenStream; + fn new() -> $S::TokenStream; + fn is_empty($self: &$S::TokenStream) -> bool; + fn from_str(src: &str) -> $S::TokenStream; + fn to_string($self: &$S::TokenStream) -> String; + fn from_token_tree( + tree: TokenTree<$S::Group, $S::Punct, $S::Ident, $S::Literal>, + ) -> $S::TokenStream; + fn into_iter($self: $S::TokenStream) -> $S::TokenStreamIter; + }, + TokenStreamBuilder { + fn drop($self: $S::TokenStreamBuilder); + fn new() -> $S::TokenStreamBuilder; + fn push($self: &mut $S::TokenStreamBuilder, stream: $S::TokenStream); + fn build($self: $S::TokenStreamBuilder) -> $S::TokenStream; + }, + TokenStreamIter { + fn drop($self: $S::TokenStreamIter); + fn clone($self: &$S::TokenStreamIter) -> $S::TokenStreamIter; + fn next( + $self: &mut $S::TokenStreamIter, + ) -> Option>; + }, + Group { + fn drop($self: $S::Group); + fn clone($self: &$S::Group) -> $S::Group; + fn new(delimiter: Delimiter, stream: $S::TokenStream) -> $S::Group; + fn delimiter($self: &$S::Group) -> Delimiter; + fn stream($self: &$S::Group) -> $S::TokenStream; + fn span($self: &$S::Group) -> $S::Span; + fn span_open($self: &$S::Group) -> $S::Span; + fn span_close($self: &$S::Group) -> $S::Span; + fn set_span($self: &mut $S::Group, span: $S::Span); + }, + Punct { + fn new(ch: char, spacing: Spacing) -> $S::Punct; + fn as_char($self: $S::Punct) -> char; + fn spacing($self: $S::Punct) -> Spacing; + fn span($self: $S::Punct) -> $S::Span; + fn with_span($self: $S::Punct, span: $S::Span) -> $S::Punct; + }, + Ident { + fn new(string: &str, span: $S::Span, is_raw: bool) -> $S::Ident; + fn span($self: $S::Ident) -> $S::Span; + fn with_span($self: $S::Ident, span: $S::Span) -> $S::Ident; + }, + Literal { + fn drop($self: $S::Literal); + fn clone($self: &$S::Literal) -> $S::Literal; + // FIXME(eddyb) `Literal` should not expose internal `Debug` impls. + fn debug($self: &$S::Literal) -> String; + fn integer(n: &str) -> $S::Literal; + fn typed_integer(n: &str, kind: &str) -> $S::Literal; + fn float(n: &str) -> $S::Literal; + fn f32(n: &str) -> $S::Literal; + fn f64(n: &str) -> $S::Literal; + fn string(string: &str) -> $S::Literal; + fn character(ch: char) -> $S::Literal; + fn byte_string(bytes: &[u8]) -> $S::Literal; + fn span($self: &$S::Literal) -> $S::Span; + fn set_span($self: &mut $S::Literal, span: $S::Span); + fn subspan( + $self: &$S::Literal, + start: Bound, + end: Bound, + ) -> Option<$S::Span>; + }, + SourceFile { + fn drop($self: $S::SourceFile); + fn clone($self: &$S::SourceFile) -> $S::SourceFile; + fn eq($self: &$S::SourceFile, other: &$S::SourceFile) -> bool; + fn path($self: &$S::SourceFile) -> String; + fn is_real($self: &$S::SourceFile) -> bool; + }, + MultiSpan { + fn drop($self: $S::MultiSpan); + fn new() -> $S::MultiSpan; + fn push($self: &mut $S::MultiSpan, span: $S::Span); + }, + Diagnostic { + fn drop($self: $S::Diagnostic); + fn new(level: Level, msg: &str, span: $S::MultiSpan) -> $S::Diagnostic; + fn sub( + $self: &mut $S::Diagnostic, + level: Level, + msg: &str, + span: $S::MultiSpan, + ); + fn emit($self: $S::Diagnostic); + }, + Span { + fn debug($self: $S::Span) -> String; + fn def_site() -> $S::Span; + fn call_site() -> $S::Span; + fn mixed_site() -> $S::Span; + fn source_file($self: $S::Span) -> $S::SourceFile; + fn parent($self: $S::Span) -> Option<$S::Span>; + fn source($self: $S::Span) -> $S::Span; + fn start($self: $S::Span) -> LineColumn; + fn end($self: $S::Span) -> LineColumn; + fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>; + fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span; + fn source_text($self: $S::Span) -> Option; + }, + } + }; +} + +// FIXME(eddyb) this calls `encode` for each argument, but in reverse, +// to avoid borrow conflicts from borrows started by `&mut` arguments. +macro_rules! reverse_encode { + ($writer:ident;) => {}; + ($writer:ident; $first:ident $(, $rest:ident)*) => { + reverse_encode!($writer; $($rest),*); + $first.encode(&mut $writer, &mut ()); + } +} + +// FIXME(eddyb) this calls `decode` for each argument, but in reverse, +// to avoid borrow conflicts from borrows started by `&mut` arguments. +macro_rules! reverse_decode { + ($reader:ident, $s:ident;) => {}; + ($reader:ident, $s:ident; $first:ident: $first_ty:ty $(, $rest:ident: $rest_ty:ty)*) => { + reverse_decode!($reader, $s; $($rest: $rest_ty),*); + let $first = <$first_ty>::decode(&mut $reader, $s); + } +} + +#[allow(unsafe_code)] +mod buffer; +#[forbid(unsafe_code)] +pub mod client; +#[allow(unsafe_code)] +mod closure; +#[forbid(unsafe_code)] +mod handle; +#[macro_use] +#[forbid(unsafe_code)] +mod rpc; +#[allow(unsafe_code)] +mod scoped_cell; +#[forbid(unsafe_code)] +pub mod server; + +use buffer::Buffer; +pub use rpc::PanicMessage; +use rpc::{Decode, DecodeMut, Encode, Reader, Writer}; + +/// An active connection between a server and a client. +/// The server creates the bridge (`Bridge::run_server` in `server.rs`), +/// then passes it to the client through the function pointer in the `run` +/// field of `client::Client`. The client holds its copy of the `Bridge` +/// in TLS during its execution (`Bridge::{enter, with}` in `client.rs`). +#[repr(C)] +pub struct Bridge<'a> { + /// Reusable buffer (only `clear`-ed, never shrunk), primarily + /// used for making requests, but also for passing input to client. + cached_buffer: Buffer, + + /// Server-side function that the client uses to make requests. + dispatch: closure::Closure<'a, Buffer, Buffer>, +} + +#[forbid(unsafe_code)] +#[allow(non_camel_case_types)] +mod api_tags { + use super::rpc::{DecodeMut, Encode, Reader, Writer}; + + macro_rules! declare_tags { + ($($name:ident { + $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* + }),* $(,)?) => { + $( + pub(super) enum $name { + $($method),* + } + rpc_encode_decode!(enum $name { $($method),* }); + )* + + + pub(super) enum Method { + $($name($name)),* + } + rpc_encode_decode!(enum Method { $($name(m)),* }); + } + } + with_api!(self, self, declare_tags); +} + +/// Helper to wrap associated types to allow trait impl dispatch. +/// That is, normally a pair of impls for `T::Foo` and `T::Bar` +/// can overlap, but if the impls are, instead, on types like +/// `Marked` and `Marked`, they can't. +trait Mark { + type Unmarked; + fn mark(unmarked: Self::Unmarked) -> Self; +} + +/// Unwrap types wrapped by `Mark::mark` (see `Mark` for details). +trait Unmark { + type Unmarked; + fn unmark(self) -> Self::Unmarked; +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +struct Marked { + value: T, + _marker: marker::PhantomData, +} + +impl Mark for Marked { + type Unmarked = T; + fn mark(unmarked: Self::Unmarked) -> Self { + Marked { value: unmarked, _marker: marker::PhantomData } + } +} +impl Unmark for Marked { + type Unmarked = T; + fn unmark(self) -> Self::Unmarked { + self.value + } +} +impl<'a, T, M> Unmark for &'a Marked { + type Unmarked = &'a T; + fn unmark(self) -> Self::Unmarked { + &self.value + } +} +impl<'a, T, M> Unmark for &'a mut Marked { + type Unmarked = &'a mut T; + fn unmark(self) -> Self::Unmarked { + &mut self.value + } +} + +impl Mark for Option { + type Unmarked = Option; + fn mark(unmarked: Self::Unmarked) -> Self { + unmarked.map(T::mark) + } +} +impl Unmark for Option { + type Unmarked = Option; + fn unmark(self) -> Self::Unmarked { + self.map(T::unmark) + } +} + +macro_rules! mark_noop { + ($($ty:ty),* $(,)?) => { + $( + impl Mark for $ty { + type Unmarked = Self; + fn mark(unmarked: Self::Unmarked) -> Self { + unmarked + } + } + impl Unmark for $ty { + type Unmarked = Self; + fn unmark(self) -> Self::Unmarked { + self + } + } + )* + } +} +mark_noop! { + (), + bool, + char, + &'_ [u8], + &'_ str, + String, + Delimiter, + Level, + LineColumn, + Spacing, + Bound, +} + +rpc_encode_decode!( + enum Delimiter { + Parenthesis, + Brace, + Bracket, + None, + } +); +rpc_encode_decode!( + enum Level { + Error, + Warning, + Note, + Help, + } +); +rpc_encode_decode!(struct LineColumn { line, column }); +rpc_encode_decode!( + enum Spacing { + Alone, + Joint, + } +); + +#[derive(Clone)] +pub enum TokenTree { + Group(G), + Punct(P), + Ident(I), + Literal(L), +} + +impl Mark for TokenTree { + type Unmarked = TokenTree; + fn mark(unmarked: Self::Unmarked) -> Self { + match unmarked { + TokenTree::Group(tt) => TokenTree::Group(G::mark(tt)), + TokenTree::Punct(tt) => TokenTree::Punct(P::mark(tt)), + TokenTree::Ident(tt) => TokenTree::Ident(I::mark(tt)), + TokenTree::Literal(tt) => TokenTree::Literal(L::mark(tt)), + } + } +} +impl Unmark for TokenTree { + type Unmarked = TokenTree; + fn unmark(self) -> Self::Unmarked { + match self { + TokenTree::Group(tt) => TokenTree::Group(tt.unmark()), + TokenTree::Punct(tt) => TokenTree::Punct(tt.unmark()), + TokenTree::Ident(tt) => TokenTree::Ident(tt.unmark()), + TokenTree::Literal(tt) => TokenTree::Literal(tt.unmark()), + } + } +} + +rpc_encode_decode!( + enum TokenTree { + Group(tt), + Punct(tt), + Ident(tt), + Literal(tt), + } +); -- cgit v1.2.3