Skip to content

Commit 2a3f536

Browse files
committed
Auto merge of rust-lang#50473 - petrochenkov:pmapi, r=alexcrichton
Review proc macro API 1.2 cc rust-lang#38356 Summary of applied changes: - Documentation for proc macro API 1.2 is expanded. - Renamed APIs: `Term` -> `Ident`, `TokenTree::Term` -> `TokenTree::Ident`, `Op` -> `Punct`, `TokenTree::Op` -> `TokenTree::Punct`, `Op::op` -> `Punct::as_char`. - Removed APIs: `Ident::as_str`, use `Display` impl for `Ident` instead. - New APIs (not stabilized in 1.2): `Ident::new_raw` for creating a raw identifier (I'm not sure `new_x` it's a very idiomatic name though). - Runtime changes: - `Punct::new` now ensures that the input `char` is a valid punctuation character in Rust. - `Ident::new` ensures that the input `str` is a valid identifier in Rust. - Lifetimes in proc macros are now represented as two joint tokens - `Punct('\'', Spacing::Joint)` and `Ident("lifetime_name_without_quote")` similarly to multi-character operators. - Stabilized APIs: None yet. A bit of motivation for renaming (although it was already stated in the review comments): - With my compiler frontend glasses on `Ident` is the single most appropriate name for this thing, *especially* if we are doing input validation on construction. `TokenTree::Ident` effectively wraps `token::Ident` or `ast::Ident + is_raw`, its meaning is "identifier" and it's already named `ident` in declarative macros. - Regarding `Punct`, the motivation is that `Op` is actively misleading. The thing doesn't mean an operator, it's neither a subset of operators (there is non-operator punctuation in the language), nor superset (operators can be multicharacter while this thing is always a single character). So I named it `Punct` (first proposed in [the original RFC](rust-lang/rfcs#1566), then [by @SimonSapin](rust-lang#38356 (comment))) , together with input validation it's now a subset of ASCII punctuation character category (`u8::is_ascii_punctuation`).
2 parents 448cc57 + dab8c0a commit 2a3f536

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+595
-210
lines changed

src/libproc_macro/lib.rs

+207-126
Large diffs are not rendered by default.

src/libproc_macro/quote.rs

+48-28
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@
1414
//! This quasiquoter uses macros 2.0 hygiene to reliably access
1515
//! items from `proc_macro`, to build a `proc_macro::TokenStream`.
1616
17-
use {Delimiter, Literal, Spacing, Span, Term, Op, Group, TokenStream, TokenTree};
17+
use {Delimiter, Literal, Spacing, Span, Ident, Punct, Group, TokenStream, TokenTree};
1818

1919
use syntax::ext::base::{ExtCtxt, ProcMacro};
2020
use syntax::parse::token;
21+
use syntax::symbol::Symbol;
2122
use syntax::tokenstream;
2223

2324
pub struct Quoter;
@@ -35,14 +36,14 @@ macro_rules! tt2ts {
3536
}
3637

