1 | //! [![github]](https://github.com/dtolnay/syn) [![crates-io]](https://crates.io/crates/syn) [![docs-rs]](crate) |
2 | //! |
3 | //! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github |
4 | //! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust |
5 | //! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs |
6 | //! |
7 | //! <br> |
8 | //! |
9 | //! Syn is a parsing library for parsing a stream of Rust tokens into a syntax |
10 | //! tree of Rust source code. |
11 | //! |
12 | //! Currently this library is geared toward use in Rust procedural macros, but |
13 | //! contains some APIs that may be useful more generally. |
14 | //! |
15 | //! - **Data structures** — Syn provides a complete syntax tree that can |
16 | //! represent any valid Rust source code. The syntax tree is rooted at |
17 | //! [`syn::File`] which represents a full source file, but there are other |
18 | //! entry points that may be useful to procedural macros including |
19 | //! [`syn::Item`], [`syn::Expr`] and [`syn::Type`]. |
20 | //! |
21 | //! - **Derives** — Of particular interest to derive macros is |
22 | //! [`syn::DeriveInput`] which is any of the three legal input items to a |
23 | //! derive macro. An example below shows using this type in a library that can |
24 | //! derive implementations of a user-defined trait. |
25 | //! |
26 | //! - **Parsing** — Parsing in Syn is built around [parser functions] with the |
27 | //! signature `fn(ParseStream) -> Result<T>`. Every syntax tree node defined |
28 | //! by Syn is individually parsable and may be used as a building block for |
29 | //! custom syntaxes, or you may dream up your own brand new syntax without |
30 | //! involving any of our syntax tree types. |
31 | //! |
32 | //! - **Location information** — Every token parsed by Syn is associated with a |
33 | //! `Span` that tracks line and column information back to the source of that |
34 | //! token. These spans allow a procedural macro to display detailed error |
35 | //! messages pointing to all the right places in the user's code. There is an |
36 | //! example of this below. |
37 | //! |
38 | //! - **Feature flags** — Functionality is aggressively feature gated so your |
39 | //! procedural macros enable only what they need, and do not pay in compile |
40 | //! time for all the rest. |
41 | //! |
42 | //! [`syn::File`]: File |
43 | //! [`syn::Item`]: Item |
44 | //! [`syn::Expr`]: Expr |
45 | //! [`syn::Type`]: Type |
46 | //! [`syn::DeriveInput`]: DeriveInput |
47 | //! [parser functions]: mod@parse |
48 | //! |
49 | //! <br> |
50 | //! |
51 | //! # Example of a derive macro |
52 | //! |
53 | //! The canonical derive macro using Syn looks like this. We write an ordinary |
54 | //! Rust function tagged with a `proc_macro_derive` attribute and the name of |
55 | //! the trait we are deriving. Any time that derive appears in the user's code, |
56 | //! the Rust compiler passes their data structure as tokens into our macro. We |
57 | //! get to execute arbitrary Rust code to figure out what to do with those |
58 | //! tokens, then hand some tokens back to the compiler to compile into the |
59 | //! user's crate. |
60 | //! |
61 | //! [`TokenStream`]: proc_macro::TokenStream |
62 | //! |
63 | //! ```toml |
64 | //! [dependencies] |
65 | //! syn = "2.0" |
66 | //! quote = "1.0" |
67 | //! |
68 | //! [lib] |
69 | //! proc-macro = true |
70 | //! ``` |
71 | //! |
72 | //! ``` |
73 | //! # extern crate proc_macro; |
74 | //! # |
75 | //! use proc_macro::TokenStream; |
76 | //! use quote::quote; |
77 | //! use syn::{parse_macro_input, DeriveInput}; |
78 | //! |
79 | //! # const IGNORE_TOKENS: &str = stringify! { |
80 | //! #[proc_macro_derive(MyMacro)] |
81 | //! # }; |
82 | //! pub fn my_macro(input: TokenStream) -> TokenStream { |
83 | //! // Parse the input tokens into a syntax tree |
84 | //! let input = parse_macro_input!(input as DeriveInput); |
85 | //! |
86 | //! // Build the output, possibly using quasi-quotation |
87 | //! let expanded = quote! { |
88 | //! // ... |
89 | //! }; |
90 | //! |
91 | //! // Hand the output tokens back to the compiler |
92 | //! TokenStream::from(expanded) |
93 | //! } |
94 | //! ``` |
95 | //! |
96 | //! The [`heapsize`] example directory shows a complete working implementation |
97 | //! of a derive macro. The example derives a `HeapSize` trait which computes an |
98 | //! estimate of the amount of heap memory owned by a value. |
99 | //! |
100 | //! [`heapsize`]: https://github.com/dtolnay/syn/tree/master/examples/heapsize |
101 | //! |
102 | //! ``` |
103 | //! pub trait HeapSize { |
104 | //! /// Total number of bytes of heap memory owned by `self`. |
105 | //! fn heap_size_of_children(&self) -> usize; |
106 | //! } |
107 | //! ``` |
108 | //! |
109 | //! The derive macro allows users to write `#[derive(HeapSize)]` on data |
110 | //! structures in their program. |
111 | //! |
112 | //! ``` |
113 | //! # const IGNORE_TOKENS: &str = stringify! { |
114 | //! #[derive(HeapSize)] |
115 | //! # }; |
116 | //! struct Demo<'a, T: ?Sized> { |
117 | //! a: Box<T>, |
118 | //! b: u8, |
119 | //! c: &'a str, |
120 | //! d: String, |
121 | //! } |
122 | //! ``` |
123 | //! |
124 | //! <p><br></p> |
125 | //! |
126 | //! # Spans and error reporting |
127 | //! |
128 | //! The token-based procedural macro API provides great control over where the |
129 | //! compiler's error messages are displayed in user code. Consider the error the |
130 | //! user sees if one of their field types does not implement `HeapSize`. |
131 | //! |
132 | //! ``` |
133 | //! # const IGNORE_TOKENS: &str = stringify! { |
134 | //! #[derive(HeapSize)] |
135 | //! # }; |
136 | //! struct Broken { |
137 | //! ok: String, |
138 | //! bad: std::thread::Thread, |
139 | //! } |
140 | //! ``` |
141 | //! |
142 | //! By tracking span information all the way through the expansion of a |
143 | //! procedural macro as shown in the `heapsize` example, token-based macros in |
144 | //! Syn are able to trigger errors that directly pinpoint the source of the |
145 | //! problem. |
146 | //! |
147 | //! ```text |
148 | //! error[E0277]: the trait bound `std::thread::Thread: HeapSize` is not satisfied |
149 | //! --> src/main.rs:7:5 |
150 | //! | |
151 | //! 7 | bad: std::thread::Thread, |
152 | //! | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HeapSize` is not implemented for `Thread` |
153 | //! ``` |
154 | //! |
155 | //! <br> |
156 | //! |
157 | //! # Parsing a custom syntax |
158 | //! |
159 | //! The [`lazy-static`] example directory shows the implementation of a |
160 | //! `functionlike!(...)` procedural macro in which the input tokens are parsed |
161 | //! using Syn's parsing API. |
162 | //! |
163 | //! [`lazy-static`]: https://github.com/dtolnay/syn/tree/master/examples/lazy-static |
164 | //! |
165 | //! The example reimplements the popular `lazy_static` crate from crates.io as a |
166 | //! procedural macro. |
167 | //! |
168 | //! ``` |
169 | //! # macro_rules! lazy_static { |
170 | //! # ($($tt:tt)*) => {} |
171 | //! # } |
172 | //! # |
173 | //! lazy_static! { |
174 | //! static ref USERNAME: Regex = Regex::new("^[a-z0-9_-]{3,16}$" ).unwrap(); |
175 | //! } |
176 | //! ``` |
177 | //! |
178 | //! The implementation shows how to trigger custom warnings and error messages |
179 | //! on the macro input. |
180 | //! |
181 | //! ```text |
182 | //! warning: come on, pick a more creative name |
183 | //! --> src/main.rs:10:16 |
184 | //! | |
185 | //! 10 | static ref FOO: String = "lazy_static".to_owned(); |
186 | //! | ^^^ |
187 | //! ``` |
188 | //! |
189 | //! <br> |
190 | //! |
191 | //! # Testing |
192 | //! |
193 | //! When testing macros, we often care not just that the macro can be used |
194 | //! successfully but also that when the macro is provided with invalid input it |
195 | //! produces maximally helpful error messages. Consider using the [`trybuild`] |
196 | //! crate to write tests for errors that are emitted by your macro or errors |
197 | //! detected by the Rust compiler in the expanded code following misuse of the |
198 | //! macro. Such tests help avoid regressions from later refactors that |
199 | //! mistakenly make an error no longer trigger or be less helpful than it used |
200 | //! to be. |
201 | //! |
202 | //! [`trybuild`]: https://github.com/dtolnay/trybuild |
203 | //! |
204 | //! <br> |
205 | //! |
206 | //! # Debugging |
207 | //! |
208 | //! When developing a procedural macro it can be helpful to look at what the |
209 | //! generated code looks like. Use `cargo rustc -- -Zunstable-options |
210 | //! --pretty=expanded` or the [`cargo expand`] subcommand. |
211 | //! |
212 | //! [`cargo expand`]: https://github.com/dtolnay/cargo-expand |
213 | //! |
214 | //! To show the expanded code for some crate that uses your procedural macro, |
215 | //! run `cargo expand` from that crate. To show the expanded code for one of |
216 | //! your own test cases, run `cargo expand --test the_test_case` where the last |
217 | //! argument is the name of the test file without the `.rs` extension. |
218 | //! |
219 | //! This write-up by Brandon W Maister discusses debugging in more detail: |
220 | //! [Debugging Rust's new Custom Derive system][debugging]. |
221 | //! |
222 | //! [debugging]: https://quodlibetor.github.io/posts/debugging-rusts-new-custom-derive-system/ |
223 | //! |
224 | //! <br> |
225 | //! |
226 | //! # Optional features |
227 | //! |
228 | //! Syn puts a lot of functionality behind optional features in order to |
229 | //! optimize compile time for the most common use cases. The following features |
230 | //! are available. |
231 | //! |
232 | //! - **`derive`** *(enabled by default)* — Data structures for representing the |
233 | //! possible input to a derive macro, including structs and enums and types. |
234 | //! - **`full`** — Data structures for representing the syntax tree of all valid |
235 | //! Rust source code, including items and expressions. |
236 | //! - **`parsing`** *(enabled by default)* — Ability to parse input tokens into |
237 | //! a syntax tree node of a chosen type. |
238 | //! - **`printing`** *(enabled by default)* — Ability to print a syntax tree |
239 | //! node as tokens of Rust source code. |
240 | //! - **`visit`** — Trait for traversing a syntax tree. |
241 | //! - **`visit-mut`** — Trait for traversing and mutating in place a syntax |
242 | //! tree. |
243 | //! - **`fold`** — Trait for transforming an owned syntax tree. |
244 | //! - **`clone-impls`** *(enabled by default)* — Clone impls for all syntax tree |
245 | //! types. |
246 | //! - **`extra-traits`** — Debug, Eq, PartialEq, Hash impls for all syntax tree |
247 | //! types. |
248 | //! - **`proc-macro`** *(enabled by default)* — Runtime dependency on the |
249 | //! dynamic library libproc_macro from rustc toolchain. |
250 | |
251 | // Syn types in rustdoc of other crates get linked to here. |
252 | #![doc (html_root_url = "https://docs.rs/syn/2.0.100" )] |
253 | #![cfg_attr (docsrs, feature(doc_cfg))] |
254 | #![deny (unsafe_op_in_unsafe_fn)] |
255 | #![allow (non_camel_case_types)] |
256 | #![cfg_attr (not(check_cfg), allow(unexpected_cfgs))] |
257 | #![allow ( |
258 | clippy::bool_to_int_with_if, |
259 | clippy::cast_lossless, |
260 | clippy::cast_possible_truncation, |
261 | clippy::cast_possible_wrap, |
262 | clippy::cast_ptr_alignment, |
263 | clippy::default_trait_access, |
264 | clippy::derivable_impls, |
265 | clippy::diverging_sub_expression, |
266 | clippy::doc_markdown, |
267 | clippy::elidable_lifetime_names, |
268 | clippy::enum_glob_use, |
269 | clippy::expl_impl_clone_on_copy, |
270 | clippy::explicit_auto_deref, |
271 | clippy::fn_params_excessive_bools, |
272 | clippy::if_not_else, |
273 | clippy::inherent_to_string, |
274 | clippy::into_iter_without_iter, |
275 | clippy::items_after_statements, |
276 | clippy::large_enum_variant, |
277 | clippy::let_underscore_untyped, // https://github.com/rust-lang/rust-clippy/issues/10410 |
278 | clippy::manual_assert, |
279 | clippy::manual_let_else, |
280 | clippy::manual_map, |
281 | clippy::match_like_matches_macro, |
282 | clippy::match_on_vec_items, |
283 | clippy::match_same_arms, |
284 | clippy::match_wildcard_for_single_variants, // clippy bug: https://github.com/rust-lang/rust-clippy/issues/6984 |
285 | clippy::missing_errors_doc, |
286 | clippy::missing_panics_doc, |
287 | clippy::module_name_repetitions, |
288 | clippy::must_use_candidate, |
289 | clippy::needless_doctest_main, |
290 | clippy::needless_lifetimes, |
291 | clippy::needless_pass_by_value, |
292 | clippy::needless_update, |
293 | clippy::never_loop, |
294 | clippy::range_plus_one, |
295 | clippy::redundant_else, |
296 | clippy::ref_option, |
297 | clippy::return_self_not_must_use, |
298 | clippy::similar_names, |
299 | clippy::single_match_else, |
300 | clippy::struct_excessive_bools, |
301 | clippy::too_many_arguments, |
302 | clippy::too_many_lines, |
303 | clippy::trivially_copy_pass_by_ref, |
304 | clippy::unconditional_recursion, // https://github.com/rust-lang/rust-clippy/issues/12133 |
305 | clippy::uninhabited_references, |
306 | clippy::uninlined_format_args, |
307 | clippy::unnecessary_box_returns, |
308 | clippy::unnecessary_unwrap, |
309 | clippy::used_underscore_binding, |
310 | clippy::wildcard_imports, |
311 | )] |
312 | |
313 | extern crate self as syn; |
314 | |
315 | #[cfg (feature = "proc-macro" )] |
316 | extern crate proc_macro; |
317 | |
318 | #[macro_use ] |
319 | mod macros; |
320 | |
321 | #[cfg (feature = "parsing" )] |
322 | #[macro_use ] |
323 | mod group; |
324 | |
325 | #[macro_use ] |
326 | pub mod token; |
327 | |
328 | #[cfg (any(feature = "full" , feature = "derive" ))] |
329 | mod attr; |
330 | #[cfg (any(feature = "full" , feature = "derive" ))] |
331 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
332 | pub use crate::attr::{AttrStyle, Attribute, Meta, MetaList, MetaNameValue}; |
333 | |
334 | mod bigint; |
335 | |
336 | #[cfg (feature = "parsing" )] |
337 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
338 | pub mod buffer; |
339 | |
340 | #[cfg (any( |
341 | all(feature = "parsing" , feature = "full" ), |
342 | all(feature = "printing" , any(feature = "full" , feature = "derive" )), |
343 | ))] |
344 | mod classify; |
345 | |
346 | mod custom_keyword; |
347 | |
348 | mod custom_punctuation; |
349 | |
350 | #[cfg (any(feature = "full" , feature = "derive" ))] |
351 | mod data; |
352 | #[cfg (any(feature = "full" , feature = "derive" ))] |
353 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
354 | pub use crate::data::{Field, Fields, FieldsNamed, FieldsUnnamed, Variant}; |
355 | |
356 | #[cfg (any(feature = "full" , feature = "derive" ))] |
357 | mod derive; |
358 | #[cfg (feature = "derive" )] |
359 | #[cfg_attr (docsrs, doc(cfg(feature = "derive" )))] |
360 | pub use crate::derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput}; |
361 | |
362 | mod drops; |
363 | |
364 | mod error; |
365 | pub use crate::error::{Error, Result}; |
366 | |
367 | #[cfg (any(feature = "full" , feature = "derive" ))] |
368 | mod expr; |
369 | #[cfg (feature = "full" )] |
370 | #[cfg_attr (docsrs, doc(cfg(feature = "full" )))] |
371 | pub use crate::expr::{Arm, Label, PointerMutability, RangeLimits}; |
372 | #[cfg (any(feature = "full" , feature = "derive" ))] |
373 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
374 | pub use crate::expr::{ |
375 | Expr, ExprBinary, ExprCall, ExprCast, ExprField, ExprIndex, ExprLit, ExprMacro, ExprMethodCall, |
376 | ExprParen, ExprPath, ExprReference, ExprStruct, ExprUnary, FieldValue, Index, Member, |
377 | }; |
378 | #[cfg (any(feature = "full" , feature = "derive" ))] |
379 | #[cfg_attr (docsrs, doc(cfg(feature = "full" )))] |
380 | pub use crate::expr::{ |
381 | ExprArray, ExprAssign, ExprAsync, ExprAwait, ExprBlock, ExprBreak, ExprClosure, ExprConst, |
382 | ExprContinue, ExprForLoop, ExprGroup, ExprIf, ExprInfer, ExprLet, ExprLoop, ExprMatch, |
383 | ExprRange, ExprRawAddr, ExprRepeat, ExprReturn, ExprTry, ExprTryBlock, ExprTuple, ExprUnsafe, |
384 | ExprWhile, ExprYield, |
385 | }; |
386 | |
387 | #[cfg (feature = "parsing" )] |
388 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
389 | pub mod ext; |
390 | |
391 | #[cfg (feature = "full" )] |
392 | mod file; |
393 | #[cfg (feature = "full" )] |
394 | #[cfg_attr (docsrs, doc(cfg(feature = "full" )))] |
395 | pub use crate::file::File; |
396 | |
397 | #[cfg (all(any(feature = "full" , feature = "derive" ), feature = "printing" ))] |
398 | mod fixup; |
399 | |
400 | #[cfg (any(feature = "full" , feature = "derive" ))] |
401 | mod generics; |
402 | #[cfg (any(feature = "full" , feature = "derive" ))] |
403 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
404 | pub use crate::generics::{ |
405 | BoundLifetimes, ConstParam, GenericParam, Generics, LifetimeParam, PredicateLifetime, |
406 | PredicateType, TraitBound, TraitBoundModifier, TypeParam, TypeParamBound, WhereClause, |
407 | WherePredicate, |
408 | }; |
409 | #[cfg (feature = "full" )] |
410 | #[cfg_attr (docsrs, doc(cfg(feature = "full" )))] |
411 | pub use crate::generics::{CapturedParam, PreciseCapture}; |
412 | #[cfg (all(any(feature = "full" , feature = "derive" ), feature = "printing" ))] |
413 | #[cfg_attr ( |
414 | docsrs, |
415 | doc(cfg(all(any(feature = "full" , feature = "derive" ), feature = "printing" ))) |
416 | )] |
417 | pub use crate::generics::{ImplGenerics, Turbofish, TypeGenerics}; |
418 | |
419 | mod ident; |
420 | #[doc (inline)] |
421 | pub use crate::ident::Ident; |
422 | |
423 | #[cfg (feature = "full" )] |
424 | mod item; |
425 | #[cfg (feature = "full" )] |
426 | #[cfg_attr (docsrs, doc(cfg(feature = "full" )))] |
427 | pub use crate::item::{ |
428 | FnArg, ForeignItem, ForeignItemFn, ForeignItemMacro, ForeignItemStatic, ForeignItemType, |
429 | ImplItem, ImplItemConst, ImplItemFn, ImplItemMacro, ImplItemType, ImplRestriction, Item, |
430 | ItemConst, ItemEnum, ItemExternCrate, ItemFn, ItemForeignMod, ItemImpl, ItemMacro, ItemMod, |
431 | ItemStatic, ItemStruct, ItemTrait, ItemTraitAlias, ItemType, ItemUnion, ItemUse, Receiver, |
432 | Signature, StaticMutability, TraitItem, TraitItemConst, TraitItemFn, TraitItemMacro, |
433 | TraitItemType, UseGlob, UseGroup, UseName, UsePath, UseRename, UseTree, Variadic, |
434 | }; |
435 | |
436 | mod lifetime; |
437 | #[doc (inline)] |
438 | pub use crate::lifetime::Lifetime; |
439 | |
440 | mod lit; |
441 | #[doc (hidden)] // https://github.com/dtolnay/syn/issues/1566 |
442 | pub use crate::lit::StrStyle; |
443 | #[doc (inline)] |
444 | pub use crate::lit::{ |
445 | Lit, LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitInt, LitStr, |
446 | }; |
447 | |
448 | #[cfg (feature = "parsing" )] |
449 | mod lookahead; |
450 | |
451 | #[cfg (any(feature = "full" , feature = "derive" ))] |
452 | mod mac; |
453 | #[cfg (any(feature = "full" , feature = "derive" ))] |
454 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
455 | pub use crate::mac::{Macro, MacroDelimiter}; |
456 | |
457 | #[cfg (all(feature = "parsing" , any(feature = "full" , feature = "derive" )))] |
458 | #[cfg_attr ( |
459 | docsrs, |
460 | doc(cfg(all(feature = "parsing" , any(feature = "full" , feature = "derive" )))) |
461 | )] |
462 | pub mod meta; |
463 | |
464 | #[cfg (any(feature = "full" , feature = "derive" ))] |
465 | mod op; |
466 | #[cfg (any(feature = "full" , feature = "derive" ))] |
467 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
468 | pub use crate::op::{BinOp, UnOp}; |
469 | |
470 | #[cfg (feature = "parsing" )] |
471 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
472 | pub mod parse; |
473 | |
474 | #[cfg (all(feature = "parsing" , feature = "proc-macro" ))] |
475 | mod parse_macro_input; |
476 | |
477 | #[cfg (all(feature = "parsing" , feature = "printing" ))] |
478 | mod parse_quote; |
479 | |
480 | #[cfg (feature = "full" )] |
481 | mod pat; |
482 | #[cfg (feature = "full" )] |
483 | #[cfg_attr (docsrs, doc(cfg(feature = "full" )))] |
484 | pub use crate::pat::{ |
485 | FieldPat, Pat, PatConst, PatIdent, PatLit, PatMacro, PatOr, PatParen, PatPath, PatRange, |
486 | PatReference, PatRest, PatSlice, PatStruct, PatTuple, PatTupleStruct, PatType, PatWild, |
487 | }; |
488 | |
489 | #[cfg (any(feature = "full" , feature = "derive" ))] |
490 | mod path; |
491 | #[cfg (any(feature = "full" , feature = "derive" ))] |
492 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
493 | pub use crate::path::{ |
494 | AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, GenericArgument, |
495 | ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf, |
496 | }; |
497 | |
498 | #[cfg (all( |
499 | any(feature = "full" , feature = "derive" ), |
500 | any(feature = "parsing" , feature = "printing" ) |
501 | ))] |
502 | mod precedence; |
503 | |
504 | #[cfg (all(any(feature = "full" , feature = "derive" ), feature = "printing" ))] |
505 | mod print; |
506 | |
507 | pub mod punctuated; |
508 | |
509 | #[cfg (any(feature = "full" , feature = "derive" ))] |
510 | mod restriction; |
511 | #[cfg (any(feature = "full" , feature = "derive" ))] |
512 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
513 | pub use crate::restriction::{FieldMutability, VisRestricted, Visibility}; |
514 | |
515 | mod sealed; |
516 | |
517 | #[cfg (all(feature = "parsing" , feature = "derive" , not(feature = "full" )))] |
518 | mod scan_expr; |
519 | |
520 | mod span; |
521 | |
522 | #[cfg (all(feature = "parsing" , feature = "printing" ))] |
523 | #[cfg_attr (docsrs, doc(cfg(all(feature = "parsing" , feature = "printing" ))))] |
524 | pub mod spanned; |
525 | |
526 | #[cfg (feature = "full" )] |
527 | mod stmt; |
528 | #[cfg (feature = "full" )] |
529 | #[cfg_attr (docsrs, doc(cfg(feature = "full" )))] |
530 | pub use crate::stmt::{Block, Local, LocalInit, Stmt, StmtMacro}; |
531 | |
532 | mod thread; |
533 | |
534 | #[cfg (all(any(feature = "full" , feature = "derive" ), feature = "extra-traits" ))] |
535 | mod tt; |
536 | |
537 | #[cfg (any(feature = "full" , feature = "derive" ))] |
538 | mod ty; |
539 | #[cfg (any(feature = "full" , feature = "derive" ))] |
540 | #[cfg_attr (docsrs, doc(cfg(any(feature = "full" , feature = "derive" ))))] |
541 | pub use crate::ty::{ |
542 | Abi, BareFnArg, BareVariadic, ReturnType, Type, TypeArray, TypeBareFn, TypeGroup, |
543 | TypeImplTrait, TypeInfer, TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, TypeReference, |
544 | TypeSlice, TypeTraitObject, TypeTuple, |
545 | }; |
546 | |
547 | #[cfg (all(any(feature = "full" , feature = "derive" ), feature = "parsing" ))] |
548 | mod verbatim; |
549 | |
550 | #[cfg (all(feature = "parsing" , feature = "full" ))] |
551 | mod whitespace; |
552 | |
553 | #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/6176 |
554 | mod gen { |
555 | /// Syntax tree traversal to transform the nodes of an owned syntax tree. |
556 | /// |
557 | /// Each method of the [`Fold`] trait is a hook that can be overridden to |
558 | /// customize the behavior when transforming the corresponding type of node. |
559 | /// By default, every method recursively visits the substructure of the |
560 | /// input by invoking the right visitor method of each of its fields. |
561 | /// |
562 | /// [`Fold`]: fold::Fold |
563 | /// |
564 | /// ``` |
565 | /// # use syn::{Attribute, BinOp, Expr, ExprBinary}; |
566 | /// # |
567 | /// pub trait Fold { |
568 | /// /* ... */ |
569 | /// |
570 | /// fn fold_expr_binary(&mut self, node: ExprBinary) -> ExprBinary { |
571 | /// fold_expr_binary(self, node) |
572 | /// } |
573 | /// |
574 | /// /* ... */ |
575 | /// # fn fold_attribute(&mut self, node: Attribute) -> Attribute; |
576 | /// # fn fold_expr(&mut self, node: Expr) -> Expr; |
577 | /// # fn fold_bin_op(&mut self, node: BinOp) -> BinOp; |
578 | /// } |
579 | /// |
580 | /// pub fn fold_expr_binary<V>(v: &mut V, node: ExprBinary) -> ExprBinary |
581 | /// where |
582 | /// V: Fold + ?Sized, |
583 | /// { |
584 | /// ExprBinary { |
585 | /// attrs: node |
586 | /// .attrs |
587 | /// .into_iter() |
588 | /// .map(|attr| v.fold_attribute(attr)) |
589 | /// .collect(), |
590 | /// left: Box::new(v.fold_expr(*node.left)), |
591 | /// op: v.fold_bin_op(node.op), |
592 | /// right: Box::new(v.fold_expr(*node.right)), |
593 | /// } |
594 | /// } |
595 | /// |
596 | /// /* ... */ |
597 | /// ``` |
598 | /// |
599 | /// <br> |
600 | /// |
601 | /// # Example |
602 | /// |
603 | /// This fold inserts parentheses to fully parenthesizes any expression. |
604 | /// |
605 | /// ``` |
606 | /// // [dependencies] |
607 | /// // quote = "1.0" |
608 | /// // syn = { version = "2.0", features = ["fold", "full"] } |
609 | /// |
610 | /// use quote::quote; |
611 | /// use syn::fold::{fold_expr, Fold}; |
612 | /// use syn::{token, Expr, ExprParen}; |
613 | /// |
614 | /// struct ParenthesizeEveryExpr; |
615 | /// |
616 | /// impl Fold for ParenthesizeEveryExpr { |
617 | /// fn fold_expr(&mut self, expr: Expr) -> Expr { |
618 | /// Expr::Paren(ExprParen { |
619 | /// attrs: Vec::new(), |
620 | /// expr: Box::new(fold_expr(self, expr)), |
621 | /// paren_token: token::Paren::default(), |
622 | /// }) |
623 | /// } |
624 | /// } |
625 | /// |
626 | /// fn main() { |
627 | /// let code = quote! { a() + b(1) * c.d }; |
628 | /// let expr: Expr = syn::parse2(code).unwrap(); |
629 | /// let parenthesized = ParenthesizeEveryExpr.fold_expr(expr); |
630 | /// println!("{}" , quote!(#parenthesized)); |
631 | /// |
632 | /// // Output: (((a)()) + (((b)((1))) * ((c).d))) |
633 | /// } |
634 | /// ``` |
635 | #[cfg (feature = "fold" )] |
636 | #[cfg_attr (docsrs, doc(cfg(feature = "fold" )))] |
637 | #[rustfmt::skip] |
638 | pub mod fold; |
639 | |
640 | /// Syntax tree traversal to walk a shared borrow of a syntax tree. |
641 | /// |
642 | /// Each method of the [`Visit`] trait is a hook that can be overridden to |
643 | /// customize the behavior when visiting the corresponding type of node. By |
644 | /// default, every method recursively visits the substructure of the input |
645 | /// by invoking the right visitor method of each of its fields. |
646 | /// |
647 | /// [`Visit`]: visit::Visit |
648 | /// |
649 | /// ``` |
650 | /// # use syn::{Attribute, BinOp, Expr, ExprBinary}; |
651 | /// # |
652 | /// pub trait Visit<'ast> { |
653 | /// /* ... */ |
654 | /// |
655 | /// fn visit_expr_binary(&mut self, node: &'ast ExprBinary) { |
656 | /// visit_expr_binary(self, node); |
657 | /// } |
658 | /// |
659 | /// /* ... */ |
660 | /// # fn visit_attribute(&mut self, node: &'ast Attribute); |
661 | /// # fn visit_expr(&mut self, node: &'ast Expr); |
662 | /// # fn visit_bin_op(&mut self, node: &'ast BinOp); |
663 | /// } |
664 | /// |
665 | /// pub fn visit_expr_binary<'ast, V>(v: &mut V, node: &'ast ExprBinary) |
666 | /// where |
667 | /// V: Visit<'ast> + ?Sized, |
668 | /// { |
669 | /// for attr in &node.attrs { |
670 | /// v.visit_attribute(attr); |
671 | /// } |
672 | /// v.visit_expr(&*node.left); |
673 | /// v.visit_bin_op(&node.op); |
674 | /// v.visit_expr(&*node.right); |
675 | /// } |
676 | /// |
677 | /// /* ... */ |
678 | /// ``` |
679 | /// |
680 | /// <br> |
681 | /// |
682 | /// # Example |
683 | /// |
684 | /// This visitor will print the name of every freestanding function in the |
685 | /// syntax tree, including nested functions. |
686 | /// |
687 | /// ``` |
688 | /// // [dependencies] |
689 | /// // quote = "1.0" |
690 | /// // syn = { version = "2.0", features = ["full", "visit"] } |
691 | /// |
692 | /// use quote::quote; |
693 | /// use syn::visit::{self, Visit}; |
694 | /// use syn::{File, ItemFn}; |
695 | /// |
696 | /// struct FnVisitor; |
697 | /// |
698 | /// impl<'ast> Visit<'ast> for FnVisitor { |
699 | /// fn visit_item_fn(&mut self, node: &'ast ItemFn) { |
700 | /// println!("Function with name={}" , node.sig.ident); |
701 | /// |
702 | /// // Delegate to the default impl to visit any nested functions. |
703 | /// visit::visit_item_fn(self, node); |
704 | /// } |
705 | /// } |
706 | /// |
707 | /// fn main() { |
708 | /// let code = quote! { |
709 | /// pub fn f() { |
710 | /// fn g() {} |
711 | /// } |
712 | /// }; |
713 | /// |
714 | /// let syntax_tree: File = syn::parse2(code).unwrap(); |
715 | /// FnVisitor.visit_file(&syntax_tree); |
716 | /// } |
717 | /// ``` |
718 | /// |
719 | /// The `'ast` lifetime on the input references means that the syntax tree |
720 | /// outlives the complete recursive visit call, so the visitor is allowed to |
721 | /// hold on to references into the syntax tree. |
722 | /// |
723 | /// ``` |
724 | /// use quote::quote; |
725 | /// use syn::visit::{self, Visit}; |
726 | /// use syn::{File, ItemFn}; |
727 | /// |
728 | /// struct FnVisitor<'ast> { |
729 | /// functions: Vec<&'ast ItemFn>, |
730 | /// } |
731 | /// |
732 | /// impl<'ast> Visit<'ast> for FnVisitor<'ast> { |
733 | /// fn visit_item_fn(&mut self, node: &'ast ItemFn) { |
734 | /// self.functions.push(node); |
735 | /// visit::visit_item_fn(self, node); |
736 | /// } |
737 | /// } |
738 | /// |
739 | /// fn main() { |
740 | /// let code = quote! { |
741 | /// pub fn f() { |
742 | /// fn g() {} |
743 | /// } |
744 | /// }; |
745 | /// |
746 | /// let syntax_tree: File = syn::parse2(code).unwrap(); |
747 | /// let mut visitor = FnVisitor { functions: Vec::new() }; |
748 | /// visitor.visit_file(&syntax_tree); |
749 | /// for f in visitor.functions { |
750 | /// println!("Function with name={}" , f.sig.ident); |
751 | /// } |
752 | /// } |
753 | /// ``` |
754 | #[cfg (feature = "visit" )] |
755 | #[cfg_attr (docsrs, doc(cfg(feature = "visit" )))] |
756 | #[rustfmt::skip] |
757 | pub mod visit; |
758 | |
759 | /// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in |
760 | /// place. |
761 | /// |
762 | /// Each method of the [`VisitMut`] trait is a hook that can be overridden |
763 | /// to customize the behavior when mutating the corresponding type of node. |
764 | /// By default, every method recursively visits the substructure of the |
765 | /// input by invoking the right visitor method of each of its fields. |
766 | /// |
767 | /// [`VisitMut`]: visit_mut::VisitMut |
768 | /// |
769 | /// ``` |
770 | /// # use syn::{Attribute, BinOp, Expr, ExprBinary}; |
771 | /// # |
772 | /// pub trait VisitMut { |
773 | /// /* ... */ |
774 | /// |
775 | /// fn visit_expr_binary_mut(&mut self, node: &mut ExprBinary) { |
776 | /// visit_expr_binary_mut(self, node); |
777 | /// } |
778 | /// |
779 | /// /* ... */ |
780 | /// # fn visit_attribute_mut(&mut self, node: &mut Attribute); |
781 | /// # fn visit_expr_mut(&mut self, node: &mut Expr); |
782 | /// # fn visit_bin_op_mut(&mut self, node: &mut BinOp); |
783 | /// } |
784 | /// |
785 | /// pub fn visit_expr_binary_mut<V>(v: &mut V, node: &mut ExprBinary) |
786 | /// where |
787 | /// V: VisitMut + ?Sized, |
788 | /// { |
789 | /// for attr in &mut node.attrs { |
790 | /// v.visit_attribute_mut(attr); |
791 | /// } |
792 | /// v.visit_expr_mut(&mut *node.left); |
793 | /// v.visit_bin_op_mut(&mut node.op); |
794 | /// v.visit_expr_mut(&mut *node.right); |
795 | /// } |
796 | /// |
797 | /// /* ... */ |
798 | /// ``` |
799 | /// |
800 | /// <br> |
801 | /// |
802 | /// # Example |
803 | /// |
804 | /// This mut visitor replace occurrences of u256 suffixed integer literals |
805 | /// like `999u256` with a macro invocation `bigint::u256!(999)`. |
806 | /// |
807 | /// ``` |
808 | /// // [dependencies] |
809 | /// // quote = "1.0" |
810 | /// // syn = { version = "2.0", features = ["full", "visit-mut"] } |
811 | /// |
812 | /// use quote::quote; |
813 | /// use syn::visit_mut::{self, VisitMut}; |
814 | /// use syn::{parse_quote, Expr, File, Lit, LitInt}; |
815 | /// |
816 | /// struct BigintReplace; |
817 | /// |
818 | /// impl VisitMut for BigintReplace { |
819 | /// fn visit_expr_mut(&mut self, node: &mut Expr) { |
820 | /// if let Expr::Lit(expr) = &node { |
821 | /// if let Lit::Int(int) = &expr.lit { |
822 | /// if int.suffix() == "u256" { |
823 | /// let digits = int.base10_digits(); |
824 | /// let unsuffixed: LitInt = syn::parse_str(digits).unwrap(); |
825 | /// *node = parse_quote!(bigint::u256!(#unsuffixed)); |
826 | /// return; |
827 | /// } |
828 | /// } |
829 | /// } |
830 | /// |
831 | /// // Delegate to the default impl to visit nested expressions. |
832 | /// visit_mut::visit_expr_mut(self, node); |
833 | /// } |
834 | /// } |
835 | /// |
836 | /// fn main() { |
837 | /// let code = quote! { |
838 | /// fn main() { |
839 | /// let _ = 999u256; |
840 | /// } |
841 | /// }; |
842 | /// |
843 | /// let mut syntax_tree: File = syn::parse2(code).unwrap(); |
844 | /// BigintReplace.visit_file_mut(&mut syntax_tree); |
845 | /// println!("{}" , quote!(#syntax_tree)); |
846 | /// } |
847 | /// ``` |
848 | #[cfg (feature = "visit-mut" )] |
849 | #[cfg_attr (docsrs, doc(cfg(feature = "visit-mut" )))] |
850 | #[rustfmt::skip] |
851 | pub mod visit_mut; |
852 | |
853 | #[cfg (feature = "clone-impls" )] |
854 | #[rustfmt::skip] |
855 | mod clone; |
856 | |
857 | #[cfg (feature = "extra-traits" )] |
858 | #[rustfmt::skip] |
859 | mod debug; |
860 | |
861 | #[cfg (feature = "extra-traits" )] |
862 | #[rustfmt::skip] |
863 | mod eq; |
864 | |
865 | #[cfg (feature = "extra-traits" )] |
866 | #[rustfmt::skip] |
867 | mod hash; |
868 | } |
869 | |
870 | #[cfg (feature = "fold" )] |
871 | #[cfg_attr (docsrs, doc(cfg(feature = "fold" )))] |
872 | pub use crate::gen::fold; |
873 | |
874 | #[cfg (feature = "visit" )] |
875 | #[cfg_attr (docsrs, doc(cfg(feature = "visit" )))] |
876 | pub use crate::gen::visit; |
877 | |
878 | #[cfg (feature = "visit-mut" )] |
879 | #[cfg_attr (docsrs, doc(cfg(feature = "visit-mut" )))] |
880 | pub use crate::gen::visit_mut; |
881 | |
882 | // Not public API. |
883 | #[doc (hidden)] |
884 | #[path = "export.rs" ] |
885 | pub mod __private; |
886 | |
887 | /// Parse tokens of source code into the chosen syntax tree node. |
888 | /// |
889 | /// This is preferred over parsing a string because tokens are able to preserve |
890 | /// information about where in the user's code they were originally written (the |
891 | /// "span" of the token), possibly allowing the compiler to produce better error |
892 | /// messages. |
893 | /// |
894 | /// This function parses a `proc_macro::TokenStream` which is the type used for |
895 | /// interop with the compiler in a procedural macro. To parse a |
896 | /// `proc_macro2::TokenStream`, use [`syn::parse2`] instead. |
897 | /// |
898 | /// [`syn::parse2`]: parse2 |
899 | /// |
900 | /// This function enforces that the input is fully parsed. If there are any |
901 | /// unparsed tokens at the end of the stream, an error is returned. |
902 | #[cfg (all(feature = "parsing" , feature = "proc-macro" ))] |
903 | #[cfg_attr (docsrs, doc(cfg(all(feature = "parsing" , feature = "proc-macro" ))))] |
904 | pub fn parse<T: parse::Parse>(tokens: proc_macro::TokenStream) -> Result<T> { |
905 | parse::Parser::parse(T::parse, tokens) |
906 | } |
907 | |
908 | /// Parse a proc-macro2 token stream into the chosen syntax tree node. |
909 | /// |
910 | /// This function parses a `proc_macro2::TokenStream` which is commonly useful |
911 | /// when the input comes from a node of the Syn syntax tree, for example the |
912 | /// body tokens of a [`Macro`] node. When in a procedural macro parsing the |
913 | /// `proc_macro::TokenStream` provided by the compiler, use [`syn::parse`] |
914 | /// instead. |
915 | /// |
916 | /// [`syn::parse`]: parse() |
917 | /// |
918 | /// This function enforces that the input is fully parsed. If there are any |
919 | /// unparsed tokens at the end of the stream, an error is returned. |
920 | #[cfg (feature = "parsing" )] |
921 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
922 | pub fn parse2<T: parse::Parse>(tokens: proc_macro2::TokenStream) -> Result<T> { |
923 | parse::Parser::parse2(T::parse, tokens) |
924 | } |
925 | |
926 | /// Parse a string of Rust code into the chosen syntax tree node. |
927 | /// |
928 | /// This function enforces that the input is fully parsed. If there are any |
929 | /// unparsed tokens at the end of the stream, an error is returned. |
930 | /// |
931 | /// # Hygiene |
932 | /// |
933 | /// Every span in the resulting syntax tree will be set to resolve at the macro |
934 | /// call site. |
935 | /// |
936 | /// # Examples |
937 | /// |
938 | /// ``` |
939 | /// use syn::{Expr, Result}; |
940 | /// |
941 | /// fn run() -> Result<()> { |
942 | /// let code = "assert_eq!(u8::max_value(), 255)" ; |
943 | /// let expr = syn::parse_str::<Expr>(code)?; |
944 | /// println!("{:#?}" , expr); |
945 | /// Ok(()) |
946 | /// } |
947 | /// # |
948 | /// # run().unwrap(); |
949 | /// ``` |
950 | #[cfg (feature = "parsing" )] |
951 | #[cfg_attr (docsrs, doc(cfg(feature = "parsing" )))] |
952 | pub fn parse_str<T: parse::Parse>(s: &str) -> Result<T> { |
953 | parse::Parser::parse_str(T::parse, s) |
954 | } |
955 | |
956 | /// Parse the content of a file of Rust code. |
957 | /// |
958 | /// This is different from `syn::parse_str::<File>(content)` in two ways: |
959 | /// |
960 | /// - It discards a leading byte order mark `\u{FEFF}` if the file has one. |
961 | /// - It preserves the shebang line of the file, such as `#!/usr/bin/env rustx`. |
962 | /// |
963 | /// If present, either of these would be an error using `from_str`. |
964 | /// |
965 | /// # Examples |
966 | /// |
967 | /// ```no_run |
968 | /// use std::error::Error; |
969 | /// use std::fs; |
970 | /// use std::io::Read; |
971 | /// |
972 | /// fn run() -> Result<(), Box<dyn Error>> { |
973 | /// let content = fs::read_to_string("path/to/code.rs" )?; |
974 | /// let ast = syn::parse_file(&content)?; |
975 | /// if let Some(shebang) = ast.shebang { |
976 | /// println!("{}" , shebang); |
977 | /// } |
978 | /// println!("{} items" , ast.items.len()); |
979 | /// |
980 | /// Ok(()) |
981 | /// } |
982 | /// # |
983 | /// # run().unwrap(); |
984 | /// ``` |
985 | #[cfg (all(feature = "parsing" , feature = "full" ))] |
986 | #[cfg_attr (docsrs, doc(cfg(all(feature = "parsing" , feature = "full" ))))] |
987 | pub fn parse_file(mut content: &str) -> Result<File> { |
988 | // Strip the BOM if it is present |
989 | const BOM: &str = " \u{feff}" ; |
990 | if content.starts_with(BOM) { |
991 | content = &content[BOM.len()..]; |
992 | } |
993 | |
994 | let mut shebang = None; |
995 | if content.starts_with("#!" ) { |
996 | let rest = whitespace::skip(&content[2..]); |
997 | if !rest.starts_with('[' ) { |
998 | if let Some(idx) = content.find(' \n' ) { |
999 | shebang = Some(content[..idx].to_string()); |
1000 | content = &content[idx..]; |
1001 | } else { |
1002 | shebang = Some(content.to_string()); |
1003 | content = "" ; |
1004 | } |
1005 | } |
1006 | } |
1007 | |
1008 | let mut file: File = parse_str(content)?; |
1009 | file.shebang = shebang; |
1010 | Ok(file) |
1011 | } |
1012 | |