]>
Commit | Line | Data |
---|---|---|
c30ab7b3 | 1 | //! A support library for macro authors when defining new macros. |
9e0c209e | 2 | //! |
c30ab7b3 | 3 | //! This library, provided by the standard distribution, provides the types |
94b46f34 | 4 | //! consumed in the interfaces of procedurally defined macro definitions such as |
b7449926 | 5 | //! function-like macros `#[proc_macro]`, macro attributes `#[proc_macro_attribute]` and |
94b46f34 | 6 | //! custom derive attributes`#[proc_macro_derive]`. |
9e0c209e | 7 | //! |
9fa01778 XL |
8 | //! See [the book] for more. |
9 | //! | |
10 | //! [the book]: ../book/ch19-06-macros.html#procedural-macros-for-generating-code-from-attributes | |
9e0c209e | 11 | |
476ff2be | 12 | #![stable(feature = "proc_macro_lib", since = "1.15.0")] |
c30ab7b3 | 13 | #![deny(missing_docs)] |
dfeec247 | 14 | #![doc( |
dfeec247 XL |
15 | html_playground_url = "https://play.rust-lang.org/", |
16 | issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", | |
17 | test(no_crate_inject, attr(deny(warnings))), | |
18 | test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) | |
19 | )] | |
04454e1e FG |
20 | // This library is copied into rust-analyzer to allow loading rustc compiled proc macros. |
21 | // Please avoid unstable features where possible to minimize the amount of changes necessary | |
22 | // to make it compile with rust-analyzer on stable. | |
fc512014 | 23 | #![feature(rustc_allow_const_fn_unstable)] |
c30ab7b3 | 24 | #![feature(staged_api)] |
e1599b0c | 25 | #![feature(allow_internal_unstable)] |
e1599b0c | 26 | #![feature(decl_macro)] |
064997fb FG |
27 | #![feature(local_key_cell_methods)] |
28 | #![feature(maybe_uninit_write_slice)] | |
f9f354fc | 29 | #![feature(negative_impls)] |
064997fb | 30 | #![feature(new_uninit)] |
3dfed10e | 31 | #![feature(restricted_std)] |
e1599b0c | 32 | #![feature(rustc_attrs)] |
f9f354fc | 33 | #![feature(min_specialization)] |
064997fb | 34 | #![feature(strict_provenance)] |
dfeec247 | 35 | #![recursion_limit = "256"] |
94b46f34 | 36 | |
8faf50e0 XL |
37 | #[unstable(feature = "proc_macro_internals", issue = "27812")] |
38 | #[doc(hidden)] | |
a1dfa0c6 | 39 | pub mod bridge; |
8faf50e0 | 40 | |
ea8adc8c XL |
41 | mod diagnostic; |
42 | ||
b7449926 | 43 | #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] |
0bf4aa26 | 44 | pub use diagnostic::{Diagnostic, Level, MultiSpan}; |
9e0c209e | 45 | |
f9f354fc | 46 | use std::cmp::Ordering; |
17df50a5 | 47 | use std::ops::RangeBounds; |
8faf50e0 | 48 | use std::path::PathBuf; |
c30ab7b3 | 49 | use std::str::FromStr; |
353b0b11 | 50 | use std::{error, fmt}; |
c30ab7b3 | 51 | |
f9f354fc XL |
52 | /// Determines whether proc_macro has been made accessible to the currently |
53 | /// running program. | |
54 | /// | |
55 | /// The proc_macro crate is only intended for use inside the implementation of | |
56 | /// procedural macros. All the functions in this crate panic if invoked from | |
57 | /// outside of a procedural macro, such as from a build script or unit test or | |
58 | /// ordinary Rust binary. | |
59 | /// | |
60 | /// With consideration for Rust libraries that are designed to support both | |
61 | /// macro and non-macro use cases, `proc_macro::is_available()` provides a | |
62 | /// non-panicking way to detect whether the infrastructure required to use the | |
63 | /// API of proc_macro is presently available. Returns true if invoked from | |
64 | /// inside of a procedural macro, false if invoked from any other binary. | |
c295e0f8 | 65 | #[stable(feature = "proc_macro_is_available", since = "1.57.0")] |
f9f354fc | 66 | pub fn is_available() -> bool { |
064997fb | 67 | bridge::client::is_available() |
f9f354fc XL |
68 | } |
69 | ||
c30ab7b3 | 70 | /// The main type provided by this crate, representing an abstract stream of |
94b46f34 XL |
71 | /// tokens, or, more specifically, a sequence of token trees. |
72 | /// The type provide interfaces for iterating over those token trees and, conversely, | |
73 | /// collecting a number of token trees into one stream. | |
c30ab7b3 | 74 | /// |
94b46f34 XL |
75 | /// This is both the input and output of `#[proc_macro]`, `#[proc_macro_attribute]` |
76 | /// and `#[proc_macro_derive]` definitions. | |
9ffffee4 | 77 | #[rustc_diagnostic_item = "TokenStream"] |
476ff2be | 78 | #[stable(feature = "proc_macro_lib", since = "1.15.0")] |
83c7162d | 79 | #[derive(Clone)] |
923072b8 | 80 | pub struct TokenStream(Option<bridge::client::TokenStream>); |
c30ab7b3 | 81 | |
94b46f34 | 82 | #[stable(feature = "proc_macro_lib", since = "1.15.0")] |
83c7162d | 83 | impl !Send for TokenStream {} |
94b46f34 | 84 | #[stable(feature = "proc_macro_lib", since = "1.15.0")] |
83c7162d XL |
85 | impl !Sync for TokenStream {} |
86 | ||
c30ab7b3 | 87 | /// Error returned from `TokenStream::from_str`. |
476ff2be | 88 | #[stable(feature = "proc_macro_lib", since = "1.15.0")] |
136023e0 | 89 | #[non_exhaustive] |
041b39d2 | 90 | #[derive(Debug)] |
136023e0 | 91 | pub struct LexError; |
c30ab7b3 | 92 | |
ba9703b0 XL |
93 | #[stable(feature = "proc_macro_lexerror_impls", since = "1.44.0")] |
94 | impl fmt::Display for LexError { | |
95 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
96 | f.write_str("cannot parse string into token stream") | |
97 | } | |
98 | } | |
99 | ||
100 | #[stable(feature = "proc_macro_lexerror_impls", since = "1.44.0")] | |
101 | impl error::Error for LexError {} | |
102 | ||
94b46f34 | 103 | #[stable(feature = "proc_macro_lib", since = "1.15.0")] |
83c7162d | 104 | impl !Send for LexError {} |
94b46f34 | 105 | #[stable(feature = "proc_macro_lib", since = "1.15.0")] |
83c7162d XL |
106 | impl !Sync for LexError {} |
107 | ||
3c0e092e XL |
108 | /// Error returned from `TokenStream::expand_expr`. |
109 | #[unstable(feature = "proc_macro_expand", issue = "90765")] | |
110 | #[non_exhaustive] | |
111 | #[derive(Debug)] | |
112 | pub struct ExpandError; | |
113 | ||
114 | #[unstable(feature = "proc_macro_expand", issue = "90765")] | |
115 | impl fmt::Display for ExpandError { | |
116 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
117 | f.write_str("macro expansion failed") | |
118 | } | |
119 | } | |
120 | ||
121 | #[unstable(feature = "proc_macro_expand", issue = "90765")] | |
122 | impl error::Error for ExpandError {} | |
123 | ||
124 | #[unstable(feature = "proc_macro_expand", issue = "90765")] | |
125 | impl !Send for ExpandError {} | |
126 | ||
127 | #[unstable(feature = "proc_macro_expand", issue = "90765")] | |
128 | impl !Sync for ExpandError {} | |
129 | ||
83c7162d | 130 | impl TokenStream { |
94b46f34 | 131 | /// Returns an empty `TokenStream` containing no token trees. |
8faf50e0 | 132 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
94b46f34 | 133 | pub fn new() -> TokenStream { |
923072b8 | 134 | TokenStream(None) |
83c7162d XL |
135 | } |
136 | ||
137 | /// Checks if this `TokenStream` is empty. | |
8faf50e0 | 138 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 139 | pub fn is_empty(&self) -> bool { |
923072b8 | 140 | self.0.as_ref().map(|h| h.is_empty()).unwrap_or(true) |
83c7162d | 141 | } |
3c0e092e XL |
142 | |
143 | /// Parses this `TokenStream` as an expression and attempts to expand any | |
144 | /// macros within it. Returns the expanded `TokenStream`. | |
145 | /// | |
146 | /// Currently only expressions expanding to literals will succeed, although | |
147 | /// this may be relaxed in the future. | |
148 | /// | |
149 | /// NOTE: In error conditions, `expand_expr` may leave macros unexpanded, | |
150 | /// report an error, failing compilation, and/or return an `Err(..)`. The | |
151 | /// specific behavior for any error condition, and what conditions are | |
152 | /// considered errors, is unspecified and may change in the future. | |
153 | #[unstable(feature = "proc_macro_expand", issue = "90765")] | |
154 | pub fn expand_expr(&self) -> Result<TokenStream, ExpandError> { | |
923072b8 FG |
155 | let stream = self.0.as_ref().ok_or(ExpandError)?; |
156 | match bridge::client::TokenStream::expand_expr(stream) { | |
157 | Ok(stream) => Ok(TokenStream(Some(stream))), | |
3c0e092e XL |
158 | Err(_) => Err(ExpandError), |
159 | } | |
160 | } | |
83c7162d XL |
161 | } |
162 | ||
94b46f34 XL |
163 | /// Attempts to break the string into tokens and parse those tokens into a token stream. |
164 | /// May fail for a number of reasons, for example, if the string contains unbalanced delimiters | |
165 | /// or characters not existing in the language. | |
8faf50e0 | 166 | /// All tokens in the parsed stream get `Span::call_site()` spans. |
94b46f34 | 167 | /// |
9fa01778 | 168 | /// NOTE: some errors may cause panics instead of returning `LexError`. We reserve the right to |
94b46f34 | 169 | /// change these errors into `LexError`s later. |
041b39d2 XL |
170 | #[stable(feature = "proc_macro_lib", since = "1.15.0")] |
171 | impl FromStr for TokenStream { | |
172 | type Err = LexError; | |
173 | ||
174 | fn from_str(src: &str) -> Result<TokenStream, LexError> { | |
923072b8 | 175 | Ok(TokenStream(Some(bridge::client::TokenStream::from_str(src)))) |
a1dfa0c6 XL |
176 | } |
177 | } | |
178 | ||
0731742a | 179 | // N.B., the bridge only provides `to_string`, implement `fmt::Display` |
a1dfa0c6 XL |
180 | // based on it (the reverse of the usual relationship between the two). |
181 | #[stable(feature = "proc_macro_lib", since = "1.15.0")] | |
182 | impl ToString for TokenStream { | |
183 | fn to_string(&self) -> String { | |
923072b8 | 184 | self.0.as_ref().map(|t| t.to_string()).unwrap_or_default() |
041b39d2 XL |
185 | } |
186 | } | |
187 | ||
94b46f34 XL |
188 | /// Prints the token stream as a string that is supposed to be losslessly convertible back |
189 | /// into the same token stream (modulo spans), except for possibly `TokenTree::Group`s | |
190 | /// with `Delimiter::None` delimiters and negative numeric literals. | |
041b39d2 XL |
191 | #[stable(feature = "proc_macro_lib", since = "1.15.0")] |
192 | impl fmt::Display for TokenStream { | |
9fa01778 | 193 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
a1dfa0c6 | 194 | f.write_str(&self.to_string()) |
041b39d2 XL |
195 | } |
196 | } | |
197 | ||
94b46f34 | 198 | /// Prints token in a form convenient for debugging. |
83c7162d XL |
199 | #[stable(feature = "proc_macro_lib", since = "1.15.0")] |
200 | impl fmt::Debug for TokenStream { | |
9fa01778 | 201 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
83c7162d XL |
202 | f.write_str("TokenStream ")?; |
203 | f.debug_list().entries(self.clone()).finish() | |
204 | } | |
205 | } | |
041b39d2 | 206 | |
f9f354fc XL |
207 | #[stable(feature = "proc_macro_token_stream_default", since = "1.45.0")] |
208 | impl Default for TokenStream { | |
209 | fn default() -> Self { | |
210 | TokenStream::new() | |
211 | } | |
212 | } | |
213 | ||
0bf4aa26 | 214 | #[unstable(feature = "proc_macro_quote", issue = "54722")] |
8faf50e0 XL |
215 | pub use quote::{quote, quote_span}; |
216 | ||
923072b8 FG |
217 | fn tree_to_bridge_tree( |
218 | tree: TokenTree, | |
064997fb | 219 | ) -> bridge::TokenTree<bridge::client::TokenStream, bridge::client::Span, bridge::client::Symbol> { |
923072b8 FG |
220 | match tree { |
221 | TokenTree::Group(tt) => bridge::TokenTree::Group(tt.0), | |
222 | TokenTree::Punct(tt) => bridge::TokenTree::Punct(tt.0), | |
223 | TokenTree::Ident(tt) => bridge::TokenTree::Ident(tt.0), | |
224 | TokenTree::Literal(tt) => bridge::TokenTree::Literal(tt.0), | |
225 | } | |
226 | } | |
227 | ||
94b46f34 | 228 | /// Creates a token stream containing a single token tree. |
dfeec247 | 229 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
041b39d2 XL |
230 | impl From<TokenTree> for TokenStream { |
231 | fn from(tree: TokenTree) -> TokenStream { | |
923072b8 FG |
232 | TokenStream(Some(bridge::client::TokenStream::from_token_tree(tree_to_bridge_tree(tree)))) |
233 | } | |
234 | } | |
235 | ||
236 | /// Non-generic helper for implementing `FromIterator<TokenTree>` and | |
237 | /// `Extend<TokenTree>` with less monomorphization in calling crates. | |
238 | struct ConcatTreesHelper { | |
239 | trees: Vec< | |
240 | bridge::TokenTree< | |
064997fb FG |
241 | bridge::client::TokenStream, |
242 | bridge::client::Span, | |
243 | bridge::client::Symbol, | |
923072b8 FG |
244 | >, |
245 | >, | |
246 | } | |
247 | ||
248 | impl ConcatTreesHelper { | |
249 | fn new(capacity: usize) -> Self { | |
250 | ConcatTreesHelper { trees: Vec::with_capacity(capacity) } | |
251 | } | |
252 | ||
253 | fn push(&mut self, tree: TokenTree) { | |
254 | self.trees.push(tree_to_bridge_tree(tree)); | |
255 | } | |
256 | ||
257 | fn build(self) -> TokenStream { | |
258 | if self.trees.is_empty() { | |
259 | TokenStream(None) | |
260 | } else { | |
261 | TokenStream(Some(bridge::client::TokenStream::concat_trees(None, self.trees))) | |
262 | } | |
263 | } | |
264 | ||
265 | fn append_to(self, stream: &mut TokenStream) { | |
266 | if self.trees.is_empty() { | |
267 | return; | |
268 | } | |
269 | stream.0 = Some(bridge::client::TokenStream::concat_trees(stream.0.take(), self.trees)) | |
270 | } | |
271 | } | |
272 | ||
273 | /// Non-generic helper for implementing `FromIterator<TokenStream>` and | |
274 | /// `Extend<TokenStream>` with less monomorphization in calling crates. | |
275 | struct ConcatStreamsHelper { | |
276 | streams: Vec<bridge::client::TokenStream>, | |
277 | } | |
278 | ||
279 | impl ConcatStreamsHelper { | |
280 | fn new(capacity: usize) -> Self { | |
281 | ConcatStreamsHelper { streams: Vec::with_capacity(capacity) } | |
282 | } | |
283 | ||
284 | fn push(&mut self, stream: TokenStream) { | |
285 | if let Some(stream) = stream.0 { | |
286 | self.streams.push(stream); | |
287 | } | |
288 | } | |
289 | ||
290 | fn build(mut self) -> TokenStream { | |
291 | if self.streams.len() <= 1 { | |
292 | TokenStream(self.streams.pop()) | |
293 | } else { | |
294 | TokenStream(Some(bridge::client::TokenStream::concat_streams(None, self.streams))) | |
295 | } | |
296 | } | |
297 | ||
298 | fn append_to(mut self, stream: &mut TokenStream) { | |
299 | if self.streams.is_empty() { | |
300 | return; | |
301 | } | |
302 | let base = stream.0.take(); | |
303 | if base.is_none() && self.streams.len() == 1 { | |
304 | stream.0 = self.streams.pop(); | |
305 | } else { | |
306 | stream.0 = Some(bridge::client::TokenStream::concat_streams(base, self.streams)); | |
307 | } | |
041b39d2 XL |
308 | } |
309 | } | |
310 | ||
94b46f34 | 311 | /// Collects a number of token trees into a single stream. |
dfeec247 | 312 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
353b0b11 | 313 | impl FromIterator<TokenTree> for TokenStream { |
83c7162d | 314 | fn from_iter<I: IntoIterator<Item = TokenTree>>(trees: I) -> Self { |
923072b8 FG |
315 | let iter = trees.into_iter(); |
316 | let mut builder = ConcatTreesHelper::new(iter.size_hint().0); | |
317 | iter.for_each(|tree| builder.push(tree)); | |
318 | builder.build() | |
041b39d2 XL |
319 | } |
320 | } | |
321 | ||
94b46f34 XL |
322 | /// A "flattening" operation on token streams, collects token trees |
323 | /// from multiple token streams into a single stream. | |
324 | #[stable(feature = "proc_macro_lib", since = "1.15.0")] | |
353b0b11 | 325 | impl FromIterator<TokenStream> for TokenStream { |
83c7162d | 326 | fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self { |
923072b8 FG |
327 | let iter = streams.into_iter(); |
328 | let mut builder = ConcatStreamsHelper::new(iter.size_hint().0); | |
329 | iter.for_each(|stream| builder.push(stream)); | |
330 | builder.build() | |
041b39d2 XL |
331 | } |
332 | } | |
333 | ||
b7449926 XL |
334 | #[stable(feature = "token_stream_extend", since = "1.30.0")] |
335 | impl Extend<TokenTree> for TokenStream { | |
336 | fn extend<I: IntoIterator<Item = TokenTree>>(&mut self, trees: I) { | |
923072b8 FG |
337 | let iter = trees.into_iter(); |
338 | let mut builder = ConcatTreesHelper::new(iter.size_hint().0); | |
339 | iter.for_each(|tree| builder.push(tree)); | |
340 | builder.append_to(self); | |
b7449926 XL |
341 | } |
342 | } | |
343 | ||
344 | #[stable(feature = "token_stream_extend", since = "1.30.0")] | |
345 | impl Extend<TokenStream> for TokenStream { | |
346 | fn extend<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I) { | |
923072b8 FG |
347 | let iter = streams.into_iter(); |
348 | let mut builder = ConcatStreamsHelper::new(iter.size_hint().0); | |
349 | iter.for_each(|stream| builder.push(stream)); | |
350 | builder.append_to(self); | |
b7449926 XL |
351 | } |
352 | } | |
353 | ||
94b46f34 | 354 | /// Public implementation details for the `TokenStream` type, such as iterators. |
8faf50e0 | 355 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 356 | pub mod token_stream { |
dfeec247 | 357 | use crate::{bridge, Group, Ident, Literal, Punct, TokenStream, TokenTree}; |
041b39d2 | 358 | |
94b46f34 | 359 | /// An iterator over `TokenStream`'s `TokenTree`s. |
0731742a | 360 | /// The iteration is "shallow", e.g., the iterator doesn't recurse into delimited groups, |
94b46f34 | 361 | /// and returns whole groups as token trees. |
83c7162d | 362 | #[derive(Clone)] |
8faf50e0 | 363 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
923072b8 FG |
364 | pub struct IntoIter( |
365 | std::vec::IntoIter< | |
366 | bridge::TokenTree< | |
064997fb FG |
367 | bridge::client::TokenStream, |
368 | bridge::client::Span, | |
369 | bridge::client::Symbol, | |
923072b8 FG |
370 | >, |
371 | >, | |
372 | ); | |
041b39d2 | 373 | |
8faf50e0 | 374 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d XL |
375 | impl Iterator for IntoIter { |
376 | type Item = TokenTree; | |
377 | ||
378 | fn next(&mut self) -> Option<TokenTree> { | |
a1dfa0c6 XL |
379 | self.0.next().map(|tree| match tree { |
380 | bridge::TokenTree::Group(tt) => TokenTree::Group(Group(tt)), | |
381 | bridge::TokenTree::Punct(tt) => TokenTree::Punct(Punct(tt)), | |
382 | bridge::TokenTree::Ident(tt) => TokenTree::Ident(Ident(tt)), | |
383 | bridge::TokenTree::Literal(tt) => TokenTree::Literal(Literal(tt)), | |
384 | }) | |
83c7162d | 385 | } |
064997fb FG |
386 | |
387 | fn size_hint(&self) -> (usize, Option<usize>) { | |
388 | self.0.size_hint() | |
389 | } | |
390 | ||
391 | fn count(self) -> usize { | |
392 | self.0.count() | |
393 | } | |
041b39d2 XL |
394 | } |
395 | ||
8faf50e0 | 396 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d XL |
397 | impl IntoIterator for TokenStream { |
398 | type Item = TokenTree; | |
399 | type IntoIter = IntoIter; | |
400 | ||
401 | fn into_iter(self) -> IntoIter { | |
923072b8 | 402 | IntoIter(self.0.map(|v| v.into_trees()).unwrap_or_default().into_iter()) |
83c7162d | 403 | } |
041b39d2 XL |
404 | } |
405 | } | |
406 | ||
83c7162d | 407 | /// `quote!(..)` accepts arbitrary tokens and expands into a `TokenStream` describing the input. |
94222f64 | 408 | /// For example, `quote!(a + b)` will produce an expression, that, when evaluated, constructs |
94b46f34 | 409 | /// the `TokenStream` `[Ident("a"), Punct('+', Alone), Ident("b")]`. |
83c7162d XL |
410 | /// |
411 | /// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term. | |
412 | /// To quote `$` itself, use `$$`. | |
0bf4aa26 | 413 | #[unstable(feature = "proc_macro_quote", issue = "54722")] |
17df50a5 | 414 | #[allow_internal_unstable(proc_macro_def_site, proc_macro_internals)] |
e74abb32 | 415 | #[rustc_builtin_macro] |
dfeec247 XL |
416 | pub macro quote($($t:tt)*) { |
417 | /* compiler built-in */ | |
418 | } | |
041b39d2 | 419 | |
83c7162d XL |
420 | #[unstable(feature = "proc_macro_internals", issue = "27812")] |
421 | #[doc(hidden)] | |
422 | mod quote; | |
041b39d2 | 423 | |
83c7162d | 424 | /// A region of source code, along with macro expansion information. |
8faf50e0 | 425 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 426 | #[derive(Copy, Clone)] |
a1dfa0c6 | 427 | pub struct Span(bridge::client::Span); |
83c7162d | 428 | |
8faf50e0 | 429 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 430 | impl !Send for Span {} |
8faf50e0 | 431 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d XL |
432 | impl !Sync for Span {} |
433 | ||
ea8adc8c | 434 | macro_rules! diagnostic_method { |
f9f354fc | 435 | ($name:ident, $level:expr) => { |
9fa01778 | 436 | /// Creates a new `Diagnostic` with the given `message` at the span |
ea8adc8c | 437 | /// `self`. |
b7449926 | 438 | #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] |
ea8adc8c XL |
439 | pub fn $name<T: Into<String>>(self, message: T) -> Diagnostic { |
440 | Diagnostic::spanned(self, $level, message) | |
441 | } | |
f9f354fc | 442 | }; |
ea8adc8c XL |
443 | } |
444 | ||
041b39d2 | 445 | impl Span { |
83c7162d | 446 | /// A span that resolves at the macro definition site. |
0bf4aa26 | 447 | #[unstable(feature = "proc_macro_def_site", issue = "54724")] |
83c7162d | 448 | pub fn def_site() -> Span { |
a1dfa0c6 | 449 | Span(bridge::client::Span::def_site()) |
83c7162d XL |
450 | } |
451 | ||
041b39d2 | 452 | /// The span of the invocation of the current procedural macro. |
94b46f34 XL |
453 | /// Identifiers created with this span will be resolved as if they were written |
454 | /// directly at the macro call location (call-site hygiene) and other code | |
455 | /// at the macro call site will be able to refer to them as well. | |
8faf50e0 | 456 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
041b39d2 | 457 | pub fn call_site() -> Span { |
a1dfa0c6 | 458 | Span(bridge::client::Span::call_site()) |
041b39d2 | 459 | } |
ea8adc8c | 460 | |
e74abb32 XL |
461 | /// A span that represents `macro_rules` hygiene, and sometimes resolves at the macro |
462 | /// definition site (local variables, labels, `$crate`) and sometimes at the macro | |
463 | /// call site (everything else). | |
464 | /// The span location is taken from the call-site. | |
f9f354fc | 465 | #[stable(feature = "proc_macro_mixed_site", since = "1.45.0")] |
e74abb32 XL |
466 | pub fn mixed_site() -> Span { |
467 | Span(bridge::client::Span::mixed_site()) | |
468 | } | |
469 | ||
ea8adc8c | 470 | /// The original source file into which this span points. |
0bf4aa26 | 471 | #[unstable(feature = "proc_macro_span", issue = "54725")] |
ea8adc8c | 472 | pub fn source_file(&self) -> SourceFile { |
a1dfa0c6 | 473 | SourceFile(self.0.source_file()) |
ea8adc8c XL |
474 | } |
475 | ||
2c00a5a8 XL |
476 | /// The `Span` for the tokens in the previous macro expansion from which |
477 | /// `self` was generated from, if any. | |
0bf4aa26 | 478 | #[unstable(feature = "proc_macro_span", issue = "54725")] |
2c00a5a8 | 479 | pub fn parent(&self) -> Option<Span> { |
83c7162d | 480 | self.0.parent().map(Span) |
2c00a5a8 XL |
481 | } |
482 | ||
483 | /// The span for the origin source code that `self` was generated from. If | |
484 | /// this `Span` wasn't generated from other macro expansions then the return | |
485 | /// value is the same as `*self`. | |
0bf4aa26 | 486 | #[unstable(feature = "proc_macro_span", issue = "54725")] |
2c00a5a8 | 487 | pub fn source(&self) -> Span { |
a1dfa0c6 | 488 | Span(self.0.source()) |
2c00a5a8 XL |
489 | } |
490 | ||
9fa01778 | 491 | /// Gets the starting line/column in the source file for this span. |
0bf4aa26 | 492 | #[unstable(feature = "proc_macro_span", issue = "54725")] |
ea8adc8c | 493 | pub fn start(&self) -> LineColumn { |
94222f64 | 494 | self.0.start().add_1_to_column() |
ea8adc8c XL |
495 | } |
496 | ||
9fa01778 | 497 | /// Gets the ending line/column in the source file for this span. |
0bf4aa26 | 498 | #[unstable(feature = "proc_macro_span", issue = "54725")] |
ea8adc8c | 499 | pub fn end(&self) -> LineColumn { |
94222f64 | 500 | self.0.end().add_1_to_column() |
ea8adc8c XL |
501 | } |
502 | ||
c295e0f8 XL |
503 | /// Creates an empty span pointing to directly before this span. |
504 | #[unstable(feature = "proc_macro_span_shrink", issue = "87552")] | |
505 | pub fn before(&self) -> Span { | |
506 | Span(self.0.before()) | |
507 | } | |
508 | ||
509 | /// Creates an empty span pointing to directly after this span. | |
510 | #[unstable(feature = "proc_macro_span_shrink", issue = "87552")] | |
511 | pub fn after(&self) -> Span { | |
512 | Span(self.0.after()) | |
513 | } | |
514 | ||
9fa01778 | 515 | /// Creates a new span encompassing `self` and `other`. |
ea8adc8c XL |
516 | /// |
517 | /// Returns `None` if `self` and `other` are from different files. | |
0bf4aa26 | 518 | #[unstable(feature = "proc_macro_span", issue = "54725")] |
ea8adc8c | 519 | pub fn join(&self, other: Span) -> Option<Span> { |
a1dfa0c6 | 520 | self.0.join(other.0).map(Span) |
ea8adc8c XL |
521 | } |
522 | ||
2c00a5a8 XL |
523 | /// Creates a new span with the same line/column information as `self` but |
524 | /// that resolves symbols as though it were at `other`. | |
f9f354fc | 525 | #[stable(feature = "proc_macro_span_resolved_at", since = "1.45.0")] |
2c00a5a8 | 526 | pub fn resolved_at(&self, other: Span) -> Span { |
a1dfa0c6 | 527 | Span(self.0.resolved_at(other.0)) |
2c00a5a8 XL |
528 | } |
529 | ||
530 | /// Creates a new span with the same name resolution behavior as `self` but | |
531 | /// with the line/column information of `other`. | |
f9f354fc | 532 | #[stable(feature = "proc_macro_span_located_at", since = "1.45.0")] |
2c00a5a8 XL |
533 | pub fn located_at(&self, other: Span) -> Span { |
534 | other.resolved_at(*self) | |
535 | } | |
536 | ||
2b03887a | 537 | /// Compares two spans to see if they're equal. |
0bf4aa26 | 538 | #[unstable(feature = "proc_macro_span", issue = "54725")] |
83c7162d XL |
539 | pub fn eq(&self, other: &Span) -> bool { |
540 | self.0 == other.0 | |
541 | } | |
542 | ||
532ac7d7 XL |
543 | /// Returns the source text behind a span. This preserves the original source |
544 | /// code, including spaces and comments. It only returns a result if the span | |
545 | /// corresponds to real source code. | |
546 | /// | |
547 | /// Note: The observable result of a macro should only rely on the tokens and | |
548 | /// not on this source text. The result of this function is a best effort to | |
549 | /// be used for diagnostics only. | |
2b03887a | 550 | #[stable(feature = "proc_macro_source_text", since = "1.66.0")] |
532ac7d7 XL |
551 | pub fn source_text(&self) -> Option<String> { |
552 | self.0.source_text() | |
553 | } | |
554 | ||
17df50a5 XL |
555 | // Used by the implementation of `Span::quote` |
556 | #[doc(hidden)] | |
557 | #[unstable(feature = "proc_macro_internals", issue = "27812")] | |
558 | pub fn save_span(&self) -> usize { | |
559 | self.0.save_span() | |
560 | } | |
561 | ||
562 | // Used by the implementation of `Span::quote` | |
563 | #[doc(hidden)] | |
564 | #[unstable(feature = "proc_macro_internals", issue = "27812")] | |
565 | pub fn recover_proc_macro_span(id: usize) -> Span { | |
566 | Span(bridge::client::Span::recover_proc_macro_span(id)) | |
567 | } | |
568 | ||
ea8adc8c XL |
569 | diagnostic_method!(error, Level::Error); |
570 | diagnostic_method!(warning, Level::Warning); | |
571 | diagnostic_method!(note, Level::Note); | |
572 | diagnostic_method!(help, Level::Help); | |
573 | } | |
574 | ||
94b46f34 | 575 | /// Prints a span in a form convenient for debugging. |
8faf50e0 | 576 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 577 | impl fmt::Debug for Span { |
9fa01778 | 578 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
a1dfa0c6 | 579 | self.0.fmt(f) |
83c7162d XL |
580 | } |
581 | } | |
582 | ||
ea8adc8c | 583 | /// A line-column pair representing the start or end of a `Span`. |
0bf4aa26 | 584 | #[unstable(feature = "proc_macro_span", issue = "54725")] |
9ffffee4 | 585 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] |
ea8adc8c XL |
586 | pub struct LineColumn { |
587 | /// The 1-indexed line in the source file on which the span starts or ends (inclusive). | |
0bf4aa26 | 588 | #[unstable(feature = "proc_macro_span", issue = "54725")] |
ff7c6d11 | 589 | pub line: usize, |
94222f64 XL |
590 | /// The 1-indexed column (number of bytes in UTF-8 encoding) in the source |
591 | /// file on which the span starts or ends (inclusive). | |
0bf4aa26 | 592 | #[unstable(feature = "proc_macro_span", issue = "54725")] |
dfeec247 | 593 | pub column: usize, |
ea8adc8c XL |
594 | } |
595 | ||
94222f64 XL |
596 | impl LineColumn { |
597 | fn add_1_to_column(self) -> Self { | |
598 | LineColumn { line: self.line, column: self.column + 1 } | |
599 | } | |
600 | } | |
601 | ||
0bf4aa26 | 602 | #[unstable(feature = "proc_macro_span", issue = "54725")] |
83c7162d | 603 | impl !Send for LineColumn {} |
0bf4aa26 | 604 | #[unstable(feature = "proc_macro_span", issue = "54725")] |
83c7162d XL |
605 | impl !Sync for LineColumn {} |
606 | ||
f9f354fc XL |
607 | #[unstable(feature = "proc_macro_span", issue = "54725")] |
608 | impl Ord for LineColumn { | |
609 | fn cmp(&self, other: &Self) -> Ordering { | |
610 | self.line.cmp(&other.line).then(self.column.cmp(&other.column)) | |
611 | } | |
612 | } | |
613 | ||
614 | #[unstable(feature = "proc_macro_span", issue = "54725")] | |
615 | impl PartialOrd for LineColumn { | |
616 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { | |
617 | Some(self.cmp(other)) | |
618 | } | |
619 | } | |
620 | ||
ea8adc8c | 621 | /// The source file of a given `Span`. |
0bf4aa26 | 622 | #[unstable(feature = "proc_macro_span", issue = "54725")] |
ea8adc8c | 623 | #[derive(Clone)] |
a1dfa0c6 | 624 | pub struct SourceFile(bridge::client::SourceFile); |
0531ce1d | 625 | |
ea8adc8c | 626 | impl SourceFile { |
9fa01778 | 627 | /// Gets the path to this source file. |
ea8adc8c XL |
628 | /// |
629 | /// ### Note | |
630 | /// If the code span associated with this `SourceFile` was generated by an external macro, this | |
94222f64 | 631 | /// macro, this might not be an actual path on the filesystem. Use [`is_real`] to check. |
ea8adc8c | 632 | /// |
0531ce1d | 633 | /// Also note that even if `is_real` returns `true`, if `--remap-path-prefix` was passed on |
94222f64 | 634 | /// the command line, the path as given might not actually be valid. |
ea8adc8c | 635 | /// |
3dfed10e | 636 | /// [`is_real`]: Self::is_real |
0bf4aa26 | 637 | #[unstable(feature = "proc_macro_span", issue = "54725")] |
8faf50e0 | 638 | pub fn path(&self) -> PathBuf { |
a1dfa0c6 | 639 | PathBuf::from(self.0.path()) |
ea8adc8c XL |
640 | } |
641 | ||
642 | /// Returns `true` if this source file is a real source file, and not generated by an external | |
643 | /// macro's expansion. | |
0bf4aa26 | 644 | #[unstable(feature = "proc_macro_span", issue = "54725")] |
ea8adc8c XL |
645 | pub fn is_real(&self) -> bool { |
646 | // This is a hack until intercrate spans are implemented and we can have real source files | |
647 | // for spans generated in external macros. | |
648 | // https://github.com/rust-lang/rust/pull/43604#issuecomment-333334368 | |
a1dfa0c6 | 649 | self.0.is_real() |
ea8adc8c XL |
650 | } |
651 | } | |
652 | ||
0bf4aa26 | 653 | #[unstable(feature = "proc_macro_span", issue = "54725")] |
ea8adc8c | 654 | impl fmt::Debug for SourceFile { |
9fa01778 | 655 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
ea8adc8c | 656 | f.debug_struct("SourceFile") |
8faf50e0 | 657 | .field("path", &self.path()) |
ea8adc8c XL |
658 | .field("is_real", &self.is_real()) |
659 | .finish() | |
660 | } | |
661 | } | |
662 | ||
0bf4aa26 | 663 | #[unstable(feature = "proc_macro_span", issue = "54725")] |
ea8adc8c XL |
664 | impl PartialEq for SourceFile { |
665 | fn eq(&self, other: &Self) -> bool { | |
a1dfa0c6 | 666 | self.0.eq(&other.0) |
ea8adc8c XL |
667 | } |
668 | } | |
669 | ||
0bf4aa26 | 670 | #[unstable(feature = "proc_macro_span", issue = "54725")] |
ea8adc8c XL |
671 | impl Eq for SourceFile {} |
672 | ||
0731742a | 673 | /// A single token or a delimited sequence of token trees (e.g., `[1, (), ..]`). |
8faf50e0 | 674 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d XL |
675 | #[derive(Clone)] |
676 | pub enum TokenTree { | |
94b46f34 | 677 | /// A token stream surrounded by bracket delimiters. |
8faf50e0 | 678 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
dfeec247 | 679 | Group(#[stable(feature = "proc_macro_lib2", since = "1.29.0")] Group), |
94b46f34 | 680 | /// An identifier. |
8faf50e0 | 681 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
dfeec247 | 682 | Ident(#[stable(feature = "proc_macro_lib2", since = "1.29.0")] Ident), |
94b46f34 | 683 | /// A single punctuation character (`+`, `,`, `$`, etc.). |
8faf50e0 | 684 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
dfeec247 | 685 | Punct(#[stable(feature = "proc_macro_lib2", since = "1.29.0")] Punct), |
83c7162d | 686 | /// A literal character (`'a'`), string (`"hello"`), number (`2.3`), etc. |
8faf50e0 | 687 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
dfeec247 | 688 | Literal(#[stable(feature = "proc_macro_lib2", since = "1.29.0")] Literal), |
041b39d2 XL |
689 | } |
690 | ||
8faf50e0 | 691 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 692 | impl !Send for TokenTree {} |
8faf50e0 | 693 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d XL |
694 | impl !Sync for TokenTree {} |
695 | ||
696 | impl TokenTree { | |
94b46f34 XL |
697 | /// Returns the span of this tree, delegating to the `span` method of |
698 | /// the contained token or a delimited stream. | |
8faf50e0 | 699 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d XL |
700 | pub fn span(&self) -> Span { |
701 | match *self { | |
702 | TokenTree::Group(ref t) => t.span(), | |
94b46f34 XL |
703 | TokenTree::Ident(ref t) => t.span(), |
704 | TokenTree::Punct(ref t) => t.span(), | |
83c7162d XL |
705 | TokenTree::Literal(ref t) => t.span(), |
706 | } | |
707 | } | |
708 | ||
709 | /// Configures the span for *only this token*. | |
710 | /// | |
711 | /// Note that if this token is a `Group` then this method will not configure | |
712 | /// the span of each of the internal tokens, this will simply delegate to | |
713 | /// the `set_span` method of each variant. | |
8faf50e0 | 714 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d XL |
715 | pub fn set_span(&mut self, span: Span) { |
716 | match *self { | |
717 | TokenTree::Group(ref mut t) => t.set_span(span), | |
94b46f34 XL |
718 | TokenTree::Ident(ref mut t) => t.set_span(span), |
719 | TokenTree::Punct(ref mut t) => t.set_span(span), | |
83c7162d XL |
720 | TokenTree::Literal(ref mut t) => t.set_span(span), |
721 | } | |
722 | } | |
723 | } | |
724 | ||
a1dfa0c6 | 725 | /// Prints token tree in a form convenient for debugging. |
8faf50e0 | 726 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 727 | impl fmt::Debug for TokenTree { |
9fa01778 | 728 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
83c7162d XL |
729 | // Each of these has the name in the struct type in the derived debug, |
730 | // so don't bother with an extra layer of indirection | |
731 | match *self { | |
732 | TokenTree::Group(ref tt) => tt.fmt(f), | |
94b46f34 XL |
733 | TokenTree::Ident(ref tt) => tt.fmt(f), |
734 | TokenTree::Punct(ref tt) => tt.fmt(f), | |
83c7162d XL |
735 | TokenTree::Literal(ref tt) => tt.fmt(f), |
736 | } | |
737 | } | |
738 | } | |
739 | ||
8faf50e0 | 740 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d XL |
741 | impl From<Group> for TokenTree { |
742 | fn from(g: Group) -> TokenTree { | |
743 | TokenTree::Group(g) | |
744 | } | |
745 | } | |
746 | ||
8faf50e0 | 747 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
94b46f34 XL |
748 | impl From<Ident> for TokenTree { |
749 | fn from(g: Ident) -> TokenTree { | |
750 | TokenTree::Ident(g) | |
83c7162d XL |
751 | } |
752 | } | |
753 | ||
8faf50e0 | 754 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
94b46f34 XL |
755 | impl From<Punct> for TokenTree { |
756 | fn from(g: Punct) -> TokenTree { | |
757 | TokenTree::Punct(g) | |
83c7162d XL |
758 | } |
759 | } | |
760 | ||
8faf50e0 | 761 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d XL |
762 | impl From<Literal> for TokenTree { |
763 | fn from(g: Literal) -> TokenTree { | |
764 | TokenTree::Literal(g) | |
041b39d2 XL |
765 | } |
766 | } | |
767 | ||
0731742a | 768 | // N.B., the bridge only provides `to_string`, implement `fmt::Display` |
a1dfa0c6 XL |
769 | // based on it (the reverse of the usual relationship between the two). |
770 | #[stable(feature = "proc_macro_lib", since = "1.15.0")] | |
771 | impl ToString for TokenTree { | |
772 | fn to_string(&self) -> String { | |
773 | match *self { | |
774 | TokenTree::Group(ref t) => t.to_string(), | |
775 | TokenTree::Ident(ref t) => t.to_string(), | |
776 | TokenTree::Punct(ref t) => t.to_string(), | |
777 | TokenTree::Literal(ref t) => t.to_string(), | |
778 | } | |
779 | } | |
780 | } | |
781 | ||
94b46f34 XL |
782 | /// Prints the token tree as a string that is supposed to be losslessly convertible back |
783 | /// into the same token tree (modulo spans), except for possibly `TokenTree::Group`s | |
784 | /// with `Delimiter::None` delimiters and negative numeric literals. | |
8faf50e0 | 785 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
041b39d2 | 786 | impl fmt::Display for TokenTree { |
9fa01778 | 787 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
a1dfa0c6 | 788 | f.write_str(&self.to_string()) |
041b39d2 XL |
789 | } |
790 | } | |
791 | ||
94b46f34 | 792 | /// A delimited token stream. |
83c7162d | 793 | /// |
94b46f34 | 794 | /// A `Group` internally contains a `TokenStream` which is surrounded by `Delimiter`s. |
8faf50e0 XL |
795 | #[derive(Clone)] |
796 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] | |
064997fb | 797 | pub struct Group(bridge::Group<bridge::client::TokenStream, bridge::client::Span>); |
041b39d2 | 798 | |
8faf50e0 | 799 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 800 | impl !Send for Group {} |
8faf50e0 | 801 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d XL |
802 | impl !Sync for Group {} |
803 | ||
041b39d2 | 804 | /// Describes how a sequence of token trees is delimited. |
3b2f2976 | 805 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
8faf50e0 | 806 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
041b39d2 XL |
807 | pub enum Delimiter { |
808 | /// `( ... )` | |
8faf50e0 | 809 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
041b39d2 | 810 | Parenthesis, |
041b39d2 | 811 | /// `{ ... }` |
8faf50e0 | 812 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
3b2f2976 XL |
813 | Brace, |
814 | /// `[ ... ]` | |
8faf50e0 | 815 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
041b39d2 | 816 | Bracket, |
94b46f34 | 817 | /// `Ø ... Ø` |
04454e1e | 818 | /// An invisible delimiter, that may, for example, appear around tokens coming from a |
94b46f34 XL |
819 | /// "macro variable" `$var`. It is important to preserve operator priorities in cases like |
820 | /// `$var * 3` where `$var` is `1 + 2`. | |
04454e1e | 821 | /// Invisible delimiters might not survive roundtrip of a token stream through a string. |
8faf50e0 | 822 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
041b39d2 XL |
823 | None, |
824 | } | |
825 | ||
83c7162d | 826 | impl Group { |
94b46f34 | 827 | /// Creates a new `Group` with the given delimiter and token stream. |
83c7162d XL |
828 | /// |
829 | /// This constructor will set the span for this group to | |
830 | /// `Span::call_site()`. To change the span you can use the `set_span` | |
831 | /// method below. | |
8faf50e0 | 832 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 833 | pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group { |
064997fb FG |
834 | Group(bridge::Group { |
835 | delimiter, | |
836 | stream: stream.0, | |
837 | span: bridge::DelimSpan::from_single(Span::call_site().0), | |
838 | }) | |
83c7162d | 839 | } |
041b39d2 | 840 | |
83c7162d | 841 | /// Returns the delimiter of this `Group` |
8faf50e0 | 842 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 843 | pub fn delimiter(&self) -> Delimiter { |
064997fb | 844 | self.0.delimiter |
041b39d2 XL |
845 | } |
846 | ||
83c7162d XL |
847 | /// Returns the `TokenStream` of tokens that are delimited in this `Group`. |
848 | /// | |
849 | /// Note that the returned token stream does not include the delimiter | |
850 | /// returned above. | |
8faf50e0 | 851 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 852 | pub fn stream(&self) -> TokenStream { |
064997fb | 853 | TokenStream(self.0.stream.clone()) |
83c7162d XL |
854 | } |
855 | ||
856 | /// Returns the span for the delimiters of this token stream, spanning the | |
857 | /// entire `Group`. | |
b7449926 XL |
858 | /// |
859 | /// ```text | |
860 | /// pub fn span(&self) -> Span { | |
861 | /// ^^^^^^^ | |
862 | /// ``` | |
8faf50e0 | 863 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 864 | pub fn span(&self) -> Span { |
064997fb | 865 | Span(self.0.span.entire) |
b7449926 XL |
866 | } |
867 | ||
868 | /// Returns the span pointing to the opening delimiter of this group. | |
869 | /// | |
870 | /// ```text | |
871 | /// pub fn span_open(&self) -> Span { | |
872 | /// ^ | |
873 | /// ``` | |
136023e0 | 874 | #[stable(feature = "proc_macro_group_span", since = "1.55.0")] |
b7449926 | 875 | pub fn span_open(&self) -> Span { |
064997fb | 876 | Span(self.0.span.open) |
b7449926 XL |
877 | } |
878 | ||
879 | /// Returns the span pointing to the closing delimiter of this group. | |
880 | /// | |
881 | /// ```text | |
882 | /// pub fn span_close(&self) -> Span { | |
883 | /// ^ | |
884 | /// ``` | |
136023e0 | 885 | #[stable(feature = "proc_macro_group_span", since = "1.55.0")] |
b7449926 | 886 | pub fn span_close(&self) -> Span { |
064997fb | 887 | Span(self.0.span.close) |
83c7162d XL |
888 | } |
889 | ||
890 | /// Configures the span for this `Group`'s delimiters, but not its internal | |
891 | /// tokens. | |
892 | /// | |
893 | /// This method will **not** set the span of all the internal tokens spanned | |
894 | /// by this group, but rather it will only set the span of the delimiter | |
895 | /// tokens at the level of the `Group`. | |
8faf50e0 | 896 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 897 | pub fn set_span(&mut self, span: Span) { |
064997fb | 898 | self.0.span = bridge::DelimSpan::from_single(span.0); |
a1dfa0c6 XL |
899 | } |
900 | } | |
901 | ||
0731742a | 902 | // N.B., the bridge only provides `to_string`, implement `fmt::Display` |
a1dfa0c6 XL |
903 | // based on it (the reverse of the usual relationship between the two). |
904 | #[stable(feature = "proc_macro_lib", since = "1.15.0")] | |
905 | impl ToString for Group { | |
906 | fn to_string(&self) -> String { | |
907 | TokenStream::from(TokenTree::from(self.clone())).to_string() | |
83c7162d XL |
908 | } |
909 | } | |
910 | ||
94b46f34 XL |
911 | /// Prints the group as a string that should be losslessly convertible back |
912 | /// into the same group (modulo spans), except for possibly `TokenTree::Group`s | |
913 | /// with `Delimiter::None` delimiters. | |
8faf50e0 | 914 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 915 | impl fmt::Display for Group { |
9fa01778 | 916 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
a1dfa0c6 | 917 | f.write_str(&self.to_string()) |
041b39d2 XL |
918 | } |
919 | } | |
920 | ||
8faf50e0 XL |
921 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
922 | impl fmt::Debug for Group { | |
9fa01778 | 923 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
8faf50e0 XL |
924 | f.debug_struct("Group") |
925 | .field("delimiter", &self.delimiter()) | |
926 | .field("stream", &self.stream()) | |
927 | .field("span", &self.span()) | |
928 | .finish() | |
929 | } | |
930 | } | |
931 | ||
136023e0 | 932 | /// A `Punct` is a single punctuation character such as `+`, `-` or `#`. |
83c7162d | 933 | /// |
a1dfa0c6 | 934 | /// Multi-character operators like `+=` are represented as two instances of `Punct` with different |
83c7162d | 935 | /// forms of `Spacing` returned. |
8faf50e0 XL |
936 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
937 | #[derive(Clone)] | |
064997fb | 938 | pub struct Punct(bridge::Punct<bridge::client::Span>); |
83c7162d | 939 | |
8faf50e0 | 940 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
94b46f34 | 941 | impl !Send for Punct {} |
8faf50e0 | 942 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
94b46f34 | 943 | impl !Sync for Punct {} |
83c7162d | 944 | |
136023e0 XL |
945 | /// Describes whether a `Punct` is followed immediately by another `Punct` ([`Spacing::Joint`]) or |
946 | /// by a different token or whitespace ([`Spacing::Alone`]). | |
3b2f2976 | 947 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
8faf50e0 | 948 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
041b39d2 | 949 | pub enum Spacing { |
136023e0 XL |
950 | /// A `Punct` is not immediately followed by another `Punct`. |
951 | /// E.g. `+` is `Alone` in `+ =`, `+ident` and `+()`. | |
8faf50e0 | 952 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
041b39d2 | 953 | Alone, |
136023e0 XL |
954 | /// A `Punct` is immediately followed by another `Punct`. |
955 | /// E.g. `+` is `Joint` in `+=` and `++`. | |
956 | /// | |
957 | /// Additionally, single quote `'` can join with identifiers to form lifetimes: `'ident`. | |
8faf50e0 | 958 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
041b39d2 XL |
959 | Joint, |
960 | } | |
961 | ||
94b46f34 XL |
962 | impl Punct { |
963 | /// Creates a new `Punct` from the given character and spacing. | |
964 | /// The `ch` argument must be a valid punctuation character permitted by the language, | |
965 | /// otherwise the function will panic. | |
83c7162d | 966 | /// |
94b46f34 | 967 | /// The returned `Punct` will have the default span of `Span::call_site()` |
83c7162d | 968 | /// which can be further configured with the `set_span` method below. |
8faf50e0 | 969 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
94b46f34 | 970 | pub fn new(ch: char, spacing: Spacing) -> Punct { |
064997fb FG |
971 | const LEGAL_CHARS: &[char] = &[ |
972 | '=', '<', '>', '!', '~', '+', '-', '*', '/', '%', '^', '&', '|', '@', '.', ',', ';', | |
973 | ':', '#', '$', '?', '\'', | |
974 | ]; | |
975 | if !LEGAL_CHARS.contains(&ch) { | |
976 | panic!("unsupported character `{:?}`", ch); | |
977 | } | |
978 | Punct(bridge::Punct { | |
979 | ch: ch as u8, | |
980 | joint: spacing == Spacing::Joint, | |
981 | span: Span::call_site().0, | |
982 | }) | |
83c7162d XL |
983 | } |
984 | ||
94b46f34 | 985 | /// Returns the value of this punctuation character as `char`. |
8faf50e0 | 986 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
94b46f34 | 987 | pub fn as_char(&self) -> char { |
064997fb | 988 | self.0.ch as char |
83c7162d XL |
989 | } |
990 | ||
94b46f34 XL |
991 | /// Returns the spacing of this punctuation character, indicating whether it's immediately |
992 | /// followed by another `Punct` in the token stream, so they can potentially be combined into | |
a1dfa0c6 | 993 | /// a multi-character operator (`Joint`), or it's followed by some other token or whitespace |
94b46f34 | 994 | /// (`Alone`) so the operator has certainly ended. |
8faf50e0 | 995 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 996 | pub fn spacing(&self) -> Spacing { |
064997fb | 997 | if self.0.joint { Spacing::Joint } else { Spacing::Alone } |
83c7162d XL |
998 | } |
999 | ||
94b46f34 | 1000 | /// Returns the span for this punctuation character. |
8faf50e0 | 1001 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 1002 | pub fn span(&self) -> Span { |
064997fb | 1003 | Span(self.0.span) |
83c7162d XL |
1004 | } |
1005 | ||
94b46f34 | 1006 | /// Configure the span for this punctuation character. |
8faf50e0 | 1007 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 1008 | pub fn set_span(&mut self, span: Span) { |
064997fb | 1009 | self.0.span = span.0; |
a1dfa0c6 XL |
1010 | } |
1011 | } | |
1012 | ||
064997fb | 1013 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
a1dfa0c6 XL |
1014 | impl ToString for Punct { |
1015 | fn to_string(&self) -> String { | |
064997fb | 1016 | self.as_char().to_string() |
83c7162d XL |
1017 | } |
1018 | } | |
1019 | ||
94b46f34 XL |
1020 | /// Prints the punctuation character as a string that should be losslessly convertible |
1021 | /// back into the same character. | |
8faf50e0 | 1022 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
94b46f34 | 1023 | impl fmt::Display for Punct { |
9fa01778 | 1024 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
064997fb | 1025 | write!(f, "{}", self.as_char()) |
83c7162d XL |
1026 | } |
1027 | } | |
041b39d2 | 1028 | |
8faf50e0 XL |
1029 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
1030 | impl fmt::Debug for Punct { | |
9fa01778 | 1031 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
8faf50e0 XL |
1032 | f.debug_struct("Punct") |
1033 | .field("ch", &self.as_char()) | |
1034 | .field("spacing", &self.spacing()) | |
1035 | .field("span", &self.span()) | |
1036 | .finish() | |
1037 | } | |
1038 | } | |
1039 | ||
6a06907d | 1040 | #[stable(feature = "proc_macro_punct_eq", since = "1.50.0")] |
fc512014 XL |
1041 | impl PartialEq<char> for Punct { |
1042 | fn eq(&self, rhs: &char) -> bool { | |
1043 | self.as_char() == *rhs | |
1044 | } | |
1045 | } | |
1046 | ||
6a06907d XL |
1047 | #[stable(feature = "proc_macro_punct_eq_flipped", since = "1.52.0")] |
1048 | impl PartialEq<Punct> for char { | |
1049 | fn eq(&self, rhs: &Punct) -> bool { | |
1050 | *self == rhs.as_char() | |
1051 | } | |
1052 | } | |
1053 | ||
94b46f34 | 1054 | /// An identifier (`ident`). |
8faf50e0 XL |
1055 | #[derive(Clone)] |
1056 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] | |
064997fb | 1057 | pub struct Ident(bridge::Ident<bridge::client::Span, bridge::client::Symbol>); |
83c7162d | 1058 | |
94b46f34 XL |
1059 | impl Ident { |
1060 | /// Creates a new `Ident` with the given `string` as well as the specified | |
83c7162d | 1061 | /// `span`. |
94b46f34 | 1062 | /// The `string` argument must be a valid identifier permitted by the |
3dfed10e | 1063 | /// language (including keywords, e.g. `self` or `fn`). Otherwise, the function will panic. |
83c7162d XL |
1064 | /// |
1065 | /// Note that `span`, currently in rustc, configures the hygiene information | |
94b46f34 XL |
1066 | /// for this identifier. |
1067 | /// | |
1068 | /// As of this time `Span::call_site()` explicitly opts-in to "call-site" hygiene | |
1069 | /// meaning that identifiers created with this span will be resolved as if they were written | |
1070 | /// directly at the location of the macro call, and other code at the macro call site will be | |
1071 | /// able to refer to them as well. | |
1072 | /// | |
1073 | /// Later spans like `Span::def_site()` will allow to opt-in to "definition-site" hygiene | |
1074 | /// meaning that identifiers created with this span will be resolved at the location of the | |
1075 | /// macro definition and other code at the macro call site will not be able to refer to them. | |
83c7162d XL |
1076 | /// |
1077 | /// Due to the current importance of hygiene this constructor, unlike other | |
1078 | /// tokens, requires a `Span` to be specified at construction. | |
8faf50e0 | 1079 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
94b46f34 | 1080 | pub fn new(string: &str, span: Span) -> Ident { |
064997fb FG |
1081 | Ident(bridge::Ident { |
1082 | sym: bridge::client::Symbol::new_ident(string, false), | |
1083 | is_raw: false, | |
1084 | span: span.0, | |
1085 | }) | |
83c7162d XL |
1086 | } |
1087 | ||
94b46f34 | 1088 | /// Same as `Ident::new`, but creates a raw identifier (`r#ident`). |
3dfed10e XL |
1089 | /// The `string` argument be a valid identifier permitted by the language |
1090 | /// (including keywords, e.g. `fn`). Keywords which are usable in path segments | |
1091 | /// (e.g. `self`, `super`) are not supported, and will cause a panic. | |
1092 | #[stable(feature = "proc_macro_raw_ident", since = "1.47.0")] | |
94b46f34 | 1093 | pub fn new_raw(string: &str, span: Span) -> Ident { |
064997fb FG |
1094 | Ident(bridge::Ident { |
1095 | sym: bridge::client::Symbol::new_ident(string, true), | |
1096 | is_raw: true, | |
1097 | span: span.0, | |
1098 | }) | |
83c7162d XL |
1099 | } |
1100 | ||
94b46f34 | 1101 | /// Returns the span of this `Ident`, encompassing the entire string returned |
064997fb | 1102 | /// by [`to_string`](ToString::to_string). |
8faf50e0 | 1103 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 1104 | pub fn span(&self) -> Span { |
064997fb | 1105 | Span(self.0.span) |
83c7162d XL |
1106 | } |
1107 | ||
94b46f34 | 1108 | /// Configures the span of this `Ident`, possibly changing its hygiene context. |
8faf50e0 | 1109 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 1110 | pub fn set_span(&mut self, span: Span) { |
064997fb | 1111 | self.0.span = span.0; |
a1dfa0c6 XL |
1112 | } |
1113 | } | |
1114 | ||
064997fb FG |
1115 | /// Converts the identifier to a string that should be losslessly convertible |
1116 | /// back into the same identifier. | |
1117 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] | |
a1dfa0c6 XL |
1118 | impl ToString for Ident { |
1119 | fn to_string(&self) -> String { | |
064997fb | 1120 | self.0.sym.with(|sym| if self.0.is_raw { ["r#", sym].concat() } else { sym.to_owned() }) |
83c7162d XL |
1121 | } |
1122 | } | |
1123 | ||
064997fb FG |
1124 | /// Prints the identifier as a string that should be losslessly convertible back |
1125 | /// into the same identifier. | |
8faf50e0 | 1126 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
94b46f34 | 1127 | impl fmt::Display for Ident { |
9fa01778 | 1128 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
064997fb FG |
1129 | if self.0.is_raw { |
1130 | f.write_str("r#")?; | |
1131 | } | |
1132 | fmt::Display::fmt(&self.0.sym, f) | |
8faf50e0 XL |
1133 | } |
1134 | } | |
1135 | ||
1136 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] | |
1137 | impl fmt::Debug for Ident { | |
9fa01778 | 1138 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
8faf50e0 XL |
1139 | f.debug_struct("Ident") |
1140 | .field("ident", &self.to_string()) | |
1141 | .field("span", &self.span()) | |
1142 | .finish() | |
041b39d2 XL |
1143 | } |
1144 | } | |
1145 | ||
94b46f34 XL |
1146 | /// A literal string (`"hello"`), byte string (`b"hello"`), |
1147 | /// character (`'a'`), byte character (`b'a'`), an integer or floating point number | |
1148 | /// with or without a suffix (`1`, `1u8`, `2.3`, `2.3f32`). | |
1149 | /// Boolean literals like `true` and `false` do not belong here, they are `Ident`s. | |
a1dfa0c6 | 1150 | #[derive(Clone)] |
8faf50e0 | 1151 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
064997fb | 1152 | pub struct Literal(bridge::Literal<bridge::client::Span, bridge::client::Symbol>); |
83c7162d XL |
1153 | |
1154 | macro_rules! suffixed_int_literals { | |
1155 | ($($name:ident => $kind:ident,)*) => ($( | |
1156 | /// Creates a new suffixed integer literal with the specified value. | |
1157 | /// | |
1158 | /// This function will create an integer like `1u32` where the integer | |
1159 | /// value specified is the first part of the token and the integral is | |
1160 | /// also suffixed at the end. | |
94222f64 | 1161 | /// Literals created from negative numbers might not survive round-trips through |
94b46f34 | 1162 | /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). |
83c7162d XL |
1163 | /// |
1164 | /// Literals created through this method have the `Span::call_site()` | |
1165 | /// span by default, which can be configured with the `set_span` method | |
1166 | /// below. | |
8faf50e0 | 1167 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 1168 | pub fn $name(n: $kind) -> Literal { |
064997fb FG |
1169 | Literal(bridge::Literal { |
1170 | kind: bridge::LitKind::Integer, | |
1171 | symbol: bridge::client::Symbol::new(&n.to_string()), | |
1172 | suffix: Some(bridge::client::Symbol::new(stringify!($kind))), | |
1173 | span: Span::call_site().0, | |
1174 | }) | |
041b39d2 | 1175 | } |
83c7162d XL |
1176 | )*) |
1177 | } | |
1178 | ||
1179 | macro_rules! unsuffixed_int_literals { | |
1180 | ($($name:ident => $kind:ident,)*) => ($( | |
1181 | /// Creates a new unsuffixed integer literal with the specified value. | |
1182 | /// | |
1183 | /// This function will create an integer like `1` where the integer | |
1184 | /// value specified is the first part of the token. No suffix is | |
1185 | /// specified on this token, meaning that invocations like | |
1186 | /// `Literal::i8_unsuffixed(1)` are equivalent to | |
1187 | /// `Literal::u32_unsuffixed(1)`. | |
94222f64 | 1188 | /// Literals created from negative numbers might not survive rountrips through |
94b46f34 | 1189 | /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). |
83c7162d XL |
1190 | /// |
1191 | /// Literals created through this method have the `Span::call_site()` | |
1192 | /// span by default, which can be configured with the `set_span` method | |
1193 | /// below. | |
8faf50e0 | 1194 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 1195 | pub fn $name(n: $kind) -> Literal { |
064997fb FG |
1196 | Literal(bridge::Literal { |
1197 | kind: bridge::LitKind::Integer, | |
1198 | symbol: bridge::client::Symbol::new(&n.to_string()), | |
1199 | suffix: None, | |
1200 | span: Span::call_site().0, | |
1201 | }) | |
83c7162d XL |
1202 | } |
1203 | )*) | |
041b39d2 XL |
1204 | } |
1205 | ||
1206 | impl Literal { | |
064997fb FG |
1207 | fn new(kind: bridge::LitKind, value: &str, suffix: Option<&str>) -> Self { |
1208 | Literal(bridge::Literal { | |
1209 | kind, | |
1210 | symbol: bridge::client::Symbol::new(value), | |
1211 | suffix: suffix.map(bridge::client::Symbol::new), | |
1212 | span: Span::call_site().0, | |
1213 | }) | |
1214 | } | |
1215 | ||
83c7162d XL |
1216 | suffixed_int_literals! { |
1217 | u8_suffixed => u8, | |
1218 | u16_suffixed => u16, | |
1219 | u32_suffixed => u32, | |
1220 | u64_suffixed => u64, | |
1221 | u128_suffixed => u128, | |
1222 | usize_suffixed => usize, | |
1223 | i8_suffixed => i8, | |
1224 | i16_suffixed => i16, | |
1225 | i32_suffixed => i32, | |
1226 | i64_suffixed => i64, | |
1227 | i128_suffixed => i128, | |
1228 | isize_suffixed => isize, | |
1229 | } | |
1230 | ||
1231 | unsuffixed_int_literals! { | |
1232 | u8_unsuffixed => u8, | |
1233 | u16_unsuffixed => u16, | |
1234 | u32_unsuffixed => u32, | |
1235 | u64_unsuffixed => u64, | |
1236 | u128_unsuffixed => u128, | |
1237 | usize_unsuffixed => usize, | |
1238 | i8_unsuffixed => i8, | |
1239 | i16_unsuffixed => i16, | |
1240 | i32_unsuffixed => i32, | |
1241 | i64_unsuffixed => i64, | |
1242 | i128_unsuffixed => i128, | |
1243 | isize_unsuffixed => isize, | |
041b39d2 XL |
1244 | } |
1245 | ||
83c7162d XL |
1246 | /// Creates a new unsuffixed floating-point literal. |
1247 | /// | |
1248 | /// This constructor is similar to those like `Literal::i8_unsuffixed` where | |
1249 | /// the float's value is emitted directly into the token but no suffix is | |
1250 | /// used, so it may be inferred to be a `f64` later in the compiler. | |
94222f64 | 1251 | /// Literals created from negative numbers might not survive rountrips through |
94b46f34 | 1252 | /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). |
83c7162d XL |
1253 | /// |
1254 | /// # Panics | |
1255 | /// | |
1256 | /// This function requires that the specified float is finite, for | |
1257 | /// example if it is infinity or NaN this function will panic. | |
8faf50e0 | 1258 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d XL |
1259 | pub fn f32_unsuffixed(n: f32) -> Literal { |
1260 | if !n.is_finite() { | |
5e7ed085 | 1261 | panic!("Invalid float literal {n}"); |
83c7162d | 1262 | } |
3c0e092e XL |
1263 | let mut repr = n.to_string(); |
1264 | if !repr.contains('.') { | |
1265 | repr.push_str(".0"); | |
1266 | } | |
064997fb | 1267 | Literal::new(bridge::LitKind::Float, &repr, None) |
041b39d2 XL |
1268 | } |
1269 | ||
83c7162d XL |
1270 | /// Creates a new suffixed floating-point literal. |
1271 | /// | |
a1dfa0c6 | 1272 | /// This constructor will create a literal like `1.0f32` where the value |
83c7162d XL |
1273 | /// specified is the preceding part of the token and `f32` is the suffix of |
1274 | /// the token. This token will always be inferred to be an `f32` in the | |
1275 | /// compiler. | |
94222f64 | 1276 | /// Literals created from negative numbers might not survive rountrips through |
94b46f34 | 1277 | /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). |
83c7162d XL |
1278 | /// |
1279 | /// # Panics | |
1280 | /// | |
1281 | /// This function requires that the specified float is finite, for | |
1282 | /// example if it is infinity or NaN this function will panic. | |
8faf50e0 | 1283 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 1284 | pub fn f32_suffixed(n: f32) -> Literal { |
041b39d2 | 1285 | if !n.is_finite() { |
5e7ed085 | 1286 | panic!("Invalid float literal {n}"); |
041b39d2 | 1287 | } |
064997fb | 1288 | Literal::new(bridge::LitKind::Float, &n.to_string(), Some("f32")) |
041b39d2 XL |
1289 | } |
1290 | ||
83c7162d XL |
1291 | /// Creates a new unsuffixed floating-point literal. |
1292 | /// | |
1293 | /// This constructor is similar to those like `Literal::i8_unsuffixed` where | |
1294 | /// the float's value is emitted directly into the token but no suffix is | |
1295 | /// used, so it may be inferred to be a `f64` later in the compiler. | |
94222f64 | 1296 | /// Literals created from negative numbers might not survive rountrips through |
94b46f34 | 1297 | /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). |
83c7162d XL |
1298 | /// |
1299 | /// # Panics | |
1300 | /// | |
1301 | /// This function requires that the specified float is finite, for | |
1302 | /// example if it is infinity or NaN this function will panic. | |
8faf50e0 | 1303 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 1304 | pub fn f64_unsuffixed(n: f64) -> Literal { |
041b39d2 | 1305 | if !n.is_finite() { |
5e7ed085 | 1306 | panic!("Invalid float literal {n}"); |
83c7162d | 1307 | } |
3c0e092e XL |
1308 | let mut repr = n.to_string(); |
1309 | if !repr.contains('.') { | |
1310 | repr.push_str(".0"); | |
1311 | } | |
064997fb | 1312 | Literal::new(bridge::LitKind::Float, &repr, None) |
041b39d2 XL |
1313 | } |
1314 | ||
83c7162d XL |
1315 | /// Creates a new suffixed floating-point literal. |
1316 | /// | |
a1dfa0c6 | 1317 | /// This constructor will create a literal like `1.0f64` where the value |
83c7162d XL |
1318 | /// specified is the preceding part of the token and `f64` is the suffix of |
1319 | /// the token. This token will always be inferred to be an `f64` in the | |
1320 | /// compiler. | |
94222f64 | 1321 | /// Literals created from negative numbers might not survive rountrips through |
94b46f34 | 1322 | /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). |
83c7162d XL |
1323 | /// |
1324 | /// # Panics | |
1325 | /// | |
1326 | /// This function requires that the specified float is finite, for | |
1327 | /// example if it is infinity or NaN this function will panic. | |
8faf50e0 | 1328 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 1329 | pub fn f64_suffixed(n: f64) -> Literal { |
041b39d2 | 1330 | if !n.is_finite() { |
5e7ed085 | 1331 | panic!("Invalid float literal {n}"); |
83c7162d | 1332 | } |
064997fb | 1333 | Literal::new(bridge::LitKind::Float, &n.to_string(), Some("f64")) |
041b39d2 XL |
1334 | } |
1335 | ||
1336 | /// String literal. | |
8faf50e0 | 1337 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
041b39d2 | 1338 | pub fn string(string: &str) -> Literal { |
064997fb FG |
1339 | let quoted = format!("{:?}", string); |
1340 | assert!(quoted.starts_with('"') && quoted.ends_with('"')); | |
1341 | let symbol = "ed[1..quoted.len() - 1]; | |
1342 | Literal::new(bridge::LitKind::Str, symbol, None) | |
041b39d2 XL |
1343 | } |
1344 | ||
1345 | /// Character literal. | |
8faf50e0 | 1346 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
041b39d2 | 1347 | pub fn character(ch: char) -> Literal { |
064997fb FG |
1348 | let quoted = format!("{:?}", ch); |
1349 | assert!(quoted.starts_with('\'') && quoted.ends_with('\'')); | |
1350 | let symbol = "ed[1..quoted.len() - 1]; | |
1351 | Literal::new(bridge::LitKind::Char, symbol, None) | |
041b39d2 XL |
1352 | } |
1353 | ||
1354 | /// Byte string literal. | |
8faf50e0 | 1355 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
041b39d2 | 1356 | pub fn byte_string(bytes: &[u8]) -> Literal { |
f2b60f7d | 1357 | let string = bytes.escape_ascii().to_string(); |
064997fb | 1358 | Literal::new(bridge::LitKind::ByteStr, &string, None) |
041b39d2 | 1359 | } |
041b39d2 | 1360 | |
83c7162d | 1361 | /// Returns the span encompassing this literal. |
8faf50e0 | 1362 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 1363 | pub fn span(&self) -> Span { |
064997fb | 1364 | Span(self.0.span) |
83c7162d XL |
1365 | } |
1366 | ||
1367 | /// Configures the span associated for this literal. | |
8faf50e0 | 1368 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 1369 | pub fn set_span(&mut self, span: Span) { |
064997fb | 1370 | self.0.span = span.0; |
a1dfa0c6 XL |
1371 | } |
1372 | ||
1373 | /// Returns a `Span` that is a subset of `self.span()` containing only the | |
1374 | /// source bytes in range `range`. Returns `None` if the would-be trimmed | |
1375 | /// span is outside the bounds of `self`. | |
1376 | // FIXME(SergioBenitez): check that the byte range starts and ends at a | |
1377 | // UTF-8 boundary of the source. otherwise, it's likely that a panic will | |
1378 | // occur elsewhere when the source text is printed. | |
1379 | // FIXME(SergioBenitez): there is no way for the user to know what | |
1380 | // `self.span()` actually maps to, so this method can currently only be | |
1381 | // called blindly. For example, `to_string()` for the character 'c' returns | |
1382 | // "'\u{63}'"; there is no way for the user to know whether the source text | |
1383 | // was 'c' or whether it was '\u{63}'. | |
1384 | #[unstable(feature = "proc_macro_span", issue = "54725")] | |
1385 | pub fn subspan<R: RangeBounds<usize>>(&self, range: R) -> Option<Span> { | |
064997fb FG |
1386 | self.0.span.subspan(range.start_bound().cloned(), range.end_bound().cloned()).map(Span) |
1387 | } | |
1388 | ||
1389 | fn with_symbol_and_suffix<R>(&self, f: impl FnOnce(&str, &str) -> R) -> R { | |
1390 | self.0.symbol.with(|symbol| match self.0.suffix { | |
1391 | Some(suffix) => suffix.with(|suffix| f(symbol, suffix)), | |
1392 | None => f(symbol, ""), | |
1393 | }) | |
1394 | } | |
1395 | ||
1396 | /// Invokes the callback with a `&[&str]` consisting of each part of the | |
1397 | /// literal's representation. This is done to allow the `ToString` and | |
1398 | /// `Display` implementations to borrow references to symbol values, and | |
1399 | /// both be optimized to reduce overhead. | |
1400 | fn with_stringify_parts<R>(&self, f: impl FnOnce(&[&str]) -> R) -> R { | |
1401 | /// Returns a string containing exactly `num` '#' characters. | |
1402 | /// Uses a 256-character source string literal which is always safe to | |
1403 | /// index with a `u8` index. | |
1404 | fn get_hashes_str(num: u8) -> &'static str { | |
1405 | const HASHES: &str = "\ | |
1406 | ################################################################\ | |
1407 | ################################################################\ | |
1408 | ################################################################\ | |
1409 | ################################################################\ | |
1410 | "; | |
1411 | const _: () = assert!(HASHES.len() == 256); | |
1412 | &HASHES[..num as usize] | |
1413 | } | |
1414 | ||
1415 | self.with_symbol_and_suffix(|symbol, suffix| match self.0.kind { | |
1416 | bridge::LitKind::Byte => f(&["b'", symbol, "'", suffix]), | |
1417 | bridge::LitKind::Char => f(&["'", symbol, "'", suffix]), | |
1418 | bridge::LitKind::Str => f(&["\"", symbol, "\"", suffix]), | |
1419 | bridge::LitKind::StrRaw(n) => { | |
1420 | let hashes = get_hashes_str(n); | |
1421 | f(&["r", hashes, "\"", symbol, "\"", hashes, suffix]) | |
1422 | } | |
1423 | bridge::LitKind::ByteStr => f(&["b\"", symbol, "\"", suffix]), | |
1424 | bridge::LitKind::ByteStrRaw(n) => { | |
1425 | let hashes = get_hashes_str(n); | |
1426 | f(&["br", hashes, "\"", symbol, "\"", hashes, suffix]) | |
1427 | } | |
1428 | _ => f(&[symbol, suffix]), | |
1429 | }) | |
17df50a5 XL |
1430 | } |
1431 | } | |
1432 | ||
1433 | /// Parse a single literal from its stringified representation. | |
1434 | /// | |
1435 | /// In order to parse successfully, the input string must not contain anything | |
1436 | /// but the literal token. Specifically, it must not contain whitespace or | |
1437 | /// comments in addition to the literal. | |
1438 | /// | |
1439 | /// The resulting literal token will have a `Span::call_site()` span. | |
1440 | /// | |
1441 | /// NOTE: some errors may cause panics instead of returning `LexError`. We | |
1442 | /// reserve the right to change these errors into `LexError`s later. | |
1443 | #[stable(feature = "proc_macro_literal_parse", since = "1.54.0")] | |
1444 | impl FromStr for Literal { | |
1445 | type Err = LexError; | |
a1dfa0c6 | 1446 | |
17df50a5 | 1447 | fn from_str(src: &str) -> Result<Self, LexError> { |
064997fb | 1448 | match bridge::client::FreeFunctions::literal_from_str(src) { |
17df50a5 | 1449 | Ok(literal) => Ok(Literal(literal)), |
3c0e092e | 1450 | Err(()) => Err(LexError), |
17df50a5 | 1451 | } |
a1dfa0c6 XL |
1452 | } |
1453 | } | |
1454 | ||
064997fb | 1455 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
a1dfa0c6 XL |
1456 | impl ToString for Literal { |
1457 | fn to_string(&self) -> String { | |
064997fb | 1458 | self.with_stringify_parts(|parts| parts.concat()) |
83c7162d | 1459 | } |
041b39d2 XL |
1460 | } |
1461 | ||
94b46f34 XL |
1462 | /// Prints the literal as a string that should be losslessly convertible |
1463 | /// back into the same literal (except for possible rounding for floating point literals). | |
8faf50e0 | 1464 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
83c7162d | 1465 | impl fmt::Display for Literal { |
9fa01778 | 1466 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
064997fb FG |
1467 | self.with_stringify_parts(|parts| { |
1468 | for part in parts { | |
1469 | fmt::Display::fmt(part, f)?; | |
1470 | } | |
1471 | Ok(()) | |
1472 | }) | |
041b39d2 XL |
1473 | } |
1474 | } | |
1475 | ||
a1dfa0c6 XL |
1476 | #[stable(feature = "proc_macro_lib2", since = "1.29.0")] |
1477 | impl fmt::Debug for Literal { | |
9fa01778 | 1478 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
064997fb FG |
1479 | f.debug_struct("Literal") |
1480 | // format the kind on one line even in {:#?} mode | |
1481 | .field("kind", &format_args!("{:?}", &self.0.kind)) | |
1482 | .field("symbol", &self.0.symbol) | |
1483 | // format `Some("...")` on one line even in {:#?} mode | |
1484 | .field("suffix", &format_args!("{:?}", &self.0.suffix)) | |
1485 | .field("span", &self.0.span) | |
1486 | .finish() | |
c30ab7b3 SL |
1487 | } |
1488 | } | |
3dfed10e XL |
1489 | |
1490 | /// Tracked access to environment variables. | |
064997fb | 1491 | #[unstable(feature = "proc_macro_tracked_env", issue = "99515")] |
3dfed10e XL |
1492 | pub mod tracked_env { |
1493 | use std::env::{self, VarError}; | |
1494 | use std::ffi::OsStr; | |
1495 | ||
1496 | /// Retrieve an environment variable and add it to build dependency info. | |
9c376795 | 1497 | /// The build system executing the compiler will know that the variable was accessed during |
3dfed10e XL |
1498 | /// compilation, and will be able to rerun the build when the value of that variable changes. |
1499 | /// Besides the dependency tracking this function should be equivalent to `env::var` from the | |
1500 | /// standard library, except that the argument must be UTF-8. | |
064997fb | 1501 | #[unstable(feature = "proc_macro_tracked_env", issue = "99515")] |
3dfed10e XL |
1502 | pub fn var<K: AsRef<OsStr> + AsRef<str>>(key: K) -> Result<String, VarError> { |
1503 | let key: &str = key.as_ref(); | |
1504 | let value = env::var(key); | |
1505 | crate::bridge::client::FreeFunctions::track_env_var(key, value.as_deref().ok()); | |
1506 | value | |
1507 | } | |
1508 | } | |
136023e0 XL |
1509 | |
1510 | /// Tracked access to additional files. | |
064997fb | 1511 | #[unstable(feature = "track_path", issue = "99515")] |
136023e0 XL |
1512 | pub mod tracked_path { |
1513 | ||
1514 | /// Track a file explicitly. | |
1515 | /// | |
1516 | /// Commonly used for tracking asset preprocessing. | |
064997fb | 1517 | #[unstable(feature = "track_path", issue = "99515")] |
136023e0 XL |
1518 | pub fn path<P: AsRef<str>>(path: P) { |
1519 | let path: &str = path.as_ref(); | |
1520 | crate::bridge::client::FreeFunctions::track_path(path); | |
1521 | } | |
1522 | } |