blob: d08988c0f6e834ec5e9ab00345775f8ed25408ea [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 Crichton44bffbc2017-05-19 17:51:59 -070031extern crate proc_macro;
32
David Tolnayd66ecf62018-01-02 20:05:42 -080033#[cfg(not(feature = "nightly"))]
David Tolnayb1032662017-05-31 15:52:28 -070034extern crate unicode_xid;
Alex Crichton44bffbc2017-05-19 17:51:59 -070035
36use std::fmt;
Alex Crichton44bffbc2017-05-19 17:51:59 -070037use std::str::FromStr;
38use std::iter::FromIterator;
39
David Tolnayb1032662017-05-31 15:52:28 -070040#[macro_use]
David Tolnayd66ecf62018-01-02 20:05:42 -080041#[cfg(not(feature = "nightly"))]
David Tolnayb1032662017-05-31 15:52:28 -070042mod strnom;
43
Alex Crichton44bffbc2017-05-19 17:51:59 -070044#[path = "stable.rs"]
David Tolnayd66ecf62018-01-02 20:05:42 -080045#[cfg(not(feature = "nightly"))]
Alex Crichtonb15c6352017-05-19 19:36:36 -070046mod imp;
47#[path = "unstable.rs"]
David Tolnayd66ecf62018-01-02 20:05:42 -080048#[cfg(feature = "nightly")]
Alex Crichton44bffbc2017-05-19 17:51:59 -070049mod imp;
50
David Tolnaycb1b85f2017-06-03 16:40:35 -070051#[macro_use]
52mod macros;
53
54#[derive(Clone)]
Alex Crichton44bffbc2017-05-19 17:51:59 -070055pub struct TokenStream(imp::TokenStream);
56
Alex Crichton44bffbc2017-05-19 17:51:59 -070057pub struct LexError(imp::LexError);
58
59impl FromStr for TokenStream {
60 type Err = LexError;
61
62 fn from_str(src: &str) -> Result<TokenStream, LexError> {
63 match src.parse() {
64 Ok(e) => Ok(TokenStream(e)),
65 Err(e) => Err(LexError(e)),
66 }
67 }
68}
69
Alex Crichton44bffbc2017-05-19 17:51:59 -070070impl From<proc_macro::TokenStream> for TokenStream {
71 fn from(inner: proc_macro::TokenStream) -> TokenStream {
72 TokenStream(inner.into())
73 }
74}
75
76impl From<TokenStream> for proc_macro::TokenStream {
77 fn from(inner: TokenStream) -> proc_macro::TokenStream {
78 inner.0.into()
79 }
80}
81
82impl From<TokenTree> for TokenStream {
83 fn from(tree: TokenTree) -> TokenStream {
84 TokenStream(tree.into())
85 }
86}
87
Alex Crichton44bffbc2017-05-19 17:51:59 -070088impl<T: Into<TokenStream>> FromIterator<T> for TokenStream {
89 fn from_iter<I: IntoIterator<Item = T>>(streams: I) -> Self {
90 TokenStream(streams.into_iter().map(|t| t.into().0).collect())
91 }
92}
93
94impl IntoIterator for TokenStream {
95 type Item = TokenTree;
Alex Crichton1a7f7622017-07-05 17:47:15 -070096 type IntoIter = TokenTreeIter;
Alex Crichton44bffbc2017-05-19 17:51:59 -070097
Alex Crichton1a7f7622017-07-05 17:47:15 -070098 fn into_iter(self) -> TokenTreeIter {
99 TokenTreeIter(self.0.into_iter())
Alex Crichton44bffbc2017-05-19 17:51:59 -0700100 }
101}
102
103impl TokenStream {
104 pub fn empty() -> TokenStream {
105 TokenStream(imp::TokenStream::empty())
106 }
107
108 pub fn is_empty(&self) -> bool {
109 self.0.is_empty()
110 }
111}
112
Nika Layzellb35a9a32017-12-30 14:34:35 -0500113// Returned by reference, so we can't easily wrap it.
David Tolnay1ebe3972018-01-02 20:14:20 -0800114#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500115pub use imp::FileName;
116
David Tolnay1ebe3972018-01-02 20:14:20 -0800117#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500118#[derive(Clone, PartialEq, Eq)]
119pub struct SourceFile(imp::SourceFile);
120
David Tolnay1ebe3972018-01-02 20:14:20 -0800121#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500122impl SourceFile {
123 /// Get the path to this source file as a string.
Nika Layzellb35a9a32017-12-30 14:34:35 -0500124 pub fn path(&self) -> &FileName {
125 self.0.path()
Nika Layzellf8d5f212017-12-11 14:07:02 -0500126 }
127
128 pub fn is_real(&self) -> bool {
129 self.0.is_real()
130 }
131}
132
David Tolnay1ebe3972018-01-02 20:14:20 -0800133#[cfg(procmacro2_semver_exempt)]
Nika Layzellb35a9a32017-12-30 14:34:35 -0500134impl AsRef<FileName> for SourceFile {
135 fn as_ref(&self) -> &FileName {
136 self.0.path()
Nika Layzellf8d5f212017-12-11 14:07:02 -0500137 }
138}
139
David Tolnay1ebe3972018-01-02 20:14:20 -0800140#[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500141impl fmt::Debug for SourceFile {
142 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
143 self.0.fmt(f)
144 }
145}
146
David Tolnay1ebe3972018-01-02 20:14:20 -0800147#[cfg(procmacro2_semver_exempt)]
Nika Layzell1ecb6ce2017-12-30 14:34:05 -0500148pub struct LineColumn {
149 pub line: usize,
150 pub column: usize,
151}
Nika Layzellf8d5f212017-12-11 14:07:02 -0500152
David Tolnaycb1b85f2017-06-03 16:40:35 -0700153#[derive(Copy, Clone)]
Alex Crichton44bffbc2017-05-19 17:51:59 -0700154pub struct Span(imp::Span);
155
Alex Crichton44bffbc2017-05-19 17:51:59 -0700156impl Span {
157 pub fn call_site() -> Span {
158 Span(imp::Span::call_site())
159 }
Alex Crichtone6085b72017-11-21 07:24:25 -0800160
161 pub fn def_site() -> Span {
162 Span(imp::Span::def_site())
163 }
Nika Layzellf8d5f212017-12-11 14:07:02 -0500164
David Tolnay4e8e3972018-01-05 18:10:22 -0800165 /// Creates a new span with the same line/column information as `self` but
166 /// that resolves symbols as though it were at `other`.
167 pub fn resolved_at(&self, other: Span) -> Span {
168 Span(self.0.resolved_at(other.0))
169 }
170
171 /// Creates a new span with the same name resolution behavior as `self` but
172 /// with the line/column information of `other`.
173 pub fn located_at(&self, other: Span) -> Span {
174 Span(self.0.located_at(other.0))
175 }
176
David Tolnayd66ecf62018-01-02 20:05:42 -0800177 /// This method is only available when the `"nightly"` feature is enabled.
178 #[cfg(feature = "nightly")]
David Tolnay16a17202017-12-31 10:47:24 -0500179 pub fn unstable(self) -> proc_macro::Span {
180 self.0.unstable()
181 }
182
David Tolnay1ebe3972018-01-02 20:14:20 -0800183 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500184 pub fn source_file(&self) -> SourceFile {
185 SourceFile(self.0.source_file())
186 }
187
David Tolnay1ebe3972018-01-02 20:14:20 -0800188 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500189 pub fn start(&self) -> LineColumn {
Nika Layzell1ecb6ce2017-12-30 14:34:05 -0500190 let imp::LineColumn{ line, column } = self.0.start();
David Tolnay79105e52017-12-31 11:03:04 -0500191 LineColumn { line: line, column: column }
Nika Layzellf8d5f212017-12-11 14:07:02 -0500192 }
193
David Tolnay1ebe3972018-01-02 20:14:20 -0800194 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500195 pub fn end(&self) -> LineColumn {
Nika Layzell1ecb6ce2017-12-30 14:34:05 -0500196 let imp::LineColumn{ line, column } = self.0.end();
David Tolnay79105e52017-12-31 11:03:04 -0500197 LineColumn { line: line, column: column }
Nika Layzellf8d5f212017-12-11 14:07:02 -0500198 }
199
David Tolnay1ebe3972018-01-02 20:14:20 -0800200 #[cfg(procmacro2_semver_exempt)]
Nika Layzellf8d5f212017-12-11 14:07:02 -0500201 pub fn join(&self, other: Span) -> Option<Span> {
202 self.0.join(other.0).map(Span)
203 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700204}
205
David Tolnay977f8282017-05-31 17:41:33 -0700206#[derive(Clone, Debug)]
Alex Crichton44bffbc2017-05-19 17:51:59 -0700207pub struct TokenTree {
208 pub span: Span,
Alex Crichton1a7f7622017-07-05 17:47:15 -0700209 pub kind: TokenNode,
210}
211
212impl From<TokenNode> for TokenTree {
213 fn from(kind: TokenNode) -> TokenTree {
David Tolnay1ce3a792018-01-07 12:21:03 -0800214 TokenTree { span: Span::def_site(), kind: kind }
Alex Crichton1a7f7622017-07-05 17:47:15 -0700215 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700216}
217
Alex Crichton44bffbc2017-05-19 17:51:59 -0700218impl fmt::Display for TokenTree {
219 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
220 TokenStream::from(self.clone()).fmt(f)
221 }
222}
223
David Tolnay977f8282017-05-31 17:41:33 -0700224#[derive(Clone, Debug)]
Alex Crichton1a7f7622017-07-05 17:47:15 -0700225pub enum TokenNode {
226 Group(Delimiter, TokenStream),
227 Term(Term),
228 Op(char, Spacing),
Alex Crichton44bffbc2017-05-19 17:51:59 -0700229 Literal(Literal),
230}
231
Michael Layzell5372f4b2017-06-02 10:29:31 -0400232#[derive(Copy, Clone, Debug, Eq, PartialEq)]
Alex Crichton44bffbc2017-05-19 17:51:59 -0700233pub enum Delimiter {
234 Parenthesis,
235 Brace,
236 Bracket,
237 None,
238}
239
David Tolnaycb1b85f2017-06-03 16:40:35 -0700240#[derive(Copy, Clone)]
Alex Crichton1a7f7622017-07-05 17:47:15 -0700241pub struct Term(imp::Term);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700242
Alex Crichton1a7f7622017-07-05 17:47:15 -0700243impl Term {
244 pub fn intern(string: &str) -> Term {
David Tolnay10effeb2018-01-06 11:07:49 -0800245 Term(imp::Term::intern(string))
Alex Crichton44bffbc2017-05-19 17:51:59 -0700246 }
Alex Crichton44bffbc2017-05-19 17:51:59 -0700247
Alex Crichton43881252017-05-26 08:51:06 -0700248 pub fn as_str(&self) -> &str {
David Tolnay10effeb2018-01-06 11:07:49 -0800249 self.0.as_str()
Alex Crichton44bffbc2017-05-19 17:51:59 -0700250 }
251}
252
Lukas Kalbertodteb3f9302017-08-20 18:58:41 +0200253#[derive(Copy, Clone, Debug, Eq, PartialEq)]
Alex Crichton1a7f7622017-07-05 17:47:15 -0700254pub enum Spacing {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700255 Alone,
256 Joint,
257}
258
David Tolnaycb1b85f2017-06-03 16:40:35 -0700259#[derive(Clone)]
Alex Crichton44bffbc2017-05-19 17:51:59 -0700260pub struct Literal(imp::Literal);
261
Alex Crichton1a7f7622017-07-05 17:47:15 -0700262macro_rules! int_literals {
263 ($($kind:ident,)*) => ($(
264 pub fn $kind(n: $kind) -> Literal {
265 Literal(n.into())
266 }
267 )*)
268}
269
Alex Crichton852d53d2017-05-19 19:25:08 -0700270impl Literal {
Alex Crichton1a7f7622017-07-05 17:47:15 -0700271 pub fn integer(s: i64) -> Literal {
272 Literal(imp::Literal::integer(s))
273 }
274
275 int_literals! {
Alex Crichton1a16c782017-07-05 18:06:36 -0700276 u8, u16, u32, u64, usize,
277 i8, i16, i32, i64, isize,
Alex Crichton1a7f7622017-07-05 17:47:15 -0700278 }
279
280 pub fn float(f: f64) -> Literal {
281 Literal(imp::Literal::float(f))
282 }
283
284 pub fn f64(f: f64) -> Literal {
285 Literal(f.into())
286 }
287
288 pub fn f32(f: f32) -> Literal {
289 Literal(f.into())
290 }
291
292 pub fn string(string: &str) -> Literal {
293 Literal(string.into())
294 }
295
296 pub fn character(ch: char) -> Literal {
297 Literal(ch.into())
Alex Crichton76a5cc82017-05-23 07:01:44 -0700298 }
299
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700300 pub fn byte_string(s: &[u8]) -> Literal {
301 Literal(imp::Literal::byte_string(s))
Alex Crichton852d53d2017-05-19 19:25:08 -0700302 }
Alex Crichton76a5cc82017-05-23 07:01:44 -0700303
Alex Crichton1a7f7622017-07-05 17:47:15 -0700304 // =======================================================================
305 // Not present upstream in proc_macro yet
306
307 pub fn byte_char(b: u8) -> Literal {
308 Literal(imp::Literal::byte_char(b))
309 }
310
Alex Crichton76a5cc82017-05-23 07:01:44 -0700311 pub fn doccomment(s: &str) -> Literal {
312 Literal(imp::Literal::doccomment(s))
313 }
Alex Crichton9c2fb0a2017-05-26 08:49:31 -0700314
Alex Crichton31316622017-05-26 12:54:47 -0700315 pub fn raw_string(s: &str, pounds: usize) -> Literal {
316 Literal(imp::Literal::raw_string(s, pounds))
317 }
318
319 pub fn raw_byte_string(s: &str, pounds: usize) -> Literal {
320 Literal(imp::Literal::raw_byte_string(s, pounds))
321 }
Alex Crichton852d53d2017-05-19 19:25:08 -0700322}
323
Alex Crichton1a7f7622017-07-05 17:47:15 -0700324pub struct TokenTreeIter(imp::TokenTreeIter);
Alex Crichton44bffbc2017-05-19 17:51:59 -0700325
Alex Crichton1a7f7622017-07-05 17:47:15 -0700326impl Iterator for TokenTreeIter {
Alex Crichton44bffbc2017-05-19 17:51:59 -0700327 type Item = TokenTree;
328
329 fn next(&mut self) -> Option<TokenTree> {
330 self.0.next()
331 }
332}
David Tolnaycb1b85f2017-06-03 16:40:35 -0700333
334forward_fmt!(Debug for LexError);
335forward_fmt!(Debug for Literal);
336forward_fmt!(Debug for Span);
Alex Crichton1a7f7622017-07-05 17:47:15 -0700337forward_fmt!(Debug for Term);
338forward_fmt!(Debug for TokenTreeIter);
David Tolnaycb1b85f2017-06-03 16:40:35 -0700339forward_fmt!(Debug for TokenStream);
340forward_fmt!(Display for Literal);
341forward_fmt!(Display for TokenStream);