Skip to content

Commit fbcc673

Browse files
committed
proc_macro: use the proc_macro API at runtime to construct quasi-quoted TokenStream's.
1 parent a51c69e commit fbcc673

File tree

2 files changed

+118
-130
lines changed

2 files changed

+118
-130
lines changed

src/libproc_macro/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -728,7 +728,7 @@ impl TokenTree {
728728
#[unstable(feature = "proc_macro_internals", issue = "27812")]
729729
#[doc(hidden)]
730730
pub mod __internal {
731-
pub use quote::{Quoter, __rt};
731+
pub use quote::{LiteralKind, Quoter, unquote};
732732

733733
use std::cell::Cell;
734734

src/libproc_macro/quote.rs

Lines changed: 117 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -11,39 +11,19 @@
1111
//! # Quasiquoter
1212
//! This file contains the implementation internals of the quasiquoter provided by `quote!`.
1313
14-
//! This quasiquoter uses macros 2.0 hygiene to reliably use items from `__rt`,
15-
//! including re-exported API `libsyntax`, to build a `syntax::tokenstream::TokenStream`
16-
//! and wrap it into a `proc_macro::TokenStream`.
14+
//! This quasiquoter uses macros 2.0 hygiene to reliably access
15+
//! items from `proc_macro`, to build a `proc_macro::TokenStream`.
1716
1817
use {Delimiter, Literal, Spacing, Span, Term, TokenNode, TokenStream, TokenTree};
1918

20-
use std::iter;
2119
use syntax::ext::base::{ExtCtxt, ProcMacro};
2220
use syntax::parse::token;
2321
use syntax::tokenstream;
2422

2523
pub struct Quoter;
2624

27-
pub mod __rt {
28-
pub use syntax::ast::Ident;
29-
pub use syntax::parse::token;
30-
pub use syntax::symbol::Symbol;
31-
pub use syntax::tokenstream::{TokenStream, TokenStreamBuilder, TokenTree, Delimited};
32-
33-
use syntax_pos::Span;
34-
use syntax_pos::hygiene::SyntaxContext;
35-
36-
pub fn unquote<T: Into<::TokenStream> + Clone>(tokens: &T) -> TokenStream {
37-
T::into(tokens.clone()).0
38-
}
39-
40-
pub fn ctxt() -> SyntaxContext {
41-
::__internal::with_sess(|(_, mark)| SyntaxContext::empty().apply_mark(mark))
42-
}
43-
44-
pub fn span() -> Span {
45-
::Span::default().0
46-
}
25+
pub fn unquote<T: Into<TokenStream> + Clone>(tokens: &T) -> TokenStream {
26+
T::into(tokens.clone())
4727
}
4828

4929
pub trait Quote {
@@ -75,7 +55,6 @@ macro_rules! quote_tree {
7555
(($($t:tt)*)) => { TokenNode::Group(Delimiter::Parenthesis, quote!($($t)*)) };
7656
([$($t:tt)*]) => { TokenNode::Group(Delimiter::Bracket, quote!($($t)*)) };
7757
({$($t:tt)*}) => { TokenNode::Group(Delimiter::Brace, quote!($($t)*)) };
78-
(rt) => { quote!(::__internal::__rt) };
7958
($t:tt) => { quote_tok!($t) };
8059
}
8160

@@ -96,9 +75,7 @@ impl ProcMacro for Quoter {
9675
let mut info = cx.current_expansion.mark.expn_info().unwrap();
9776
info.callee.allow_internal_unstable = true;
9877
cx.current_expansion.mark.set_expn_info(info);
99-
::__internal::set_sess(cx, || quote!(::TokenStream {
100-
0: (quote TokenStream(stream))
101-
}).0)
78+
::__internal::set_sess(cx, || TokenStream(stream).quote().0)
10279
}
10380
}
10481

@@ -113,102 +90,61 @@ impl<T: Quote> Quote for Option<T> {
11390

11491
impl Quote for TokenStream {
11592
fn quote(self) -> TokenStream {
93+
if self.is_empty() {
94+
return quote!(::TokenStream::empty());
95+
}
11696
let mut after_dollar = false;
117-
let stream = iter::once(quote!(rt::TokenStreamBuilder::new()))
118-
.chain(self.into_iter().filter_map(|tree| {
119-
if after_dollar {
120-
after_dollar = false;
121-
match tree.kind {
122-
TokenNode::Term(_) => {
123-
return Some(quote!(.add(rt::unquote(&(unquote tree)))));
124-
}
125-
TokenNode::Op('$', _) => {}
126-
_ => panic!("`$` must be followed by an ident or `$` in `quote!`"),
97+
let tokens = self.into_iter().filter_map(|tree| {
98+
if after_dollar {
99+
after_dollar = false;
100+
match tree.kind {
101+
TokenNode::Term(_) => {
102+
return Some(quote!(::__internal::unquote(&(unquote tree)),));
127103
}
128-
} else if let TokenNode::Op('$', _) = tree.kind {
129-
after_dollar = true;
130-
return None;
104+
TokenNode::Op('$', _) => {}
105+
_ => panic!("`$` must be followed by an ident or `$` in `quote!`"),
131106
}
107+
} else if let TokenNode::Op('$', _) = tree.kind {
108+
after_dollar = true;
109+
return None;
110+
}
132111

133-
Some(quote!(.add(rt::TokenStream::from((quote tree)))))
134-
}))
135-
.chain(iter::once(quote!(.build()))).collect();
112+
Some(quote!(::TokenStream::from((quote tree)),))
113+
}).collect::<TokenStream>();
136114

137115
if after_dollar {
138116
panic!("unexpected trailing `$` in `quote!`");
139117
}
140118

141-
stream
119+
quote!([(unquote tokens)].iter().cloned().collect::<::TokenStream>())
142120
}
143121
}
144122

145123
impl Quote for TokenTree {
146124
fn quote(self) -> TokenStream {
147-
let (op, kind) = match self.kind {
148-
TokenNode::Op(op, kind) => (op, kind),
149-
TokenNode::Group(delimiter, tokens) => {
150-
return quote! {
151-
rt::TokenTree::Delimited((quote self.span), rt::Delimited {
152-
delim: (quote delimiter),
153-
tts: (quote tokens).into()
154-
})
155-
};
156-
},
157-
TokenNode::Term(term) => {
158-
let variant = if term.as_str().starts_with("'") {
159-
quote!(Lifetime)
160-
} else {
161-
quote!(Ident)
162-
};
163-
return quote! {
164-
rt::TokenTree::Token((quote self.span),
165-
rt::token::(unquote variant)(rt::Ident {
166-
name: (quote term),
167-
ctxt: rt::ctxt()
168-
}))
169-
};
170-
}
171-
TokenNode::Literal(lit) => {
172-
return quote! {
173-
rt::TokenTree::Token((quote self.span), (quote lit))
174-
};
125+
quote!(::TokenTree { span: (quote self.span), kind: (quote self.kind) })
126+
}
127+
}
128+
129+
impl Quote for TokenNode {
130+
fn quote(self) -> TokenStream {
131+
macro_rules! gen_match {
132+
($($i:ident($($arg:ident),+)),*) => {
133+
match self {
134+
$(TokenNode::$i($($arg),+) => quote! {
135+
::TokenNode::$i($((quote $arg)),+)
136+
},)*
137+
}
175138
}
176-
};
177-
178-
let token = match op {
179-
'=' => quote!(Eq),
180-
'<' => quote!(Lt),
181-
'>' => quote!(Gt),
182-
'!' => quote!(Not),
183-
'~' => quote!(Tilde),
184-
'+' => quote!(BinOp(rt::token::BinOpToken::Plus)),
185-
'-' => quote!(BinOp(rt::token::BinOpToken::Minus)),
186-
'*' => quote!(BinOp(rt::token::BinOpToken::Star)),
187-
'/' => quote!(BinOp(rt::token::BinOpToken::Slash)),
188-
'%' => quote!(BinOp(rt::token::BinOpToken::Percent)),
189-
'^' => quote!(BinOp(rt::token::BinOpToken::Caret)),
190-
'&' => quote!(BinOp(rt::token::BinOpToken::And)),
191-
'|' => quote!(BinOp(rt::token::BinOpToken::Or)),
192-
'@' => quote!(At),
193-
'.' => quote!(Dot),
194-
',' => quote!(Comma),
195-
';' => quote!(Semi),
196-
':' => quote!(Colon),
197-
'#' => quote!(Pound),
198-
'$' => quote!(Dollar),
199-
'?' => quote!(Question),
200-
'_' => quote!(Underscore),
201-
_ => panic!("unsupported character {}", op),
202-
};
203-
204-
match kind {
205-
Spacing::Alone => quote! {
206-
rt::TokenTree::Token((quote self.span), rt::token::(unquote token))
207-
},
208-
Spacing::Joint => quote! {
209-
rt::TokenTree::Token((quote self.span), rt::token::(unquote token)).joint()
210-
},
211139
}
140+
141+
gen_match! { Op(op, kind), Group(delim, tokens), Term(term), Literal(lit) }
142+
}
143+
}
144+
145+
impl Quote for char {
146+
fn quote(self) -> TokenStream {
147+
TokenNode::Literal(Literal::character(self)).into()
212148
}
213149
}
214150

@@ -226,52 +162,104 @@ impl Quote for usize {
226162

227163
impl Quote for Term {
228164
fn quote(self) -> TokenStream {
229-
quote!(rt::Symbol::intern((quote self.as_str())))
165+
quote!(::Term::intern((quote self.as_str())))
230166
}
231167
}
232168

233169
impl Quote for Span {
234170
fn quote(self) -> TokenStream {
235-
quote!(rt::span())
171+
quote!(::Span::default())
236172
}
237173
}
238174

239-
impl Quote for Literal {
240-
fn quote(self) -> TokenStream {
241-
let (lit, sfx) = match self.0 {
242-
token::Literal(lit, sfx) => (lit, sfx.map(Term)),
243-
_ => panic!("unsupported literal {:?}", self.0),
244-
};
175+
macro_rules! literals {
176+
($($i:ident),*; $($raw:ident),*) => {
177+
pub enum LiteralKind {
178+
$($i,)*
179+
$($raw(usize),)*
180+
}
245181

246-
macro_rules! gen_match {
247-
($($i:ident),*; $($raw:ident),*) => {
248-
match lit {
249-
$(token::Lit::$i(lit) => quote! {
250-
rt::token::Literal(rt::token::Lit::$i((quote Term(lit))),
251-
(quote sfx))
182+
impl LiteralKind {
183+
pub fn with_contents_and_suffix(self, contents: Term, suffix: Option<Term>)
184+
-> Literal {
185+
let contents = contents.0;
186+
let suffix = suffix.map(|t| t.0);
187+
match self {
188+
$(LiteralKind::$i => {
189+
Literal(token::Literal(token::Lit::$i(contents), suffix))
190+
})*
191+
$(LiteralKind::$raw(n) => {
192+
Literal(token::Literal(token::Lit::$raw(contents, n), suffix))
193+
})*
194+
}
195+
}
196+
}
197+
198+
impl Literal {
199+
fn kind_contents_and_suffix(self) -> (LiteralKind, Term, Option<Term>) {
200+
let (lit, suffix) = match self.0 {
201+
token::Literal(lit, suffix) => (lit, suffix),
202+
_ => panic!("unsupported literal {:?}", self.0),
203+
};
204+
205+
let (kind, contents) = match lit {
206+
$(token::Lit::$i(contents) => (LiteralKind::$i, contents),)*
207+
$(token::Lit::$raw(contents, n) => (LiteralKind::$raw(n), contents),)*
208+
};
209+
(kind, Term(contents), suffix.map(Term))
210+
}
211+
}
212+
213+
impl Quote for LiteralKind {
214+
fn quote(self) -> TokenStream {
215+
match self {
216+
$(LiteralKind::$i => quote! {
217+
::__internal::LiteralKind::$i
252218
},)*
253-
$(token::Lit::$raw(lit, n) => quote! {
254-
rt::token::Literal(rt::token::Lit::$raw((quote Term(lit)), (quote n)),
255-
(quote sfx))
219+
$(LiteralKind::$raw(n) => quote! {
220+
::__internal::LiteralKind::$raw((quote n))
256221
},)*
257222
}
258223
}
259224
}
260225

261-
gen_match!(Byte, Char, Float, Str_, Integer, ByteStr; StrRaw, ByteStrRaw)
226+
impl Quote for Literal {
227+
fn quote(self) -> TokenStream {
228+
let (kind, contents, suffix) = self.kind_contents_and_suffix();
229+
quote! {
230+
(quote kind).with_contents_and_suffix((quote contents), (quote suffix))
231+
}
232+
}
233+
}
262234
}
263235
}
264236

237+
literals!(Byte, Char, Float, Str_, Integer, ByteStr; StrRaw, ByteStrRaw);
238+
265239
impl Quote for Delimiter {
266240
fn quote(self) -> TokenStream {
267241
macro_rules! gen_match {
268-
($($i:ident => $j:ident),*) => {
242+
($($i:ident),*) => {
243+
match self {
244+
$(Delimiter::$i => { quote!(::Delimiter::$i) })*
245+
}
246+
}
247+
}
248+
249+
gen_match!(Parenthesis, Brace, Bracket, None)
250+
}
251+
}
252+
253+
impl Quote for Spacing {
254+
fn quote(self) -> TokenStream {
255+
macro_rules! gen_match {
256+
($($i:ident),*) => {
269257
match self {
270-
$(Delimiter::$i => { quote!(rt::token::DelimToken::$j) })*
258+
$(Spacing::$i => { quote!(::Spacing::$i) })*
271259
}
272260
}
273261
}
274262

275-
gen_match!(Parenthesis => Paren, Brace => Brace, Bracket => Bracket, None => NoDelim)
263+
gen_match!(Alone, Joint)
276264
}
277265
}

0 commit comments

Comments
 (0)