3738
macro_rules! quote_tok {
38-
(,) => { tt2ts!(Op::new(',', Spacing::Alone)) };
39-
(.) => { tt2ts!(Op::new('.', Spacing::Alone)) };
40-
(:) => { tt2ts!(Op::new(':', Spacing::Alone)) };
41-
(|) => { tt2ts!(Op::new('|', Spacing::Alone)) };
39+
(,) => { tt2ts!(Punct::new(',', Spacing::Alone)) };
40+
(.) => { tt2ts!(Punct::new('.', Spacing::Alone)) };
41+
(:) => { tt2ts!(Punct::new(':', Spacing::Alone)) };
42+
(|) => { tt2ts!(Punct::new('|', Spacing::Alone)) };
4243
(::) => {
4344
[
44-
TokenTree::from(Op::new(':', Spacing::Joint)),
45-
TokenTree::from(Op::new(':', Spacing::Alone)),
45+
TokenTree::from(Punct::new(':', Spacing::Joint)),
46+
TokenTree::from(Punct::new(':', Spacing::Alone)),
4647
].iter()
4748
.cloned()
4849
.map(|mut x| {
@@ -51,13 +52,13 @@ macro_rules! quote_tok {
5152
})
5253
.collect::<TokenStream>()
5354
};
54-
(!) => { tt2ts!(Op::new('!', Spacing::Alone)) };
55-
(<) => { tt2ts!(Op::new('<', Spacing::Alone)) };
56-
(>) => { tt2ts!(Op::new('>', Spacing::Alone)) };
57-
(_) => { tt2ts!(Op::new('_', Spacing::Alone)) };
55+
(!) => { tt2ts!(Punct::new('!', Spacing::Alone)) };
56+
(<) => { tt2ts!(Punct::new('<', Spacing::Alone)) };
57+
(>) => { tt2ts!(Punct::new('>', Spacing::Alone)) };
58+
(_) => { tt2ts!(Punct::new('_', Spacing::Alone)) };
5859
(0) => { tt2ts!(Literal::i8_unsuffixed(0)) };
59-
(&) => { tt2ts!(Op::new('&', Spacing::Alone)) };
60-
($i:ident) => { tt2ts!(Term::new(stringify!($i), Span::def_site())) };
60+
(&) => { tt2ts!(Punct::new('&', Spacing::Alone)) };
61+
($i:ident) => { tt2ts!(Ident::new(stringify!($i), Span::def_site())) };
6162
}
6263

6364
macro_rules! quote_tree {
@@ -110,15 +111,15 @@ impl Quote for TokenStream {
110111
if after_dollar {
111112
after_dollar = false;
112113
match tree {
113-
TokenTree::Term(_) => {
114+
TokenTree::Ident(_) => {
114115
let tree = TokenStream::from(tree);
115116
return Some(quote!(::__internal::unquote(&(unquote tree)),));
116117
}
117-
TokenTree::Op(ref tt) if tt.op() == '$' => {}
118+
TokenTree::Punct(ref tt) if tt.as_char() == '$' => {}
118119
_ => panic!("`$` must be followed by an ident or `$` in `quote!`"),
119120
}
120-
} else if let TokenTree::Op(tt) = tree {
121-
if tt.op() == '$' {
121+
} else if let TokenTree::Punct(ref tt) = tree {
122+
if tt.as_char() == '$' {
122123
after_dollar = true;
123124
return None;
124125
}
@@ -143,9 +144,9 @@ impl Quote for TokenStream {
143144
impl Quote for TokenTree {
144145
fn quote(self) -> TokenStream {
145146
match self {
146-
TokenTree::Op(tt) => quote!(::TokenTree::Op( (quote tt) )),
147+
TokenTree::Punct(tt) => quote!(::TokenTree::Punct( (quote tt) )),
147148
TokenTree::Group(tt) => quote!(::TokenTree::Group( (quote tt) )),
148-
TokenTree::Term(tt) => quote!(::TokenTree::Term( (quote tt) )),
149+
TokenTree::Ident(tt) => quote!(::TokenTree::Ident( (quote tt) )),
149150
TokenTree::Literal(tt) => quote!(::TokenTree::Literal( (quote tt) )),
150151
}
151152
}
@@ -175,15 +176,15 @@ impl Quote for Group {
175176
}
176177
}
177178

178-
impl Quote for Op {
179+
impl Quote for Punct {
179180
fn quote(self) -> TokenStream {
180-
quote!(::Op::new((quote self.op()), (quote self.spacing())))
181+
quote!(::Punct::new((quote self.as_char()), (quote self.spacing())))
181182
}
182183
}
183184

184-
impl Quote for Term {
185+
impl Quote for Ident {
185186
fn quote(self) -> TokenStream {
186-
quote!(::Term::new((quote self.sym.as_str()), (quote self.span())))
187+
quote!(::Ident::new((quote self.sym.as_str()), (quote self.span())))
187188
}
188189
}
189190

@@ -195,14 +196,32 @@ impl Quote for Span {
195196

196197
macro_rules! literals {
197198
($($i:ident),*; $($raw:ident),*) => {
199+
pub struct SpannedSymbol {
200+
sym: Symbol,
201+
span: Span,
202+
}
203+
204+
impl SpannedSymbol {
205+
pub fn new(string: &str, span: Span) -> SpannedSymbol {
206+
SpannedSymbol { sym: Symbol::intern(string), span }
207+
}
208+
}
209+
210+
impl Quote for SpannedSymbol {
211+
fn quote(self) -> TokenStream {
212+
quote!(::__internal::SpannedSymbol::new((quote self.sym.as_str()),
213+
(quote self.span)))
214+
}
215+
}
216+
198217
pub enum LiteralKind {
199218
$($i,)*
200219
$($raw(u16),)*
201220
}
202221

203222
impl LiteralKind {
204-
pub fn with_contents_and_suffix(self, contents: Term, suffix: Option<Term>)
205-
-> Literal {
223+
pub fn with_contents_and_suffix(self, contents: SpannedSymbol,
224+
suffix: Option<SpannedSymbol>) -> Literal {
206225
let sym = contents.sym;
207226
let suffix = suffix.map(|t| t.sym);
208227
match self {
@@ -225,13 +244,14 @@ macro_rules! literals {
225244
}
226245

227246
impl Literal {
228-
fn kind_contents_and_suffix(self) -> (LiteralKind, Term, Option<Term>) {
247+
fn kind_contents_and_suffix(self) -> (LiteralKind, SpannedSymbol, Option<SpannedSymbol>)
248+
{
229249
let (kind, contents) = match self.lit {
230250
$(token::Lit::$i(contents) => (LiteralKind::$i, contents),)*
231251
$(token::Lit::$raw(contents, n) => (LiteralKind::$raw(n), contents),)*
232252
};
233-
let suffix = self.suffix.map(|sym| Term::new(&sym.as_str(), self.span()));
234-
(kind, Term::new(&contents.as_str(), self.span()), suffix)
253+
let suffix = self.suffix.map(|sym| SpannedSymbol::new(&sym.as_str(), self.span()));
254+
(kind, SpannedSymbol::new(&contents.as_str(), self.span()), suffix)
235255
}
236256
}
237257

src/librustc/ich/impls_syntax.rs

+1
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@ fn hash_token<'a, 'gcx, W: StableHasherResult>(
314314
token::Token::Pound |
315315
token::Token::Dollar |
316316
token::Token::Question |
317+
token::Token::SingleQuote |
317318
token::Token::Whitespace |
318319
token::Token::Comment |
319320
token::Token::Eof => {}

src/librustdoc/html/highlight.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ impl<'a> Classifier<'a> {
353353
token::Lifetime(..) => Class::Lifetime,
354354

355355
token::Eof | token::Interpolated(..) |
356-
token::Tilde | token::At | token::DotEq => Class::None,
356+
token::Tilde | token::At | token::DotEq | token::SingleQuote => Class::None,
357357
};
358358

359359
// Anything that didn't return above is the simple case where we the

src/libsyntax/ext/quote.rs

+1
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,7 @@ fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P<ast::Expr> {
711711
token::Pound => "Pound",
712712
token::Dollar => "Dollar",
713713
token::Question => "Question",
714+
token::SingleQuote => "SingleQuote",
714715
token::Eof => "Eof",
715716

716717
token::Whitespace | token::Comment | token::Shebang(_) => {

src/libsyntax/parse/lexer/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1770,6 +1770,12 @@ fn ident_continue(c: Option<char>) -> bool {
17701770
(c > '\x7f' && c.is_xid_continue())
17711771
}
17721772

1773+
// The string is a valid identifier or a lifetime identifier.
1774+
pub fn is_valid_ident(s: &str) -> bool {
1775+
let mut chars = s.chars();
1776+
ident_start(chars.next()) && chars.all(|ch| ident_continue(Some(ch)))
1777+
}
1778+
17731779
#[cfg(test)]
17741780
mod tests {
17751781
use super::*;

src/libsyntax/parse/token.rs

+6
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@ pub enum Token {
210210
Pound,
211211
Dollar,
212212
Question,
213+
/// Used by proc macros for representing lifetimes, not generated by lexer right now.
214+
SingleQuote,
213215
/// An opening delimiter, eg. `{`
214216
OpenDelim(DelimToken),
215217
/// A closing delimiter, eg. `}`
@@ -513,6 +515,10 @@ impl Token {
513515
Colon => ModSep,
514516
_ => return None,
515517
},
518+
SingleQuote => match joint {
519+
Ident(ident, false) => Lifetime(ident),
520+
_ => return None,
521+
},
516522

517523
Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot | DotEq |
518524
DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar |

src/libsyntax/print/pprust.rs

+1
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ pub fn token_to_string(tok: &Token) -> String {
224224
token::Pound => "#".to_string(),
225225
token::Dollar => "$".to_string(),
226226
token::Question => "?".to_string(),
227+
token::SingleQuote => "'".to_string(),
227228

228229
/* Literals */
229230
token::Literal(lit, suf) => {

src/test/compile-fail-fulldeps/proc-macro/auxiliary/attributes-included.rs

+11-11
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub fn bar(attr: TokenStream, input: TokenStream) -> TokenStream {
5353

5454
fn assert_inline(slice: &mut &[TokenTree]) {
5555
match &slice[0] {
56-
TokenTree::Op(tt) => assert_eq!(tt.op(), '#'),
56+
TokenTree::Punct(tt) => assert_eq!(tt.as_char(), '#'),
5757
_ => panic!("expected '#' char"),
5858
}
5959
match &slice[1] {
@@ -65,8 +65,8 @@ fn assert_inline(slice: &mut &[TokenTree]) {
6565

6666
fn assert_doc(slice: &mut &[TokenTree]) {
6767
match &slice[0] {
68-
TokenTree::Op(tt) => {
69-
assert_eq!(tt.op(), '#');
68+
TokenTree::Punct(tt) => {
69+
assert_eq!(tt.as_char(), '#');
7070
assert_eq!(tt.spacing(), Spacing::Alone);
7171
}
7272
_ => panic!("expected #"),
@@ -86,12 +86,12 @@ fn assert_doc(slice: &mut &[TokenTree]) {
8686
}
8787

8888
match &tokens[0] {
89-
TokenTree::Term(tt) => assert_eq!("doc", &*tt.to_string()),
89+
TokenTree::Ident(tt) => assert_eq!("doc", &*tt.to_string()),
9090
_ => panic!("expected `doc`"),
9191
}
9292
match &tokens[1] {
93-
TokenTree::Op(tt) => {
94-
assert_eq!(tt.op(), '=');
93+
TokenTree::Punct(tt) => {
94+
assert_eq!(tt.as_char(), '=');
9595
assert_eq!(tt.spacing(), Spacing::Alone);
9696
}
9797
_ => panic!("expected equals"),
@@ -106,7 +106,7 @@ fn assert_doc(slice: &mut &[TokenTree]) {
106106

107107
fn assert_invoc(slice: &mut &[TokenTree]) {
108108
match &slice[0] {
109-
TokenTree::Op(tt) => assert_eq!(tt.op(), '#'),
109+
TokenTree::Punct(tt) => assert_eq!(tt.as_char(), '#'),
110110
_ => panic!("expected '#' char"),
111111
}
112112
match &slice[1] {
@@ -118,11 +118,11 @@ fn assert_invoc(slice: &mut &[TokenTree]) {
118118

119119
fn assert_foo(slice: &mut &[TokenTree]) {
120120
match &slice[0] {
121-
TokenTree::Term(tt) => assert_eq!(&*tt.to_string(), "fn"),
121+
TokenTree::Ident(tt) => assert_eq!(&*tt.to_string(), "fn"),
122122
_ => panic!("expected fn"),
123123
}
124124
match &slice[1] {
125-
TokenTree::Term(tt) => assert_eq!(&*tt.to_string(), "foo"),
125+
TokenTree::Ident(tt) => assert_eq!(&*tt.to_string(), "foo"),
126126
_ => panic!("expected foo"),
127127
}
128128
match &slice[2] {
@@ -148,8 +148,8 @@ fn fold_tree(input: TokenTree) -> TokenTree {
148148
TokenTree::Group(b) => {
149149
TokenTree::Group(Group::new(b.delimiter(), fold_stream(b.stream())))
150150
}
151-
TokenTree::Op(b) => TokenTree::Op(b),
152-
TokenTree::Term(a) => TokenTree::Term(a),
151+
TokenTree::Punct(b) => TokenTree::Punct(b),
152+
TokenTree::Ident(a) => TokenTree::Ident(a),
153153
TokenTree::Literal(a) => {
154154
if a.to_string() != "\"foo\"" {
155155
TokenTree::Literal(a)

src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue_38586.rs

-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
// force-host
1212
// no-prefer-dynamic
1313

14-
#![feature(proc_macro, proc_macro_lib)]
1514
#![crate_type = "proc-macro"]
1615

1716
extern crate proc_macro;

src/test/compile-fail-fulldeps/proc-macro/issue-38586.rs

-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111
// aux-build:issue_38586.rs
1212
// ignore-stage1
1313

14-
#![feature(proc_macro)]
15-
1614
#[macro_use]
1715
extern crate issue_38586;
1816

src/test/compile-fail-fulldeps/proc-macro/lints_in_proc_macros.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
// aux-build:bang_proc_macro2.rs
1212
// ignore-stage1
1313

14-
#![feature(proc_macro, proc_macro_non_items)]
14+
#![feature(use_extern_macros, proc_macro_non_items)]
1515
#![allow(unused_macros)]
1616

1717
extern crate bang_proc_macro2;

src/test/compile-fail-fulldeps/proc-macro/macro-use-bang.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
// aux-build:bang_proc_macro.rs
1212

13-
#![feature(proc_macro, proc_macro_non_items)]
13+
#![feature(proc_macro_non_items)]
1414

1515
#[macro_use]
1616
extern crate bang_proc_macro;

src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates2.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
// aux-build:proc-macro-gates.rs
1212

13-
#![feature(proc_macro, stmt_expr_attributes)]
13+
#![feature(use_extern_macros, stmt_expr_attributes)]
1414

1515
extern crate proc_macro_gates as foo;
1616

src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub fn cond(input: TokenStream) -> TokenStream {
3333
panic!("Invalid macro usage in cond: {}", cond);
3434
}
3535
let is_else = match test {
36-
TokenTree::Term(word) => &*word.to_string() == "else",
36+
TokenTree::Ident(ref word) => &*word.to_string() == "else",
3737
_ => false,
3838
};
3939
conds.push(if is_else || input.peek().is_none() {

src/test/run-pass-fulldeps/auxiliary/hello_macro.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
// no-prefer-dynamic
1212

1313
#![crate_type = "proc-macro"]
14-
#![feature(proc_macro, proc_macro_lib, proc_macro_non_items)]
14+
#![feature(proc_macro, proc_macro_non_items)]
1515

1616
extern crate proc_macro;
1717

src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
// no-prefer-dynamic
1212

1313
#![crate_type = "proc-macro"]
14-
#![feature(proc_macro, proc_macro_lib, proc_macro_non_items)]
14+
#![feature(proc_macro, proc_macro_non_items)]
1515

1616
extern crate proc_macro;
1717

src/test/run-pass-fulldeps/macro-quote-cond.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
// aux-build:cond_plugin.rs
1212
// ignore-stage1
1313

14-
#![feature(proc_macro, proc_macro_non_items)]
14+
#![feature(use_extern_macros, proc_macro_non_items)]
1515

1616
extern crate cond_plugin;
1717

src/test/run-pass-fulldeps/macro-quote-test.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
// aux-build:hello_macro.rs
1414
// ignore-stage1
1515

16-
#![feature(proc_macro, proc_macro_non_items)]
16+
#![feature(use_extern_macros, proc_macro_non_items)]
1717

1818
extern crate hello_macro;
1919

src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ fn count_compound_ops_helper(input: TokenStream) -> u32 {
2828
let mut count = 0;
2929
for token in input {
3030
match &token {
31-
TokenTree::Op(tt) if tt.spacing() == Spacing::Alone => {
31+
TokenTree::Punct(tt) if tt.spacing() == Spacing::Alone => {
3232
count += 1;
3333
}
3434
TokenTree::Group(tt) => {

0 commit comments

Comments
 (0)