blob: 31ba7654264cf004e24275d3048348ddaeefb321 [file] [log] [blame]
Alex Crichton1fd0e8a2018-02-04 21:29:13 -08001//! A "shim crate" intended to multiplex the [`proc_macro`] API on to stable
2//! Rust.
Alex Crichtonbabc99e2017-07-05 18:00:29 -07003//!
4//! Procedural macros in Rust operate over the upstream
Alex Crichton1fd0e8a2018-02-04 21:29:13 -08005//! [`proc_macro::TokenStream`][ts] type. This type currently is quite
6//! conservative and exposed no internal implementation details. Nightly
7//! compilers, however, contain a much richer interface. This richer interface
8//! allows fine-grained inspection of the token stream which avoids
9//! stringification/re-lexing and also preserves span information.
Alex Crichtonbabc99e2017-07-05 18:00:29 -070010//!
Alex Crichton1fd0e8a2018-02-04 21:29:13 -080011//! The upcoming APIs added to [`proc_macro`] upstream are the foundation for
Alex Crichtonbabc99e2017-07-05 18:00:29 -070012//! productive procedural macros in the ecosystem. To help prepare the ecosystem
13//! for using them this crate serves to both compile on stable and nightly and
14//! mirrors the API-to-be. The intention is that procedural macros which switch
15//! to use this crate will be trivially able to switch to the upstream
16//! `proc_macro` crate once its API stabilizes.
17//!
David Tolnayd66ecf62018-01-02 20:05:42 -080018//! In the meantime this crate also has a `nightly` Cargo feature which
Alex Crichton1fd0e8a2018-02-04 21:29:13 -080019//! enables it to reimplement itself with the unstable API of [`proc_macro`].
Alex Crichtonbabc99e2017-07-05 18:00:29 -070020//! This'll allow immediate usage of the beneficial upstream API, particularly
21//! around preserving span information.
Alex Crichton1fd0e8a2018-02-04 21:29:13 -080022//!
23//! [`proc_macro`]: https://doc.rust-lang.org/proc_macro/
24//! [ts]: https://doc.rust-lang.org/proc_macro/struct.TokenStream.html
Alex Crichtonbabc99e2017-07-05 18:00:29 -070025
David Tolnay15cc4982018-01-08 08:03:27 -080026// Proc-macro2 types in rustdoc of other crates get linked to here.
David Tolnayeca28d42018-01-21 21:17:28 -080027#![doc(html_root_url = "https://docs.rs/proc-macro2/0.2.2")]
David Tolnay15cc4982018-01-08 08:03:27 -080028
David Tolnayd66ecf62018-01-02 20:05:42 -080029#![cfg_attr(feature = "nightly", feature(proc_macro))]
Alex Crichtoncbec8ec2017-06-02 13:19:33 -070030
Alex Crichton0e8e7f42018-02-22 06:15:13 -080031#[cfg(feature = "proc-macro")]
Alex Crichton44bffbc2017-05-19 17:51:59 -070032extern crate proc_macro;
33
David Tolnayd66ecf62018-01-02 20:05:42 -080034#[cfg(not(feature = "nightly"))]
David Tolnayb1032662017-05-31 15:52:28 -070035extern crate unicode_xid;
Alex Crichton44bffbc2017-05-19 17:51:59 -070036
37use std::fmt;
Alex Crichton44bffbc2017-05-19 17:51:59 -070038use std::str::FromStr;
39use std::iter::FromIterator;
40
David Tolnayb1032662017-05-31 15:52:28 -070041#[macro_use]
David Tolnayd66ecf62018-01-02 20:05:42 -080042#[cfg(not(feature = "nightly"))]
David Tolnayb1032662017-05-31 15:52:28 -070043mod strnom;
44
Alex Crichton44bffbc2017-05-19 17:51:59 -070045#[path = "stable.rs"]
David Tolnayd66ecf62018-01-02 20:05:42 -080046#[cfg(not(feature = "nightly"))]
Alex Crichtonb15c6352017-05-19 19:36:36 -070047mod imp;
48#[path = "unstable.rs"]
David Tolnayd66ecf62018-01-02 20:05:42 -080049#[cfg(feature = "nightly")]
Alex Crichton44bffbc2017-05-19 17:51:59 -070050mod imp;
51
David Tolnaycb1b85f2017-06-03 16:40:35 -070052#[macro_use]
53mod macros;
54
55#[derive(Clone)]
Alex Crichton44bffbc2017-05-19 17:51:59 -070056pub struct TokenStream(imp::TokenStream);
57
Alex Crichton44bffbc2017-05-19 17:51:59 -070058pub struct LexError(imp::LexError);
59
60impl FromStr for TokenStream {
61 type Err = LexError;
62
63 fn from_str(src: &str) -> Result<TokenStream, LexError> {
64 match src.parse() {
65 Ok(e) => Ok(TokenStream(e)),
66 Err(e) => Err(LexError(e)),
67 }
68 }
69}
70
Alex Crichton0e8e7f42018-02-22 06:15:13 -080071#[cfg(feature = "proc-macro")]
Alex Crichton44bffbc2017-05-19 17:51:59 -070072impl From<proc_macro::TokenStream> for TokenStream {
73 fn from(inner: proc_macro::TokenStream) -> TokenStream {
74 TokenStream(inner.into())
75 }
76}
77
Alex Crichton0e8e7f42018-02-22 06:15:13 -080078#[cfg(feature = "proc-macro")]
Alex Crichton44bffbc2017-05-19 17:51:59 -070079impl From<TokenStream> for proc_macro::TokenStream {
80 fn from(inner: TokenStream) -> proc_macro::TokenStream {
81 inner.0.into()
82 }
83}
84
85impl From<TokenTree> for TokenStream {
86 fn from(tree: TokenTree) -> TokenStream {
87 TokenStream(tree.into())
88 }
89}
90
Alex Crichton44bffbc2017-05-19 17:51:59 -070091impl<T: Into<TokenStream>> FromIterator<T> for TokenStream {
92 fn from_iter<I: IntoIterator<Item = T>>(streams: I) -> Self {
93 TokenStream(streams.into_iter().map(|t| t.into().0).collect())
94 }
95}
96
97impl IntoIterator for TokenStream {
98 type Item = TokenTree;
Alex Crichton1a7f7622017-07-05 17:47:15 -070099 type IntoIter = TokenTreeIter;
Alex Crichton44bffbc2017-05-19 17:51:59 -0700100
Alex Crichton1a7f7622017-07-05 17:47:15 -0700101 fn into_iter(self) -> TokenTreeIter {
102 TokenTreeIter(self.0.into_iter())
Alex Crichton44bffbc2017-05-19 17:51:59 -0700103 }
104}
105
106impl TokenStream {
107 pub fn empty() -> TokenStream {
108 TokenStream(imp::TokenStream::empty())
109 }
110
111 pub fn is_empty(&self) -> bool {
112 self.0.is_empty()
113 }
114}
115
Nika Layzellb35a9a32017-12-30 14:34:35 -0500116// Returned by reference, so we can't easily wrap it.
David Tolnay1ebe3972018-01-02 20:14:20 -0800117#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500118pub use imp::FileName;
119
David Tolnay1ebe3972018-01-02 20:14:20 -0800120#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500121#[derive(Clone, PartialEq, Eq)]
122pub struct SourceFile(imp::SourceFile);
123
David Tolnay1ebe3972018-01-02 20:14:20 -0800124#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500125impl SourceFile {
126 /// Get the path to this source file as a string.
Nika Layzellb35a9a32017-12-30 14:34:35 -0500127 pub fn path(&self) -> &FileName {
128 self.0.path()
Nika Layzellf8d5f212017-12-11 14:07:02 -0500129 }
130
131 pub fn is_real(&self) -> bool {
132 self.0.is_real()
133 }
134}
135
David Tolnay1ebe3972018-01-02 20:14:20 -0800136#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500137impl AsRef<FileName> for SourceFile {
138 fn as_ref(&self) -> &FileName {
139 self.0.path()
Nika Layzellf8d5f212017-12-11 14:07:02 -0500140 }
141}
142
David Tolnay1ebe3972018-01-02 20:14:20 -0800143#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500144impl fmt::Debug for SourceFile {
145 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
146 self.0.fmt(f)
147 }
148}
149
David Tolnay1ebe3972018-01-02 20:14:20 -0800150#[cfg(procmacro2_semver_exempt)]
Nika Layzell1ecb6ce2017-12-30 14:34:05 -0500151pub struct LineColumn {
152 pub line: usize,
153 pub column: usize,
154}
Nika Layzellf8d5f212017-12-11 14:07:02 -0500155
David Tolnaycb1b85f2017-06-03 16:40:35 -0700156#[derive(Copy, Clone)]
Alex Crichton44bffbc2017-05-19 17:51:59 -0700157pub struct Span(imp::Span);
158
Alex Crichton44bffbc2017-05-19 17:51:59 -0700159impl Span {
160 pub fn call_site() -> Span {
161 Span(imp::Span::call_site())
162 }
Alex Crichtone6085b72017-11-21 07:24:25 -0800163
164 pub fn def_site() -> Span {
165 Span(imp::Span::def_site())
166 }
Nika Layzellf8d5f212017-12-11 14:07:02 -0500167
David Tolnay4e8e3972018-01-05 18:10:22 -0800168 /// Creates a new span with the same line/column information as `self` but
169 /// that resolves symbols as though it were at `other`.
170 pub fn resolved_at(&self, other: Span) -> Span {
171 Span(self.0.resolved_at(other.0))
172 }
173
174 /// Creates a new span with the same name resolution behavior as `self` but
175 /// with the line/column information of `other`.
176 pub fn located_at(&self, other: Span) -> Span {
177 Span(self.0.located_at(other.0))
178 }
179
David Tolnayd66ecf62018-01-02 20:05:42 -0800180 /// This method is only available when the `"nightly"` feature is enabled.
Alex Crichton0e8e7f42018-02-22 06:15:13 -0800181 #[cfg(all(feature = "nightly", feature = "proc-macro"))]
David Tolnay16a17202017-12-31 10:47:24 -0500182 pub fn unstable(self) -> proc_macro::Span {
183 self.0.unstable()
184 }
185
David Tolnay1ebe3972018-01-02 20:14:20 -0800186 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500187 pub fn source_file(&self) -> SourceFile {
188 SourceFile(self.0.source_file())
189 }
190
David Tolnay1ebe3972018-01-02 20:14:20 -0800191 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500192 pub fn start(&self) -> LineColumn {
Nika Layzell1ecb6ce2017-12-30 14:34:05 -0500193 let imp::LineColumn{ line, column } = self.0.start();
David Tolnay79105e52017-12-31 11:03:04 -0500194 LineColumn { line: line, column: column }
Nika Layzellf8d5f212017-12-11 14:07:02 -0500195 }
196
David Tolnay1ebe3972018-01-02 20:14:20 -0800197 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500198 pub fn end(&self) -> LineColumn {
Nika Layzell1ecb6ce2017-12-30 14:34:05 -0500199 let imp::LineColumn{ line, column } = self.0.end();
David Tolnay79105e52017-12-31 11:03:04 -0500200 LineColumn { line: line, column: column }
Nika Layzellf8d5f212017-12-11 14:07:02 -0500201 }
202
David Tolnay1ebe3972018-01-02 20:14:20 -0800203 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500204 pub fn join(&self, other: Span) -> Option<Span> {
205 self.0.join(other.0).map(Span)
206 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700207}
208
David Tolnay977f8282017-05-31 17:41:33 -0700209#[derive(Clone, Debug)]
Alex Crichton44bffbc2017-05-19 17:51:59 -0700210pub struct TokenTree {
211 pub span: Span,
Alex Crichton1a7f7622017-07-05 17:47:15 -0700212 pub kind: TokenNode,
213}
214
215impl From<TokenNode> for TokenTree {
216 fn from(kind: TokenNode) -> TokenTree {
David Tolnay1ce3a792018-01-07 12:21:03 -0800217 TokenTree { span: Span::def_site(), kind: kind }
Alex Crichton1a7f7622017-07-05 17:47:15 -0700218 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700219}
220
Alex Crichton44bffbc2017-05-19 17:51:59 -0700221impl fmt::Display for TokenTree {
222 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
223 TokenStream::from(self.clone()).fmt(f)
224 }
225}
226
David Tolnay977f8282017-05-31 17:41:33 -0700227#[derive(Clone, Debug)]
Alex Crichton1a7f7622017-07-05 17:47:15 -0700228pub enum TokenNode {
229 Group(Delimiter, TokenStream),
230 Term(Term),
231 Op(char, Spacing),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700232 Literal(Literal),
233}
234
Michael Layzell5372f4b2017-06-02 10:29:31 -0400235#[derive(Copy, Clone, Debug, Eq, PartialEq)]
Alex Crichton44bffbc2017-05-19 17:51:59 -0700236pub enum Delimiter {
237 Parenthesis,
238 Brace,
239 Bracket,
240 None,
241}
242
David Tolnaycb1b85f2017-06-03 16:40:35 -0700243#[derive(Copy, Clone)]
Alex Crichton1a7f7622017-07-05 17:47:15 -0700244pub struct Term(imp::Term);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700245
Alex Crichton1a7f7622017-07-05 17:47:15 -0700246impl Term {
247 pub fn intern(string: &str) -> Term {
David Tolnay10effeb2018-01-06 11:07:49 -0800248 Term(imp::Term::intern(string))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700249 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700250
Alex Crichton43881252017-05-26 08:51:06 -0700251 pub fn as_str(&self) -> &str {
David Tolnay10effeb2018-01-06 11:07:49 -0800252 self.0.as_str()
Alex Crichton44bffbc2017-05-19 17:51:59 -0700253 }
254}
255
Lukas Kalbertodteb3f9302017-08-20 18:58:41 +0200256#[derive(Copy, Clone, Debug, Eq, PartialEq)]
Alex Crichton1a7f7622017-07-05 17:47:15 -0700257pub enum Spacing {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700258 Alone,
259 Joint,
260}
261
David Tolnaycb1b85f2017-06-03 16:40:35 -0700262#[derive(Clone)]
Alex Crichton44bffbc2017-05-19 17:51:59 -0700263pub struct Literal(imp::Literal);
264
Alex Crichton1a7f7622017-07-05 17:47:15 -0700265macro_rules! int_literals {
266 ($($kind:ident,)*) => ($(
267 pub fn $kind(n: $kind) -> Literal {
268 Literal(n.into())
269 }
270 )*)
271}
272
Alex Crichton852d53d2017-05-19 19:25:08 -0700273impl Literal {
Alex Crichton1a7f7622017-07-05 17:47:15 -0700274 pub fn integer(s: i64) -> Literal {
275 Literal(imp::Literal::integer(s))
276 }
277
278 int_literals! {
Alex Crichton1a16c782017-07-05 18:06:36 -0700279 u8, u16, u32, u64, usize,
280 i8, i16, i32, i64, isize,
Alex Crichton1a7f7622017-07-05 17:47:15 -0700281 }
282
283 pub fn float(f: f64) -> Literal {
284 Literal(imp::Literal::float(f))
285 }
286
287 pub fn f64(f: f64) -> Literal {
288 Literal(f.into())
289 }
290
291 pub fn f32(f: f32) -> Literal {
292 Literal(f.into())
293 }
294
295 pub fn string(string: &str) -> Literal {
296 Literal(string.into())
297 }
298
299 pub fn character(ch: char) -> Literal {
300 Literal(ch.into())
Alex Crichton76a5cc82017-05-23 07:01:44 -0700301 }
302
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700303 pub fn byte_string(s: &[u8]) -> Literal {
304 Literal(imp::Literal::byte_string(s))
Alex Crichton852d53d2017-05-19 19:25:08 -0700305 }
Alex Crichton76a5cc82017-05-23 07:01:44 -0700306
Alex Crichton1a7f7622017-07-05 17:47:15 -0700307 // =======================================================================
308 // Not present upstream in proc_macro yet
309
310 pub fn byte_char(b: u8) -> Literal {
311 Literal(imp::Literal::byte_char(b))
312 }
313
Alex Crichton76a5cc82017-05-23 07:01:44 -0700314 pub fn doccomment(s: &str) -> Literal {
315 Literal(imp::Literal::doccomment(s))
316 }
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700317
Alex Crichton31316622017-05-26 12:54:47 -0700318 pub fn raw_string(s: &str, pounds: usize) -> Literal {
319 Literal(imp::Literal::raw_string(s, pounds))
320 }
321
322 pub fn raw_byte_string(s: &str, pounds: usize) -> Literal {
323 Literal(imp::Literal::raw_byte_string(s, pounds))
324 }
Alex Crichton852d53d2017-05-19 19:25:08 -0700325}
326
Alex Crichton1a7f7622017-07-05 17:47:15 -0700327pub struct TokenTreeIter(imp::TokenTreeIter);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700328
Alex Crichton1a7f7622017-07-05 17:47:15 -0700329impl Iterator for TokenTreeIter {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700330 type Item = TokenTree;
331
332 fn next(&mut self) -> Option<TokenTree> {
333 self.0.next()
334 }
335}
David Tolnaycb1b85f2017-06-03 16:40:35 -0700336
337forward_fmt!(Debug for LexError);
338forward_fmt!(Debug for Literal);
339forward_fmt!(Debug for Span);
Alex Crichton1a7f7622017-07-05 17:47:15 -0700340forward_fmt!(Debug for Term);
341forward_fmt!(Debug for TokenTreeIter);
David Tolnaycb1b85f2017-06-03 16:40:35 -0700342forward_fmt!(Debug for TokenStream);
343forward_fmt!(Display for Literal);
344forward_fmt!(Display for TokenStream);