about summary refs log tree commit diff
path: root/src/libproc_macro
diff options
context:
space:
mode:
Diffstat (limited to 'src/libproc_macro')
-rw-r--r--src/libproc_macro/lib.rs14
-rw-r--r--src/libproc_macro/quote.rs265
2 files changed, 96 insertions, 183 deletions
diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs
index ea4ca03a0a1..c88a245d3b3 100644
--- a/src/libproc_macro/lib.rs
+++ b/src/libproc_macro/lib.rs
@@ -145,6 +145,9 @@ impl fmt::Debug for TokenStream {
     }
 }
 
+#[unstable(feature = "proc_macro_quote", issue = "38356")]
+pub use quote::{quote, quote_span};
+
 /// Creates a token stream containing a single token tree.
     #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
 impl From<TokenTree> for TokenStream {
@@ -237,7 +240,7 @@ pub mod token_stream {
 /// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term.
 /// To quote `$` itself, use `$$`.
 ///
-/// This is a dummy macro, the actual implementation is in quote::Quoter
+/// This is a dummy macro, the actual implementation is in `quote::quote`.`
 #[unstable(feature = "proc_macro_quote", issue = "38356")]
 #[macro_export]
 macro_rules! quote { () => {} }
@@ -246,13 +249,6 @@ macro_rules! quote { () => {} }
 #[doc(hidden)]
 mod quote;
 
-/// Quote a `Span` into a `TokenStream`.
-/// This is needed to implement a custom quoter.
-#[unstable(feature = "proc_macro_quote", issue = "38356")]
-pub fn quote_span(span: Span) -> TokenStream {
-    quote::Quote::quote(span)
-}
-
 /// A region of source code, along with macro expansion information.
 #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
 #[derive(Copy, Clone)]
@@ -1364,8 +1360,6 @@ impl TokenTree {
 #[unstable(feature = "proc_macro_internals", issue = "27812")]
 #[doc(hidden)]
 pub mod __internal {
-    pub use quote::{Quoter, unquote};
-
     use std::cell::Cell;
     use std::ptr;
 
diff --git a/src/libproc_macro/quote.rs b/src/libproc_macro/quote.rs
index 8ae1d7b8525..7ae7b13a152 100644
--- a/src/libproc_macro/quote.rs
+++ b/src/libproc_macro/quote.rs
@@ -14,34 +14,26 @@
 //! This quasiquoter uses macros 2.0 hygiene to reliably access
 //! items from `proc_macro`, to build a `proc_macro::TokenStream`.
 
-use {Delimiter, Literal, Spacing, Span, Ident, Punct, Group, TokenStream, TokenTree};
-
-use syntax::ext::base::{ExtCtxt, ProcMacro};
-use syntax::tokenstream;
-
-/// This is the actual quote!() proc macro
-///
-/// It is manually loaded in CStore::load_macro_untracked
-pub struct Quoter;
-
-pub fn unquote<T: Into<TokenStream> + Clone>(tokens: &T) -> TokenStream {
-    tokens.clone().into()
-}
-
-pub trait Quote {
-    fn quote(self) -> TokenStream;
-}
-
-macro_rules! tt2ts {
-    ($e:expr) => (TokenStream::from(TokenTree::from($e)))
-}
-
-macro_rules! quote_tok {
-    (,) => { tt2ts!(Punct::new(',', Spacing::Alone)) };
-    (.) => { tt2ts!(Punct::new('.', Spacing::Alone)) };
-    (:) => { tt2ts!(Punct::new(':', Spacing::Alone)) };
-    (;) => { tt2ts!(Punct::new(';', Spacing::Alone)) };
-    (|) => { tt2ts!(Punct::new('|', Spacing::Alone)) };
+use {Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
+
+macro_rules! quote_tt {
+    (($($t:tt)*)) => { Group::new(Delimiter::Parenthesis, quote!($($t)*)) };
+    ([$($t:tt)*]) => { Group::new(Delimiter::Bracket, quote!($($t)*)) };
+    ({$($t:tt)*}) => { Group::new(Delimiter::Brace, quote!($($t)*)) };
+    (,) => { Punct::new(',', Spacing::Alone) };
+    (.) => { Punct::new('.', Spacing::Alone) };
+    (:) => { Punct::new(':', Spacing::Alone) };
+    (;) => { Punct::new(';', Spacing::Alone) };
+    (!) => { Punct::new('!', Spacing::Alone) };
+    (<) => { Punct::new('<', Spacing::Alone) };
+    (>) => { Punct::new('>', Spacing::Alone) };
+    (&) => { Punct::new('&', Spacing::Alone) };
+    (=) => { Punct::new('=', Spacing::Alone) };
+    ($i:ident) => { Ident::new(stringify!($i), Span::def_site()) };
+}
+
+macro_rules! quote_ts {
+    ((@ $($t:tt)*)) => { $($t)* };
     (::) => {
         [
             TokenTree::from(Punct::new(':', Spacing::Joint)),
@@ -54,57 +46,45 @@ macro_rules! quote_tok {
             })
             .collect::<TokenStream>()
     };
-    (!) => { tt2ts!(Punct::new('!', Spacing::Alone)) };
-    (<) => { tt2ts!(Punct::new('<', Spacing::Alone)) };
-    (>) => { tt2ts!(Punct::new('>', Spacing::Alone)) };
-    (_) => { tt2ts!(Punct::new('_', Spacing::Alone)) };
-    (0) => { tt2ts!(Literal::i8_unsuffixed(0)) };
-    (&) => { tt2ts!(Punct::new('&', Spacing::Alone)) };
-    (=) => { tt2ts!(Punct::new('=', Spacing::Alone)) };
-    ($i:ident) => { tt2ts!(Ident::new(stringify!($i), Span::def_site())) };
-}
-
-macro_rules! quote_tree {
-    ((unquote $($t:tt)*)) => { $($t)* };
-    ((quote $($t:tt)*)) => { ($($t)*).quote() };
-    (($($t:tt)*)) => { tt2ts!(Group::new(Delimiter::Parenthesis, quote!($($t)*))) };
-    ([$($t:tt)*]) => { tt2ts!(Group::new(Delimiter::Bracket, quote!($($t)*))) };
-    ({$($t:tt)*}) => { tt2ts!(Group::new(Delimiter::Brace, quote!($($t)*))) };
-    ($t:tt) => { quote_tok!($t) };
+    ($t:tt) => { TokenTree::from(quote_tt!($t)) };
 }
 
+/// Simpler version of the real `quote!` macro, implemented solely
+/// through `macro_rules`, for bootstrapping the real implementation
+/// (see the `quote` function), which does not have access to the
+/// real `quote!` macro due to the `proc_macro` crate not being
+/// able to depend on itself.
+///
+/// Note: supported tokens are a subset of the real `quote!`, but
+/// unquoting is different: instead of `$x`, this uses `(@ expr)`.
 macro_rules! quote {
     () => { TokenStream::new() };
     ($($t:tt)*) => {
-        [$(quote_tree!($t),)*].iter()
-            .cloned()
-            .flat_map(|x| x.into_iter())
-            .collect::<TokenStream>()
+        [
+            $(TokenStream::from(quote_ts!($t)),)*
+        ].iter().cloned().collect::<TokenStream>()
     };
 }
 
-impl ProcMacro for Quoter {
-    fn expand<'cx>(&self, cx: &'cx mut ExtCtxt,
-                   _: ::syntax_pos::Span,
-                   stream: tokenstream::TokenStream)
-                   -> tokenstream::TokenStream {
-        ::__internal::set_sess(cx, || TokenStream(stream).quote().0)
+/// Quote a `TokenStream` into a `TokenStream`.
+/// This is the actual `quote!()` proc macro.
+///
+/// It is manually loaded in `CStore::load_macro_untracked`.
+#[unstable(feature = "proc_macro_quote", issue = "38356")]
+pub fn quote(stream: TokenStream) -> TokenStream {
+    if stream.is_empty() {
+        return quote!(::TokenStream::new());
     }
-}
-
-impl Quote for TokenStream {
-    fn quote(self) -> TokenStream {
-        if self.is_empty() {
-            return quote!(::TokenStream::new());
-        }
-        let mut after_dollar = false;
-        let tokens = self.into_iter().filter_map(|tree| {
+    let mut after_dollar = false;
+    let tokens = stream
+        .into_iter()
+        .filter_map(|tree| {
             if after_dollar {
                 after_dollar = false;
                 match tree {
                     TokenTree::Ident(_) => {
-                        let tree = TokenStream::from(tree);
-                        return Some(quote!(::__internal::unquote(&(unquote tree)),));
+                        return Some(quote!(Into::<::TokenStream>::into(
+                        Clone::clone(&(@ tree))),));
                     }
                     TokenTree::Punct(ref tt) if tt.as_char() == '$' => {}
                     _ => panic!("`$` must be followed by an ident or `$` in `quote!`"),
@@ -116,116 +96,55 @@ impl Quote for TokenStream {
                 }
             }
 
-            Some(quote!(::TokenStream::from((quote tree)),))
-        }).flat_map(|t| t.into_iter()).collect::<TokenStream>();
-
-        if after_dollar {
-            panic!("unexpected trailing `$` in `quote!`");
-        }
-
-        quote!(
-            [(unquote tokens)].iter()
-                .cloned()
-                .flat_map(|x| x.into_iter())
-                .collect::<::TokenStream>()
-        )
-    }
-}
-
-impl Quote for TokenTree {
-    fn quote(self) -> TokenStream {
-        match self {
-            TokenTree::Punct(tt) => quote!(::TokenTree::Punct( (quote tt) )),
-            TokenTree::Group(tt) => quote!(::TokenTree::Group( (quote tt) )),
-            TokenTree::Ident(tt) => quote!(::TokenTree::Ident( (quote tt) )),
-            TokenTree::Literal(tt) => quote!(::TokenTree::Literal( (quote tt) )),
-        }
-    }
-}
-
-impl Quote for char {
-    fn quote(self) -> TokenStream {
-        TokenTree::from(Literal::character(self)).into()
-    }
-}
-
-impl<'a> Quote for &'a str {
-    fn quote(self) -> TokenStream {
-        TokenTree::from(Literal::string(self)).into()
-    }
-}
-
-impl Quote for u16 {
-    fn quote(self) -> TokenStream {
-        TokenTree::from(Literal::u16_unsuffixed(self)).into()
-    }
-}
-
-impl Quote for Group {
-    fn quote(self) -> TokenStream {
-        quote!(::Group::new((quote self.delimiter()), (quote self.stream())))
-    }
-}
-
-impl Quote for Punct {
-    fn quote(self) -> TokenStream {
-        quote!(::Punct::new((quote self.as_char()), (quote self.spacing())))
-    }
-}
-
-impl Quote for Ident {
-    fn quote(self) -> TokenStream {
-        quote!(::Ident::new((quote self.sym.as_str()), (quote self.span())))
-    }
-}
+            Some(quote!(::TokenStream::from((@ match tree {
+                TokenTree::Punct(tt) => quote!(::TokenTree::Punct(::Punct::new(
+                    (@ TokenTree::from(Literal::character(tt.as_char()))),
+                    (@ match tt.spacing() {
+                        Spacing::Alone => quote!(::Spacing::Alone),
+                        Spacing::Joint => quote!(::Spacing::Joint),
+                    }),
+                ))),
+                TokenTree::Group(tt) => quote!(::TokenTree::Group(::Group::new(
+                    (@ match tt.delimiter() {
+                        Delimiter::Parenthesis => quote!(::Delimiter::Parenthesis),
+                        Delimiter::Brace => quote!(::Delimiter::Brace),
+                        Delimiter::Bracket => quote!(::Delimiter::Bracket),
+                        Delimiter::None => quote!(::Delimiter::None),
+                    }),
+                    (@ quote(tt.stream())),
+                ))),
+                TokenTree::Ident(tt) => quote!(::TokenTree::Ident(::Ident::new(
+                    (@ TokenTree::from(Literal::string(&tt.to_string()))),
+                    (@ quote_span(tt.span())),
+                ))),
+                TokenTree::Literal(tt) => quote!(::TokenTree::Literal({
+                    let mut iter = (@ TokenTree::from(Literal::string(&tt.to_string())))
+                        .parse::<::TokenStream>()
+                        .unwrap()
+                        .into_iter();
+                    if let (Some(::TokenTree::Literal(mut lit)), None) =
+                        (iter.next(), iter.next())
+                    {
+                        lit.set_span((@ quote_span(tt.span())));
+                        lit
+                    } else {
+                        unreachable!()
+                    }
+                }))
+            })),))
+        })
+        .collect::<TokenStream>();
 
-impl Quote for Span {
-    fn quote(self) -> TokenStream {
-        quote!(::Span::def_site())
+    if after_dollar {
+        panic!("unexpected trailing `$` in `quote!`");
     }
-}
-
-impl Quote for Literal {
-    fn quote(self) -> TokenStream {
-        quote! {{
-            let mut iter = (quote self.to_string())
-                .parse::<::TokenStream>()
-                .unwrap()
-                .into_iter();
-            if let (Some(::TokenTree::Literal(mut lit)), None) = (iter.next(), iter.next()) {
-                lit.set_span((quote self.span));
-                lit
-            } else {
-                unreachable!()
-            }
-        }}
-    }
-}
-
-impl Quote for Delimiter {
-    fn quote(self) -> TokenStream {
-        macro_rules! gen_match {
-            ($($i:ident),*) => {
-                match self {
-                    $(Delimiter::$i => { quote!(::Delimiter::$i) })*
-                }
-            }
-        }
 
-        gen_match!(Parenthesis, Brace, Bracket, None)
-    }
+    quote!([(@ tokens)].iter().cloned().collect::<::TokenStream>())
 }
 
-impl Quote for Spacing {
-    fn quote(self) -> TokenStream {
-        macro_rules! gen_match {
-            ($($i:ident),*) => {
-                match self {
-                    $(Spacing::$i => { quote!(::Spacing::$i) })*
-                }
-            }
-        }
-
-        gen_match!(Alone, Joint)
-    }
+/// Quote a `Span` into a `TokenStream`.
+/// This is needed to implement a custom quoter.
+#[unstable(feature = "proc_macro_quote", issue = "38356")]
+pub fn quote_span(_: Span) -> TokenStream {
+    quote!(::Span::def_site())
 }