1*69942c0aSMiguel Ojeda // SPDX-License-Identifier: Apache-2.0 OR MIT
2*69942c0aSMiguel Ojeda
3808c999fSMiguel Ojeda //! [![github]](https://github.com/dtolnay/syn) [![crates-io]](https://crates.io/crates/syn) [![docs-rs]](crate)
4808c999fSMiguel Ojeda //!
5808c999fSMiguel Ojeda //! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
6808c999fSMiguel Ojeda //! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
7808c999fSMiguel Ojeda //! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
8808c999fSMiguel Ojeda //!
9808c999fSMiguel Ojeda //! <br>
10808c999fSMiguel Ojeda //!
11808c999fSMiguel Ojeda //! Syn is a parsing library for parsing a stream of Rust tokens into a syntax
12808c999fSMiguel Ojeda //! tree of Rust source code.
13808c999fSMiguel Ojeda //!
14808c999fSMiguel Ojeda //! Currently this library is geared toward use in Rust procedural macros, but
15808c999fSMiguel Ojeda //! contains some APIs that may be useful more generally.
16808c999fSMiguel Ojeda //!
17808c999fSMiguel Ojeda //! - **Data structures** — Syn provides a complete syntax tree that can
18808c999fSMiguel Ojeda //! represent any valid Rust source code. The syntax tree is rooted at
19808c999fSMiguel Ojeda //! [`syn::File`] which represents a full source file, but there are other
20808c999fSMiguel Ojeda //! entry points that may be useful to procedural macros including
21808c999fSMiguel Ojeda //! [`syn::Item`], [`syn::Expr`] and [`syn::Type`].
22808c999fSMiguel Ojeda //!
23808c999fSMiguel Ojeda //! - **Derives** — Of particular interest to derive macros is
24808c999fSMiguel Ojeda //! [`syn::DeriveInput`] which is any of the three legal input items to a
25808c999fSMiguel Ojeda //! derive macro. An example below shows using this type in a library that can
26808c999fSMiguel Ojeda //! derive implementations of a user-defined trait.
27808c999fSMiguel Ojeda //!
28808c999fSMiguel Ojeda //! - **Parsing** — Parsing in Syn is built around [parser functions] with the
29808c999fSMiguel Ojeda //! signature `fn(ParseStream) -> Result<T>`. Every syntax tree node defined
30808c999fSMiguel Ojeda //! by Syn is individually parsable and may be used as a building block for
31808c999fSMiguel Ojeda //! custom syntaxes, or you may dream up your own brand new syntax without
32808c999fSMiguel Ojeda //! involving any of our syntax tree types.
33808c999fSMiguel Ojeda //!
34808c999fSMiguel Ojeda //! - **Location information** — Every token parsed by Syn is associated with a
35808c999fSMiguel Ojeda //! `Span` that tracks line and column information back to the source of that
36808c999fSMiguel Ojeda //! token. These spans allow a procedural macro to display detailed error
37808c999fSMiguel Ojeda //! messages pointing to all the right places in the user's code. There is an
38808c999fSMiguel Ojeda //! example of this below.
39808c999fSMiguel Ojeda //!
40808c999fSMiguel Ojeda //! - **Feature flags** — Functionality is aggressively feature gated so your
41808c999fSMiguel Ojeda //! procedural macros enable only what they need, and do not pay in compile
42808c999fSMiguel Ojeda //! time for all the rest.
43808c999fSMiguel Ojeda //!
44808c999fSMiguel Ojeda //! [`syn::File`]: File
45808c999fSMiguel Ojeda //! [`syn::Item`]: Item
46808c999fSMiguel Ojeda //! [`syn::Expr`]: Expr
47808c999fSMiguel Ojeda //! [`syn::Type`]: Type
48808c999fSMiguel Ojeda //! [`syn::DeriveInput`]: DeriveInput
49808c999fSMiguel Ojeda //! [parser functions]: mod@parse
50808c999fSMiguel Ojeda //!
51808c999fSMiguel Ojeda //! <br>
52808c999fSMiguel Ojeda //!
53808c999fSMiguel Ojeda //! # Example of a derive macro
54808c999fSMiguel Ojeda //!
55808c999fSMiguel Ojeda //! The canonical derive macro using Syn looks like this. We write an ordinary
56808c999fSMiguel Ojeda //! Rust function tagged with a `proc_macro_derive` attribute and the name of
57808c999fSMiguel Ojeda //! the trait we are deriving. Any time that derive appears in the user's code,
58808c999fSMiguel Ojeda //! the Rust compiler passes their data structure as tokens into our macro. We
59808c999fSMiguel Ojeda //! get to execute arbitrary Rust code to figure out what to do with those
60808c999fSMiguel Ojeda //! tokens, then hand some tokens back to the compiler to compile into the
61808c999fSMiguel Ojeda //! user's crate.
62808c999fSMiguel Ojeda //!
63808c999fSMiguel Ojeda //! [`TokenStream`]: proc_macro::TokenStream
64808c999fSMiguel Ojeda //!
65808c999fSMiguel Ojeda //! ```toml
66808c999fSMiguel Ojeda //! [dependencies]
67808c999fSMiguel Ojeda //! syn = "2.0"
68808c999fSMiguel Ojeda //! quote = "1.0"
69808c999fSMiguel Ojeda //!
70808c999fSMiguel Ojeda //! [lib]
71808c999fSMiguel Ojeda //! proc-macro = true
72808c999fSMiguel Ojeda //! ```
73808c999fSMiguel Ojeda //!
74808c999fSMiguel Ojeda //! ```
75808c999fSMiguel Ojeda //! # extern crate proc_macro;
76808c999fSMiguel Ojeda //! #
77808c999fSMiguel Ojeda //! use proc_macro::TokenStream;
78808c999fSMiguel Ojeda //! use quote::quote;
79808c999fSMiguel Ojeda //! use syn::{parse_macro_input, DeriveInput};
80808c999fSMiguel Ojeda //!
81808c999fSMiguel Ojeda //! # const IGNORE_TOKENS: &str = stringify! {
82808c999fSMiguel Ojeda //! #[proc_macro_derive(MyMacro)]
83808c999fSMiguel Ojeda //! # };
84808c999fSMiguel Ojeda //! pub fn my_macro(input: TokenStream) -> TokenStream {
85808c999fSMiguel Ojeda //! // Parse the input tokens into a syntax tree
86808c999fSMiguel Ojeda //! let input = parse_macro_input!(input as DeriveInput);
87808c999fSMiguel Ojeda //!
88808c999fSMiguel Ojeda //! // Build the output, possibly using quasi-quotation
89808c999fSMiguel Ojeda //! let expanded = quote! {
90808c999fSMiguel Ojeda //! // ...
91808c999fSMiguel Ojeda //! };
92808c999fSMiguel Ojeda //!
93808c999fSMiguel Ojeda //! // Hand the output tokens back to the compiler
94808c999fSMiguel Ojeda //! TokenStream::from(expanded)
95808c999fSMiguel Ojeda //! }
96808c999fSMiguel Ojeda //! ```
97808c999fSMiguel Ojeda //!
98808c999fSMiguel Ojeda //! The [`heapsize`] example directory shows a complete working implementation
99808c999fSMiguel Ojeda //! of a derive macro. The example derives a `HeapSize` trait which computes an
100808c999fSMiguel Ojeda //! estimate of the amount of heap memory owned by a value.
101808c999fSMiguel Ojeda //!
102808c999fSMiguel Ojeda //! [`heapsize`]: https://github.com/dtolnay/syn/tree/master/examples/heapsize
103808c999fSMiguel Ojeda //!
104808c999fSMiguel Ojeda //! ```
105808c999fSMiguel Ojeda //! pub trait HeapSize {
106808c999fSMiguel Ojeda //! /// Total number of bytes of heap memory owned by `self`.
107808c999fSMiguel Ojeda //! fn heap_size_of_children(&self) -> usize;
108808c999fSMiguel Ojeda //! }
109808c999fSMiguel Ojeda //! ```
110808c999fSMiguel Ojeda //!
111808c999fSMiguel Ojeda //! The derive macro allows users to write `#[derive(HeapSize)]` on data
112808c999fSMiguel Ojeda //! structures in their program.
113808c999fSMiguel Ojeda //!
114808c999fSMiguel Ojeda //! ```
115808c999fSMiguel Ojeda //! # const IGNORE_TOKENS: &str = stringify! {
116808c999fSMiguel Ojeda //! #[derive(HeapSize)]
117808c999fSMiguel Ojeda //! # };
118808c999fSMiguel Ojeda //! struct Demo<'a, T: ?Sized> {
119808c999fSMiguel Ojeda //! a: Box<T>,
120808c999fSMiguel Ojeda //! b: u8,
121808c999fSMiguel Ojeda //! c: &'a str,
122808c999fSMiguel Ojeda //! d: String,
123808c999fSMiguel Ojeda //! }
124808c999fSMiguel Ojeda //! ```
125808c999fSMiguel Ojeda //!
126808c999fSMiguel Ojeda //! <p><br></p>
127808c999fSMiguel Ojeda //!
128808c999fSMiguel Ojeda //! # Spans and error reporting
129808c999fSMiguel Ojeda //!
130808c999fSMiguel Ojeda //! The token-based procedural macro API provides great control over where the
131808c999fSMiguel Ojeda //! compiler's error messages are displayed in user code. Consider the error the
132808c999fSMiguel Ojeda //! user sees if one of their field types does not implement `HeapSize`.
133808c999fSMiguel Ojeda //!
134808c999fSMiguel Ojeda //! ```
135808c999fSMiguel Ojeda //! # const IGNORE_TOKENS: &str = stringify! {
136808c999fSMiguel Ojeda //! #[derive(HeapSize)]
137808c999fSMiguel Ojeda //! # };
138808c999fSMiguel Ojeda //! struct Broken {
139808c999fSMiguel Ojeda //! ok: String,
140808c999fSMiguel Ojeda //! bad: std::thread::Thread,
141808c999fSMiguel Ojeda //! }
142808c999fSMiguel Ojeda //! ```
143808c999fSMiguel Ojeda //!
144808c999fSMiguel Ojeda //! By tracking span information all the way through the expansion of a
145808c999fSMiguel Ojeda //! procedural macro as shown in the `heapsize` example, token-based macros in
146808c999fSMiguel Ojeda //! Syn are able to trigger errors that directly pinpoint the source of the
147808c999fSMiguel Ojeda //! problem.
148808c999fSMiguel Ojeda //!
149808c999fSMiguel Ojeda //! ```text
150808c999fSMiguel Ojeda //! error[E0277]: the trait bound `std::thread::Thread: HeapSize` is not satisfied
151808c999fSMiguel Ojeda //! --> src/main.rs:7:5
152808c999fSMiguel Ojeda //! |
153808c999fSMiguel Ojeda //! 7 | bad: std::thread::Thread,
154808c999fSMiguel Ojeda //! | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HeapSize` is not implemented for `Thread`
155808c999fSMiguel Ojeda //! ```
156808c999fSMiguel Ojeda //!
157808c999fSMiguel Ojeda //! <br>
158808c999fSMiguel Ojeda //!
159808c999fSMiguel Ojeda //! # Parsing a custom syntax
160808c999fSMiguel Ojeda //!
161808c999fSMiguel Ojeda //! The [`lazy-static`] example directory shows the implementation of a
162808c999fSMiguel Ojeda //! `functionlike!(...)` procedural macro in which the input tokens are parsed
163808c999fSMiguel Ojeda //! using Syn's parsing API.
164808c999fSMiguel Ojeda //!
165808c999fSMiguel Ojeda //! [`lazy-static`]: https://github.com/dtolnay/syn/tree/master/examples/lazy-static
166808c999fSMiguel Ojeda //!
167808c999fSMiguel Ojeda //! The example reimplements the popular `lazy_static` crate from crates.io as a
168808c999fSMiguel Ojeda //! procedural macro.
169808c999fSMiguel Ojeda //!
170808c999fSMiguel Ojeda //! ```
171808c999fSMiguel Ojeda //! # macro_rules! lazy_static {
172808c999fSMiguel Ojeda //! # ($($tt:tt)*) => {}
173808c999fSMiguel Ojeda //! # }
174808c999fSMiguel Ojeda //! #
175808c999fSMiguel Ojeda //! lazy_static! {
176808c999fSMiguel Ojeda //! static ref USERNAME: Regex = Regex::new("^[a-z0-9_-]{3,16}$").unwrap();
177808c999fSMiguel Ojeda //! }
178808c999fSMiguel Ojeda //! ```
179808c999fSMiguel Ojeda //!
180808c999fSMiguel Ojeda //! The implementation shows how to trigger custom warnings and error messages
181808c999fSMiguel Ojeda //! on the macro input.
182808c999fSMiguel Ojeda //!
183808c999fSMiguel Ojeda //! ```text
184808c999fSMiguel Ojeda //! warning: come on, pick a more creative name
185808c999fSMiguel Ojeda //! --> src/main.rs:10:16
186808c999fSMiguel Ojeda //! |
187808c999fSMiguel Ojeda //! 10 | static ref FOO: String = "lazy_static".to_owned();
188808c999fSMiguel Ojeda //! | ^^^
189808c999fSMiguel Ojeda //! ```
190808c999fSMiguel Ojeda //!
191808c999fSMiguel Ojeda //! <br>
192808c999fSMiguel Ojeda //!
193808c999fSMiguel Ojeda //! # Testing
194808c999fSMiguel Ojeda //!
195808c999fSMiguel Ojeda //! When testing macros, we often care not just that the macro can be used
196808c999fSMiguel Ojeda //! successfully but also that when the macro is provided with invalid input it
197808c999fSMiguel Ojeda //! produces maximally helpful error messages. Consider using the [`trybuild`]
198808c999fSMiguel Ojeda //! crate to write tests for errors that are emitted by your macro or errors
199808c999fSMiguel Ojeda //! detected by the Rust compiler in the expanded code following misuse of the
200808c999fSMiguel Ojeda //! macro. Such tests help avoid regressions from later refactors that
201808c999fSMiguel Ojeda //! mistakenly make an error no longer trigger or be less helpful than it used
202808c999fSMiguel Ojeda //! to be.
203808c999fSMiguel Ojeda //!
204808c999fSMiguel Ojeda //! [`trybuild`]: https://github.com/dtolnay/trybuild
205808c999fSMiguel Ojeda //!
206808c999fSMiguel Ojeda //! <br>
207808c999fSMiguel Ojeda //!
208808c999fSMiguel Ojeda //! # Debugging
209808c999fSMiguel Ojeda //!
210808c999fSMiguel Ojeda //! When developing a procedural macro it can be helpful to look at what the
211808c999fSMiguel Ojeda //! generated code looks like. Use `cargo rustc -- -Zunstable-options
212808c999fSMiguel Ojeda //! --pretty=expanded` or the [`cargo expand`] subcommand.
213808c999fSMiguel Ojeda //!
214808c999fSMiguel Ojeda //! [`cargo expand`]: https://github.com/dtolnay/cargo-expand
215808c999fSMiguel Ojeda //!
216808c999fSMiguel Ojeda //! To show the expanded code for some crate that uses your procedural macro,
217808c999fSMiguel Ojeda //! run `cargo expand` from that crate. To show the expanded code for one of
218808c999fSMiguel Ojeda //! your own test cases, run `cargo expand --test the_test_case` where the last
219808c999fSMiguel Ojeda //! argument is the name of the test file without the `.rs` extension.
220808c999fSMiguel Ojeda //!
221808c999fSMiguel Ojeda //! This write-up by Brandon W Maister discusses debugging in more detail:
222808c999fSMiguel Ojeda //! [Debugging Rust's new Custom Derive system][debugging].
223808c999fSMiguel Ojeda //!
224808c999fSMiguel Ojeda //! [debugging]: https://quodlibetor.github.io/posts/debugging-rusts-new-custom-derive-system/
225808c999fSMiguel Ojeda //!
226808c999fSMiguel Ojeda //! <br>
227808c999fSMiguel Ojeda //!
228808c999fSMiguel Ojeda //! # Optional features
229808c999fSMiguel Ojeda //!
230808c999fSMiguel Ojeda //! Syn puts a lot of functionality behind optional features in order to
231808c999fSMiguel Ojeda //! optimize compile time for the most common use cases. The following features
232808c999fSMiguel Ojeda //! are available.
233808c999fSMiguel Ojeda //!
234808c999fSMiguel Ojeda //! - **`derive`** *(enabled by default)* — Data structures for representing the
235808c999fSMiguel Ojeda //! possible input to a derive macro, including structs and enums and types.
236808c999fSMiguel Ojeda //! - **`full`** — Data structures for representing the syntax tree of all valid
237808c999fSMiguel Ojeda //! Rust source code, including items and expressions.
238808c999fSMiguel Ojeda //! - **`parsing`** *(enabled by default)* — Ability to parse input tokens into
239808c999fSMiguel Ojeda //! a syntax tree node of a chosen type.
240808c999fSMiguel Ojeda //! - **`printing`** *(enabled by default)* — Ability to print a syntax tree
241808c999fSMiguel Ojeda //! node as tokens of Rust source code.
242808c999fSMiguel Ojeda //! - **`visit`** — Trait for traversing a syntax tree.
243808c999fSMiguel Ojeda //! - **`visit-mut`** — Trait for traversing and mutating in place a syntax
244808c999fSMiguel Ojeda //! tree.
245808c999fSMiguel Ojeda //! - **`fold`** — Trait for transforming an owned syntax tree.
246808c999fSMiguel Ojeda //! - **`clone-impls`** *(enabled by default)* — Clone impls for all syntax tree
247808c999fSMiguel Ojeda //! types.
248808c999fSMiguel Ojeda //! - **`extra-traits`** — Debug, Eq, PartialEq, Hash impls for all syntax tree
249808c999fSMiguel Ojeda //! types.
250808c999fSMiguel Ojeda //! - **`proc-macro`** *(enabled by default)* — Runtime dependency on the
251808c999fSMiguel Ojeda //! dynamic library libproc_macro from rustc toolchain.
252808c999fSMiguel Ojeda
253808c999fSMiguel Ojeda // Syn types in rustdoc of other crates get linked to here.
254808c999fSMiguel Ojeda #![doc(html_root_url = "https://docs.rs/syn/2.0.106")]
255808c999fSMiguel Ojeda #![cfg_attr(docsrs, feature(doc_cfg))]
256808c999fSMiguel Ojeda #![deny(unsafe_op_in_unsafe_fn)]
257808c999fSMiguel Ojeda #![allow(non_camel_case_types)]
258808c999fSMiguel Ojeda #![cfg_attr(not(check_cfg), allow(unexpected_cfgs))]
259808c999fSMiguel Ojeda #![allow(
260808c999fSMiguel Ojeda clippy::bool_to_int_with_if,
261808c999fSMiguel Ojeda clippy::cast_lossless,
262808c999fSMiguel Ojeda clippy::cast_possible_truncation,
263808c999fSMiguel Ojeda clippy::cast_possible_wrap,
264808c999fSMiguel Ojeda clippy::cast_ptr_alignment,
265808c999fSMiguel Ojeda clippy::default_trait_access,
266808c999fSMiguel Ojeda clippy::derivable_impls,
267808c999fSMiguel Ojeda clippy::diverging_sub_expression,
268808c999fSMiguel Ojeda clippy::doc_markdown,
269808c999fSMiguel Ojeda clippy::elidable_lifetime_names,
270808c999fSMiguel Ojeda clippy::enum_glob_use,
271808c999fSMiguel Ojeda clippy::expl_impl_clone_on_copy,
272808c999fSMiguel Ojeda clippy::explicit_auto_deref,
273808c999fSMiguel Ojeda clippy::fn_params_excessive_bools,
274808c999fSMiguel Ojeda clippy::if_not_else,
275808c999fSMiguel Ojeda clippy::inherent_to_string,
276808c999fSMiguel Ojeda clippy::into_iter_without_iter,
277808c999fSMiguel Ojeda clippy::items_after_statements,
278808c999fSMiguel Ojeda clippy::large_enum_variant,
279808c999fSMiguel Ojeda clippy::let_underscore_untyped, // https://github.com/rust-lang/rust-clippy/issues/10410
280808c999fSMiguel Ojeda clippy::manual_assert,
281808c999fSMiguel Ojeda clippy::manual_let_else,
282808c999fSMiguel Ojeda clippy::manual_map,
283808c999fSMiguel Ojeda clippy::match_like_matches_macro,
284808c999fSMiguel Ojeda clippy::match_same_arms,
285808c999fSMiguel Ojeda clippy::match_wildcard_for_single_variants, // clippy bug: https://github.com/rust-lang/rust-clippy/issues/6984
286808c999fSMiguel Ojeda clippy::missing_errors_doc,
287808c999fSMiguel Ojeda clippy::missing_panics_doc,
288808c999fSMiguel Ojeda clippy::module_name_repetitions,
289808c999fSMiguel Ojeda clippy::must_use_candidate,
290808c999fSMiguel Ojeda clippy::needless_doctest_main,
291808c999fSMiguel Ojeda clippy::needless_lifetimes,
292808c999fSMiguel Ojeda clippy::needless_pass_by_value,
293808c999fSMiguel Ojeda clippy::needless_update,
294808c999fSMiguel Ojeda clippy::never_loop,
295808c999fSMiguel Ojeda clippy::range_plus_one,
296808c999fSMiguel Ojeda clippy::redundant_else,
297808c999fSMiguel Ojeda clippy::ref_option,
298808c999fSMiguel Ojeda clippy::return_self_not_must_use,
299808c999fSMiguel Ojeda clippy::similar_names,
300808c999fSMiguel Ojeda clippy::single_match_else,
301808c999fSMiguel Ojeda clippy::struct_excessive_bools,
302808c999fSMiguel Ojeda clippy::too_many_arguments,
303808c999fSMiguel Ojeda clippy::too_many_lines,
304808c999fSMiguel Ojeda clippy::trivially_copy_pass_by_ref,
305808c999fSMiguel Ojeda clippy::unconditional_recursion, // https://github.com/rust-lang/rust-clippy/issues/12133
306808c999fSMiguel Ojeda clippy::uninhabited_references,
307808c999fSMiguel Ojeda clippy::uninlined_format_args,
308808c999fSMiguel Ojeda clippy::unnecessary_box_returns,
309808c999fSMiguel Ojeda clippy::unnecessary_unwrap,
310808c999fSMiguel Ojeda clippy::used_underscore_binding,
311808c999fSMiguel Ojeda clippy::wildcard_imports,
312808c999fSMiguel Ojeda )]
313808c999fSMiguel Ojeda #![allow(unknown_lints, mismatched_lifetime_syntaxes)]
314808c999fSMiguel Ojeda
315808c999fSMiguel Ojeda extern crate self as syn;
316808c999fSMiguel Ojeda
317808c999fSMiguel Ojeda #[cfg(feature = "proc-macro")]
318808c999fSMiguel Ojeda extern crate proc_macro;
319808c999fSMiguel Ojeda
320808c999fSMiguel Ojeda #[macro_use]
321808c999fSMiguel Ojeda mod macros;
322808c999fSMiguel Ojeda
323808c999fSMiguel Ojeda #[cfg(feature = "parsing")]
324808c999fSMiguel Ojeda #[macro_use]
325808c999fSMiguel Ojeda mod group;
326808c999fSMiguel Ojeda
327808c999fSMiguel Ojeda #[macro_use]
328808c999fSMiguel Ojeda pub mod token;
329808c999fSMiguel Ojeda
330808c999fSMiguel Ojeda #[cfg(any(feature = "full", feature = "derive"))]
331808c999fSMiguel Ojeda mod attr;
332808c999fSMiguel Ojeda #[cfg(any(feature = "full", feature = "derive"))]
333808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
334808c999fSMiguel Ojeda pub use crate::attr::{AttrStyle, Attribute, Meta, MetaList, MetaNameValue};
335808c999fSMiguel Ojeda
336808c999fSMiguel Ojeda mod bigint;
337808c999fSMiguel Ojeda
338808c999fSMiguel Ojeda #[cfg(feature = "parsing")]
339808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
340808c999fSMiguel Ojeda pub mod buffer;
341808c999fSMiguel Ojeda
342808c999fSMiguel Ojeda #[cfg(any(
343808c999fSMiguel Ojeda all(feature = "parsing", feature = "full"),
344808c999fSMiguel Ojeda all(feature = "printing", any(feature = "full", feature = "derive")),
345808c999fSMiguel Ojeda ))]
346808c999fSMiguel Ojeda mod classify;
347808c999fSMiguel Ojeda
348808c999fSMiguel Ojeda mod custom_keyword;
349808c999fSMiguel Ojeda
350808c999fSMiguel Ojeda mod custom_punctuation;
351808c999fSMiguel Ojeda
352808c999fSMiguel Ojeda #[cfg(any(feature = "full", feature = "derive"))]
353808c999fSMiguel Ojeda mod data;
354808c999fSMiguel Ojeda #[cfg(any(feature = "full", feature = "derive"))]
355808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
356808c999fSMiguel Ojeda pub use crate::data::{Field, Fields, FieldsNamed, FieldsUnnamed, Variant};
357808c999fSMiguel Ojeda
358808c999fSMiguel Ojeda #[cfg(any(feature = "full", feature = "derive"))]
359808c999fSMiguel Ojeda mod derive;
360808c999fSMiguel Ojeda #[cfg(feature = "derive")]
361808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
362808c999fSMiguel Ojeda pub use crate::derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput};
363808c999fSMiguel Ojeda
364808c999fSMiguel Ojeda mod drops;
365808c999fSMiguel Ojeda
366808c999fSMiguel Ojeda mod error;
367808c999fSMiguel Ojeda pub use crate::error::{Error, Result};
368808c999fSMiguel Ojeda
369808c999fSMiguel Ojeda #[cfg(any(feature = "full", feature = "derive"))]
370808c999fSMiguel Ojeda mod expr;
371808c999fSMiguel Ojeda #[cfg(feature = "full")]
372808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
373808c999fSMiguel Ojeda pub use crate::expr::{Arm, Label, PointerMutability, RangeLimits};
374808c999fSMiguel Ojeda #[cfg(any(feature = "full", feature = "derive"))]
375808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
376808c999fSMiguel Ojeda pub use crate::expr::{
377808c999fSMiguel Ojeda Expr, ExprBinary, ExprCall, ExprCast, ExprField, ExprIndex, ExprLit, ExprMacro, ExprMethodCall,
378808c999fSMiguel Ojeda ExprParen, ExprPath, ExprReference, ExprStruct, ExprUnary, FieldValue, Index, Member,
379808c999fSMiguel Ojeda };
380808c999fSMiguel Ojeda #[cfg(any(feature = "full", feature = "derive"))]
381808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
382808c999fSMiguel Ojeda pub use crate::expr::{
383808c999fSMiguel Ojeda ExprArray, ExprAssign, ExprAsync, ExprAwait, ExprBlock, ExprBreak, ExprClosure, ExprConst,
384808c999fSMiguel Ojeda ExprContinue, ExprForLoop, ExprGroup, ExprIf, ExprInfer, ExprLet, ExprLoop, ExprMatch,
385808c999fSMiguel Ojeda ExprRange, ExprRawAddr, ExprRepeat, ExprReturn, ExprTry, ExprTryBlock, ExprTuple, ExprUnsafe,
386808c999fSMiguel Ojeda ExprWhile, ExprYield,
387808c999fSMiguel Ojeda };
388808c999fSMiguel Ojeda
389808c999fSMiguel Ojeda #[cfg(feature = "parsing")]
390808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
391808c999fSMiguel Ojeda pub mod ext;
392808c999fSMiguel Ojeda
393808c999fSMiguel Ojeda #[cfg(feature = "full")]
394808c999fSMiguel Ojeda mod file;
395808c999fSMiguel Ojeda #[cfg(feature = "full")]
396808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
397808c999fSMiguel Ojeda pub use crate::file::File;
398808c999fSMiguel Ojeda
399808c999fSMiguel Ojeda #[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))]
400808c999fSMiguel Ojeda mod fixup;
401808c999fSMiguel Ojeda
402808c999fSMiguel Ojeda #[cfg(any(feature = "full", feature = "derive"))]
403808c999fSMiguel Ojeda mod generics;
404808c999fSMiguel Ojeda #[cfg(any(feature = "full", feature = "derive"))]
405808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
406808c999fSMiguel Ojeda pub use crate::generics::{
407808c999fSMiguel Ojeda BoundLifetimes, ConstParam, GenericParam, Generics, LifetimeParam, PredicateLifetime,
408808c999fSMiguel Ojeda PredicateType, TraitBound, TraitBoundModifier, TypeParam, TypeParamBound, WhereClause,
409808c999fSMiguel Ojeda WherePredicate,
410808c999fSMiguel Ojeda };
411808c999fSMiguel Ojeda #[cfg(feature = "full")]
412808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
413808c999fSMiguel Ojeda pub use crate::generics::{CapturedParam, PreciseCapture};
414808c999fSMiguel Ojeda #[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))]
415808c999fSMiguel Ojeda #[cfg_attr(
416808c999fSMiguel Ojeda docsrs,
417808c999fSMiguel Ojeda doc(cfg(all(any(feature = "full", feature = "derive"), feature = "printing")))
418808c999fSMiguel Ojeda )]
419808c999fSMiguel Ojeda pub use crate::generics::{ImplGenerics, Turbofish, TypeGenerics};
420808c999fSMiguel Ojeda
421808c999fSMiguel Ojeda mod ident;
422808c999fSMiguel Ojeda #[doc(inline)]
423808c999fSMiguel Ojeda pub use crate::ident::Ident;
424808c999fSMiguel Ojeda
425808c999fSMiguel Ojeda #[cfg(feature = "full")]
426808c999fSMiguel Ojeda mod item;
427808c999fSMiguel Ojeda #[cfg(feature = "full")]
428808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
429808c999fSMiguel Ojeda pub use crate::item::{
430808c999fSMiguel Ojeda FnArg, ForeignItem, ForeignItemFn, ForeignItemMacro, ForeignItemStatic, ForeignItemType,
431808c999fSMiguel Ojeda ImplItem, ImplItemConst, ImplItemFn, ImplItemMacro, ImplItemType, ImplRestriction, Item,
432808c999fSMiguel Ojeda ItemConst, ItemEnum, ItemExternCrate, ItemFn, ItemForeignMod, ItemImpl, ItemMacro, ItemMod,
433808c999fSMiguel Ojeda ItemStatic, ItemStruct, ItemTrait, ItemTraitAlias, ItemType, ItemUnion, ItemUse, Receiver,
434808c999fSMiguel Ojeda Signature, StaticMutability, TraitItem, TraitItemConst, TraitItemFn, TraitItemMacro,
435808c999fSMiguel Ojeda TraitItemType, UseGlob, UseGroup, UseName, UsePath, UseRename, UseTree, Variadic,
436808c999fSMiguel Ojeda };
437808c999fSMiguel Ojeda
438808c999fSMiguel Ojeda mod lifetime;
439808c999fSMiguel Ojeda #[doc(inline)]
440808c999fSMiguel Ojeda pub use crate::lifetime::Lifetime;
441808c999fSMiguel Ojeda
442808c999fSMiguel Ojeda mod lit;
443808c999fSMiguel Ojeda #[doc(hidden)] // https://github.com/dtolnay/syn/issues/1566
444808c999fSMiguel Ojeda pub use crate::lit::StrStyle;
445808c999fSMiguel Ojeda #[doc(inline)]
446808c999fSMiguel Ojeda pub use crate::lit::{
447808c999fSMiguel Ojeda Lit, LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitInt, LitStr,
448808c999fSMiguel Ojeda };
449808c999fSMiguel Ojeda
450808c999fSMiguel Ojeda #[cfg(feature = "parsing")]
451808c999fSMiguel Ojeda mod lookahead;
452808c999fSMiguel Ojeda
453808c999fSMiguel Ojeda #[cfg(any(feature = "full", feature = "derive"))]
454808c999fSMiguel Ojeda mod mac;
455808c999fSMiguel Ojeda #[cfg(any(feature = "full", feature = "derive"))]
456808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
457808c999fSMiguel Ojeda pub use crate::mac::{Macro, MacroDelimiter};
458808c999fSMiguel Ojeda
459808c999fSMiguel Ojeda #[cfg(all(feature = "parsing", any(feature = "full", feature = "derive")))]
460808c999fSMiguel Ojeda #[cfg_attr(
461808c999fSMiguel Ojeda docsrs,
462808c999fSMiguel Ojeda doc(cfg(all(feature = "parsing", any(feature = "full", feature = "derive"))))
463808c999fSMiguel Ojeda )]
464808c999fSMiguel Ojeda pub mod meta;
465808c999fSMiguel Ojeda
466808c999fSMiguel Ojeda #[cfg(any(feature = "full", feature = "derive"))]
467808c999fSMiguel Ojeda mod op;
468808c999fSMiguel Ojeda #[cfg(any(feature = "full", feature = "derive"))]
469808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
470808c999fSMiguel Ojeda pub use crate::op::{BinOp, UnOp};
471808c999fSMiguel Ojeda
472808c999fSMiguel Ojeda #[cfg(feature = "parsing")]
473808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
474808c999fSMiguel Ojeda pub mod parse;
475808c999fSMiguel Ojeda
476808c999fSMiguel Ojeda #[cfg(all(feature = "parsing", feature = "proc-macro"))]
477808c999fSMiguel Ojeda mod parse_macro_input;
478808c999fSMiguel Ojeda
479808c999fSMiguel Ojeda #[cfg(all(feature = "parsing", feature = "printing"))]
480808c999fSMiguel Ojeda mod parse_quote;
481808c999fSMiguel Ojeda
482808c999fSMiguel Ojeda #[cfg(feature = "full")]
483808c999fSMiguel Ojeda mod pat;
484808c999fSMiguel Ojeda #[cfg(feature = "full")]
485808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
486808c999fSMiguel Ojeda pub use crate::pat::{
487808c999fSMiguel Ojeda FieldPat, Pat, PatConst, PatIdent, PatLit, PatMacro, PatOr, PatParen, PatPath, PatRange,
488808c999fSMiguel Ojeda PatReference, PatRest, PatSlice, PatStruct, PatTuple, PatTupleStruct, PatType, PatWild,
489808c999fSMiguel Ojeda };
490808c999fSMiguel Ojeda
491808c999fSMiguel Ojeda #[cfg(any(feature = "full", feature = "derive"))]
492808c999fSMiguel Ojeda mod path;
493808c999fSMiguel Ojeda #[cfg(any(feature = "full", feature = "derive"))]
494808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
495808c999fSMiguel Ojeda pub use crate::path::{
496808c999fSMiguel Ojeda AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, GenericArgument,
497808c999fSMiguel Ojeda ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf,
498808c999fSMiguel Ojeda };
499808c999fSMiguel Ojeda
500808c999fSMiguel Ojeda #[cfg(all(
501808c999fSMiguel Ojeda any(feature = "full", feature = "derive"),
502808c999fSMiguel Ojeda any(feature = "parsing", feature = "printing")
503808c999fSMiguel Ojeda ))]
504808c999fSMiguel Ojeda mod precedence;
505808c999fSMiguel Ojeda
506808c999fSMiguel Ojeda #[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))]
507808c999fSMiguel Ojeda mod print;
508808c999fSMiguel Ojeda
509808c999fSMiguel Ojeda pub mod punctuated;
510808c999fSMiguel Ojeda
511808c999fSMiguel Ojeda #[cfg(any(feature = "full", feature = "derive"))]
512808c999fSMiguel Ojeda mod restriction;
513808c999fSMiguel Ojeda #[cfg(any(feature = "full", feature = "derive"))]
514808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
515808c999fSMiguel Ojeda pub use crate::restriction::{FieldMutability, VisRestricted, Visibility};
516808c999fSMiguel Ojeda
517808c999fSMiguel Ojeda mod sealed;
518808c999fSMiguel Ojeda
519808c999fSMiguel Ojeda #[cfg(all(feature = "parsing", feature = "derive", not(feature = "full")))]
520808c999fSMiguel Ojeda mod scan_expr;
521808c999fSMiguel Ojeda
522808c999fSMiguel Ojeda mod span;
523808c999fSMiguel Ojeda
524808c999fSMiguel Ojeda #[cfg(all(feature = "parsing", feature = "printing"))]
525808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))]
526808c999fSMiguel Ojeda pub mod spanned;
527808c999fSMiguel Ojeda
528808c999fSMiguel Ojeda #[cfg(feature = "full")]
529808c999fSMiguel Ojeda mod stmt;
530808c999fSMiguel Ojeda #[cfg(feature = "full")]
531808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
532808c999fSMiguel Ojeda pub use crate::stmt::{Block, Local, LocalInit, Stmt, StmtMacro};
533808c999fSMiguel Ojeda
534808c999fSMiguel Ojeda mod thread;
535808c999fSMiguel Ojeda
536808c999fSMiguel Ojeda #[cfg(all(any(feature = "full", feature = "derive"), feature = "extra-traits"))]
537808c999fSMiguel Ojeda mod tt;
538808c999fSMiguel Ojeda
539808c999fSMiguel Ojeda #[cfg(any(feature = "full", feature = "derive"))]
540808c999fSMiguel Ojeda mod ty;
541808c999fSMiguel Ojeda #[cfg(any(feature = "full", feature = "derive"))]
542808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
543808c999fSMiguel Ojeda pub use crate::ty::{
544808c999fSMiguel Ojeda Abi, BareFnArg, BareVariadic, ReturnType, Type, TypeArray, TypeBareFn, TypeGroup,
545808c999fSMiguel Ojeda TypeImplTrait, TypeInfer, TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, TypeReference,
546808c999fSMiguel Ojeda TypeSlice, TypeTraitObject, TypeTuple,
547808c999fSMiguel Ojeda };
548808c999fSMiguel Ojeda
549808c999fSMiguel Ojeda #[cfg(all(any(feature = "full", feature = "derive"), feature = "parsing"))]
550808c999fSMiguel Ojeda mod verbatim;
551808c999fSMiguel Ojeda
552808c999fSMiguel Ojeda #[cfg(all(feature = "parsing", feature = "full"))]
553808c999fSMiguel Ojeda mod whitespace;
554808c999fSMiguel Ojeda
555808c999fSMiguel Ojeda #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/6176
556808c999fSMiguel Ojeda mod gen {
557808c999fSMiguel Ojeda /// Syntax tree traversal to transform the nodes of an owned syntax tree.
558808c999fSMiguel Ojeda ///
559808c999fSMiguel Ojeda /// Each method of the [`Fold`] trait is a hook that can be overridden to
560808c999fSMiguel Ojeda /// customize the behavior when transforming the corresponding type of node.
561808c999fSMiguel Ojeda /// By default, every method recursively visits the substructure of the
562808c999fSMiguel Ojeda /// input by invoking the right visitor method of each of its fields.
563808c999fSMiguel Ojeda ///
564808c999fSMiguel Ojeda /// [`Fold`]: fold::Fold
565808c999fSMiguel Ojeda ///
566808c999fSMiguel Ojeda /// ```
567808c999fSMiguel Ojeda /// # use syn::{Attribute, BinOp, Expr, ExprBinary};
568808c999fSMiguel Ojeda /// #
569808c999fSMiguel Ojeda /// pub trait Fold {
570808c999fSMiguel Ojeda /// /* ... */
571808c999fSMiguel Ojeda ///
572808c999fSMiguel Ojeda /// fn fold_expr_binary(&mut self, node: ExprBinary) -> ExprBinary {
573808c999fSMiguel Ojeda /// fold_expr_binary(self, node)
574808c999fSMiguel Ojeda /// }
575808c999fSMiguel Ojeda ///
576808c999fSMiguel Ojeda /// /* ... */
577808c999fSMiguel Ojeda /// # fn fold_attribute(&mut self, node: Attribute) -> Attribute;
578808c999fSMiguel Ojeda /// # fn fold_expr(&mut self, node: Expr) -> Expr;
579808c999fSMiguel Ojeda /// # fn fold_bin_op(&mut self, node: BinOp) -> BinOp;
580808c999fSMiguel Ojeda /// }
581808c999fSMiguel Ojeda ///
582808c999fSMiguel Ojeda /// pub fn fold_expr_binary<V>(v: &mut V, node: ExprBinary) -> ExprBinary
583808c999fSMiguel Ojeda /// where
584808c999fSMiguel Ojeda /// V: Fold + ?Sized,
585808c999fSMiguel Ojeda /// {
586808c999fSMiguel Ojeda /// ExprBinary {
587808c999fSMiguel Ojeda /// attrs: node
588808c999fSMiguel Ojeda /// .attrs
589808c999fSMiguel Ojeda /// .into_iter()
590808c999fSMiguel Ojeda /// .map(|attr| v.fold_attribute(attr))
591808c999fSMiguel Ojeda /// .collect(),
592808c999fSMiguel Ojeda /// left: Box::new(v.fold_expr(*node.left)),
593808c999fSMiguel Ojeda /// op: v.fold_bin_op(node.op),
594808c999fSMiguel Ojeda /// right: Box::new(v.fold_expr(*node.right)),
595808c999fSMiguel Ojeda /// }
596808c999fSMiguel Ojeda /// }
597808c999fSMiguel Ojeda ///
598808c999fSMiguel Ojeda /// /* ... */
599808c999fSMiguel Ojeda /// ```
600808c999fSMiguel Ojeda ///
601808c999fSMiguel Ojeda /// <br>
602808c999fSMiguel Ojeda ///
603808c999fSMiguel Ojeda /// # Example
604808c999fSMiguel Ojeda ///
605808c999fSMiguel Ojeda /// This fold inserts parentheses to fully parenthesizes any expression.
606808c999fSMiguel Ojeda ///
607808c999fSMiguel Ojeda /// ```
608808c999fSMiguel Ojeda /// // [dependencies]
609808c999fSMiguel Ojeda /// // quote = "1.0"
610808c999fSMiguel Ojeda /// // syn = { version = "2.0", features = ["fold", "full"] }
611808c999fSMiguel Ojeda ///
612808c999fSMiguel Ojeda /// use quote::quote;
613808c999fSMiguel Ojeda /// use syn::fold::{fold_expr, Fold};
614808c999fSMiguel Ojeda /// use syn::{token, Expr, ExprParen};
615808c999fSMiguel Ojeda ///
616808c999fSMiguel Ojeda /// struct ParenthesizeEveryExpr;
617808c999fSMiguel Ojeda ///
618808c999fSMiguel Ojeda /// impl Fold for ParenthesizeEveryExpr {
619808c999fSMiguel Ojeda /// fn fold_expr(&mut self, expr: Expr) -> Expr {
620808c999fSMiguel Ojeda /// Expr::Paren(ExprParen {
621808c999fSMiguel Ojeda /// attrs: Vec::new(),
622808c999fSMiguel Ojeda /// expr: Box::new(fold_expr(self, expr)),
623808c999fSMiguel Ojeda /// paren_token: token::Paren::default(),
624808c999fSMiguel Ojeda /// })
625808c999fSMiguel Ojeda /// }
626808c999fSMiguel Ojeda /// }
627808c999fSMiguel Ojeda ///
628808c999fSMiguel Ojeda /// fn main() {
629808c999fSMiguel Ojeda /// let code = quote! { a() + b(1) * c.d };
630808c999fSMiguel Ojeda /// let expr: Expr = syn::parse2(code).unwrap();
631808c999fSMiguel Ojeda /// let parenthesized = ParenthesizeEveryExpr.fold_expr(expr);
632808c999fSMiguel Ojeda /// println!("{}", quote!(#parenthesized));
633808c999fSMiguel Ojeda ///
634808c999fSMiguel Ojeda /// // Output: (((a)()) + (((b)((1))) * ((c).d)))
635808c999fSMiguel Ojeda /// }
636808c999fSMiguel Ojeda /// ```
637808c999fSMiguel Ojeda #[cfg(feature = "fold")]
638808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "fold")))]
639808c999fSMiguel Ojeda #[rustfmt::skip]
640808c999fSMiguel Ojeda pub mod fold;
641808c999fSMiguel Ojeda
642808c999fSMiguel Ojeda /// Syntax tree traversal to walk a shared borrow of a syntax tree.
643808c999fSMiguel Ojeda ///
644808c999fSMiguel Ojeda /// Each method of the [`Visit`] trait is a hook that can be overridden to
645808c999fSMiguel Ojeda /// customize the behavior when visiting the corresponding type of node. By
646808c999fSMiguel Ojeda /// default, every method recursively visits the substructure of the input
647808c999fSMiguel Ojeda /// by invoking the right visitor method of each of its fields.
648808c999fSMiguel Ojeda ///
649808c999fSMiguel Ojeda /// [`Visit`]: visit::Visit
650808c999fSMiguel Ojeda ///
651808c999fSMiguel Ojeda /// ```
652808c999fSMiguel Ojeda /// # use syn::{Attribute, BinOp, Expr, ExprBinary};
653808c999fSMiguel Ojeda /// #
654808c999fSMiguel Ojeda /// pub trait Visit<'ast> {
655808c999fSMiguel Ojeda /// /* ... */
656808c999fSMiguel Ojeda ///
657808c999fSMiguel Ojeda /// fn visit_expr_binary(&mut self, node: &'ast ExprBinary) {
658808c999fSMiguel Ojeda /// visit_expr_binary(self, node);
659808c999fSMiguel Ojeda /// }
660808c999fSMiguel Ojeda ///
661808c999fSMiguel Ojeda /// /* ... */
662808c999fSMiguel Ojeda /// # fn visit_attribute(&mut self, node: &'ast Attribute);
663808c999fSMiguel Ojeda /// # fn visit_expr(&mut self, node: &'ast Expr);
664808c999fSMiguel Ojeda /// # fn visit_bin_op(&mut self, node: &'ast BinOp);
665808c999fSMiguel Ojeda /// }
666808c999fSMiguel Ojeda ///
667808c999fSMiguel Ojeda /// pub fn visit_expr_binary<'ast, V>(v: &mut V, node: &'ast ExprBinary)
668808c999fSMiguel Ojeda /// where
669808c999fSMiguel Ojeda /// V: Visit<'ast> + ?Sized,
670808c999fSMiguel Ojeda /// {
671808c999fSMiguel Ojeda /// for attr in &node.attrs {
672808c999fSMiguel Ojeda /// v.visit_attribute(attr);
673808c999fSMiguel Ojeda /// }
674808c999fSMiguel Ojeda /// v.visit_expr(&*node.left);
675808c999fSMiguel Ojeda /// v.visit_bin_op(&node.op);
676808c999fSMiguel Ojeda /// v.visit_expr(&*node.right);
677808c999fSMiguel Ojeda /// }
678808c999fSMiguel Ojeda ///
679808c999fSMiguel Ojeda /// /* ... */
680808c999fSMiguel Ojeda /// ```
681808c999fSMiguel Ojeda ///
682808c999fSMiguel Ojeda /// <br>
683808c999fSMiguel Ojeda ///
684808c999fSMiguel Ojeda /// # Example
685808c999fSMiguel Ojeda ///
686808c999fSMiguel Ojeda /// This visitor will print the name of every freestanding function in the
687808c999fSMiguel Ojeda /// syntax tree, including nested functions.
688808c999fSMiguel Ojeda ///
689808c999fSMiguel Ojeda /// ```
690808c999fSMiguel Ojeda /// // [dependencies]
691808c999fSMiguel Ojeda /// // quote = "1.0"
692808c999fSMiguel Ojeda /// // syn = { version = "2.0", features = ["full", "visit"] }
693808c999fSMiguel Ojeda ///
694808c999fSMiguel Ojeda /// use quote::quote;
695808c999fSMiguel Ojeda /// use syn::visit::{self, Visit};
696808c999fSMiguel Ojeda /// use syn::{File, ItemFn};
697808c999fSMiguel Ojeda ///
698808c999fSMiguel Ojeda /// struct FnVisitor;
699808c999fSMiguel Ojeda ///
700808c999fSMiguel Ojeda /// impl<'ast> Visit<'ast> for FnVisitor {
701808c999fSMiguel Ojeda /// fn visit_item_fn(&mut self, node: &'ast ItemFn) {
702808c999fSMiguel Ojeda /// println!("Function with name={}", node.sig.ident);
703808c999fSMiguel Ojeda ///
704808c999fSMiguel Ojeda /// // Delegate to the default impl to visit any nested functions.
705808c999fSMiguel Ojeda /// visit::visit_item_fn(self, node);
706808c999fSMiguel Ojeda /// }
707808c999fSMiguel Ojeda /// }
708808c999fSMiguel Ojeda ///
709808c999fSMiguel Ojeda /// fn main() {
710808c999fSMiguel Ojeda /// let code = quote! {
711808c999fSMiguel Ojeda /// pub fn f() {
712808c999fSMiguel Ojeda /// fn g() {}
713808c999fSMiguel Ojeda /// }
714808c999fSMiguel Ojeda /// };
715808c999fSMiguel Ojeda ///
716808c999fSMiguel Ojeda /// let syntax_tree: File = syn::parse2(code).unwrap();
717808c999fSMiguel Ojeda /// FnVisitor.visit_file(&syntax_tree);
718808c999fSMiguel Ojeda /// }
719808c999fSMiguel Ojeda /// ```
720808c999fSMiguel Ojeda ///
721808c999fSMiguel Ojeda /// The `'ast` lifetime on the input references means that the syntax tree
722808c999fSMiguel Ojeda /// outlives the complete recursive visit call, so the visitor is allowed to
723808c999fSMiguel Ojeda /// hold on to references into the syntax tree.
724808c999fSMiguel Ojeda ///
725808c999fSMiguel Ojeda /// ```
726808c999fSMiguel Ojeda /// use quote::quote;
727808c999fSMiguel Ojeda /// use syn::visit::{self, Visit};
728808c999fSMiguel Ojeda /// use syn::{File, ItemFn};
729808c999fSMiguel Ojeda ///
730808c999fSMiguel Ojeda /// struct FnVisitor<'ast> {
731808c999fSMiguel Ojeda /// functions: Vec<&'ast ItemFn>,
732808c999fSMiguel Ojeda /// }
733808c999fSMiguel Ojeda ///
734808c999fSMiguel Ojeda /// impl<'ast> Visit<'ast> for FnVisitor<'ast> {
735808c999fSMiguel Ojeda /// fn visit_item_fn(&mut self, node: &'ast ItemFn) {
736808c999fSMiguel Ojeda /// self.functions.push(node);
737808c999fSMiguel Ojeda /// visit::visit_item_fn(self, node);
738808c999fSMiguel Ojeda /// }
739808c999fSMiguel Ojeda /// }
740808c999fSMiguel Ojeda ///
741808c999fSMiguel Ojeda /// fn main() {
742808c999fSMiguel Ojeda /// let code = quote! {
743808c999fSMiguel Ojeda /// pub fn f() {
744808c999fSMiguel Ojeda /// fn g() {}
745808c999fSMiguel Ojeda /// }
746808c999fSMiguel Ojeda /// };
747808c999fSMiguel Ojeda ///
748808c999fSMiguel Ojeda /// let syntax_tree: File = syn::parse2(code).unwrap();
749808c999fSMiguel Ojeda /// let mut visitor = FnVisitor { functions: Vec::new() };
750808c999fSMiguel Ojeda /// visitor.visit_file(&syntax_tree);
751808c999fSMiguel Ojeda /// for f in visitor.functions {
752808c999fSMiguel Ojeda /// println!("Function with name={}", f.sig.ident);
753808c999fSMiguel Ojeda /// }
754808c999fSMiguel Ojeda /// }
755808c999fSMiguel Ojeda /// ```
756808c999fSMiguel Ojeda #[cfg(feature = "visit")]
757808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "visit")))]
758808c999fSMiguel Ojeda #[rustfmt::skip]
759808c999fSMiguel Ojeda pub mod visit;
760808c999fSMiguel Ojeda
761808c999fSMiguel Ojeda /// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in
762808c999fSMiguel Ojeda /// place.
763808c999fSMiguel Ojeda ///
764808c999fSMiguel Ojeda /// Each method of the [`VisitMut`] trait is a hook that can be overridden
765808c999fSMiguel Ojeda /// to customize the behavior when mutating the corresponding type of node.
766808c999fSMiguel Ojeda /// By default, every method recursively visits the substructure of the
767808c999fSMiguel Ojeda /// input by invoking the right visitor method of each of its fields.
768808c999fSMiguel Ojeda ///
769808c999fSMiguel Ojeda /// [`VisitMut`]: visit_mut::VisitMut
770808c999fSMiguel Ojeda ///
771808c999fSMiguel Ojeda /// ```
772808c999fSMiguel Ojeda /// # use syn::{Attribute, BinOp, Expr, ExprBinary};
773808c999fSMiguel Ojeda /// #
774808c999fSMiguel Ojeda /// pub trait VisitMut {
775808c999fSMiguel Ojeda /// /* ... */
776808c999fSMiguel Ojeda ///
777808c999fSMiguel Ojeda /// fn visit_expr_binary_mut(&mut self, node: &mut ExprBinary) {
778808c999fSMiguel Ojeda /// visit_expr_binary_mut(self, node);
779808c999fSMiguel Ojeda /// }
780808c999fSMiguel Ojeda ///
781808c999fSMiguel Ojeda /// /* ... */
782808c999fSMiguel Ojeda /// # fn visit_attribute_mut(&mut self, node: &mut Attribute);
783808c999fSMiguel Ojeda /// # fn visit_expr_mut(&mut self, node: &mut Expr);
784808c999fSMiguel Ojeda /// # fn visit_bin_op_mut(&mut self, node: &mut BinOp);
785808c999fSMiguel Ojeda /// }
786808c999fSMiguel Ojeda ///
787808c999fSMiguel Ojeda /// pub fn visit_expr_binary_mut<V>(v: &mut V, node: &mut ExprBinary)
788808c999fSMiguel Ojeda /// where
789808c999fSMiguel Ojeda /// V: VisitMut + ?Sized,
790808c999fSMiguel Ojeda /// {
791808c999fSMiguel Ojeda /// for attr in &mut node.attrs {
792808c999fSMiguel Ojeda /// v.visit_attribute_mut(attr);
793808c999fSMiguel Ojeda /// }
794808c999fSMiguel Ojeda /// v.visit_expr_mut(&mut *node.left);
795808c999fSMiguel Ojeda /// v.visit_bin_op_mut(&mut node.op);
796808c999fSMiguel Ojeda /// v.visit_expr_mut(&mut *node.right);
797808c999fSMiguel Ojeda /// }
798808c999fSMiguel Ojeda ///
799808c999fSMiguel Ojeda /// /* ... */
800808c999fSMiguel Ojeda /// ```
801808c999fSMiguel Ojeda ///
802808c999fSMiguel Ojeda /// <br>
803808c999fSMiguel Ojeda ///
804808c999fSMiguel Ojeda /// # Example
805808c999fSMiguel Ojeda ///
806808c999fSMiguel Ojeda /// This mut visitor replace occurrences of u256 suffixed integer literals
807808c999fSMiguel Ojeda /// like `999u256` with a macro invocation `bigint::u256!(999)`.
808808c999fSMiguel Ojeda ///
809808c999fSMiguel Ojeda /// ```
810808c999fSMiguel Ojeda /// // [dependencies]
811808c999fSMiguel Ojeda /// // quote = "1.0"
812808c999fSMiguel Ojeda /// // syn = { version = "2.0", features = ["full", "visit-mut"] }
813808c999fSMiguel Ojeda ///
814808c999fSMiguel Ojeda /// use quote::quote;
815808c999fSMiguel Ojeda /// use syn::visit_mut::{self, VisitMut};
816808c999fSMiguel Ojeda /// use syn::{parse_quote, Expr, File, Lit, LitInt};
817808c999fSMiguel Ojeda ///
818808c999fSMiguel Ojeda /// struct BigintReplace;
819808c999fSMiguel Ojeda ///
820808c999fSMiguel Ojeda /// impl VisitMut for BigintReplace {
821808c999fSMiguel Ojeda /// fn visit_expr_mut(&mut self, node: &mut Expr) {
822808c999fSMiguel Ojeda /// if let Expr::Lit(expr) = &node {
823808c999fSMiguel Ojeda /// if let Lit::Int(int) = &expr.lit {
824808c999fSMiguel Ojeda /// if int.suffix() == "u256" {
825808c999fSMiguel Ojeda /// let digits = int.base10_digits();
826808c999fSMiguel Ojeda /// let unsuffixed: LitInt = syn::parse_str(digits).unwrap();
827808c999fSMiguel Ojeda /// *node = parse_quote!(bigint::u256!(#unsuffixed));
828808c999fSMiguel Ojeda /// return;
829808c999fSMiguel Ojeda /// }
830808c999fSMiguel Ojeda /// }
831808c999fSMiguel Ojeda /// }
832808c999fSMiguel Ojeda ///
833808c999fSMiguel Ojeda /// // Delegate to the default impl to visit nested expressions.
834808c999fSMiguel Ojeda /// visit_mut::visit_expr_mut(self, node);
835808c999fSMiguel Ojeda /// }
836808c999fSMiguel Ojeda /// }
837808c999fSMiguel Ojeda ///
838808c999fSMiguel Ojeda /// fn main() {
839808c999fSMiguel Ojeda /// let code = quote! {
840808c999fSMiguel Ojeda /// fn main() {
841808c999fSMiguel Ojeda /// let _ = 999u256;
842808c999fSMiguel Ojeda /// }
843808c999fSMiguel Ojeda /// };
844808c999fSMiguel Ojeda ///
845808c999fSMiguel Ojeda /// let mut syntax_tree: File = syn::parse2(code).unwrap();
846808c999fSMiguel Ojeda /// BigintReplace.visit_file_mut(&mut syntax_tree);
847808c999fSMiguel Ojeda /// println!("{}", quote!(#syntax_tree));
848808c999fSMiguel Ojeda /// }
849808c999fSMiguel Ojeda /// ```
850808c999fSMiguel Ojeda #[cfg(feature = "visit-mut")]
851808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "visit-mut")))]
852808c999fSMiguel Ojeda #[rustfmt::skip]
853808c999fSMiguel Ojeda pub mod visit_mut;
854808c999fSMiguel Ojeda
855808c999fSMiguel Ojeda #[cfg(feature = "clone-impls")]
856808c999fSMiguel Ojeda #[rustfmt::skip]
857808c999fSMiguel Ojeda mod clone;
858808c999fSMiguel Ojeda
859808c999fSMiguel Ojeda #[cfg(feature = "extra-traits")]
860808c999fSMiguel Ojeda #[rustfmt::skip]
861808c999fSMiguel Ojeda mod debug;
862808c999fSMiguel Ojeda
863808c999fSMiguel Ojeda #[cfg(feature = "extra-traits")]
864808c999fSMiguel Ojeda #[rustfmt::skip]
865808c999fSMiguel Ojeda mod eq;
866808c999fSMiguel Ojeda
867808c999fSMiguel Ojeda #[cfg(feature = "extra-traits")]
868808c999fSMiguel Ojeda #[rustfmt::skip]
869808c999fSMiguel Ojeda mod hash;
870808c999fSMiguel Ojeda }
871808c999fSMiguel Ojeda
872808c999fSMiguel Ojeda #[cfg(feature = "fold")]
873808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "fold")))]
874808c999fSMiguel Ojeda pub use crate::gen::fold;
875808c999fSMiguel Ojeda
876808c999fSMiguel Ojeda #[cfg(feature = "visit")]
877808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "visit")))]
878808c999fSMiguel Ojeda pub use crate::gen::visit;
879808c999fSMiguel Ojeda
880808c999fSMiguel Ojeda #[cfg(feature = "visit-mut")]
881808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "visit-mut")))]
882808c999fSMiguel Ojeda pub use crate::gen::visit_mut;
883808c999fSMiguel Ojeda
884808c999fSMiguel Ojeda // Not public API.
885808c999fSMiguel Ojeda #[doc(hidden)]
886808c999fSMiguel Ojeda #[path = "export.rs"]
887808c999fSMiguel Ojeda pub mod __private;
888808c999fSMiguel Ojeda
889808c999fSMiguel Ojeda /// Parse tokens of source code into the chosen syntax tree node.
890808c999fSMiguel Ojeda ///
891808c999fSMiguel Ojeda /// This is preferred over parsing a string because tokens are able to preserve
892808c999fSMiguel Ojeda /// information about where in the user's code they were originally written (the
893808c999fSMiguel Ojeda /// "span" of the token), possibly allowing the compiler to produce better error
894808c999fSMiguel Ojeda /// messages.
895808c999fSMiguel Ojeda ///
896808c999fSMiguel Ojeda /// This function parses a `proc_macro::TokenStream` which is the type used for
897808c999fSMiguel Ojeda /// interop with the compiler in a procedural macro. To parse a
898808c999fSMiguel Ojeda /// `proc_macro2::TokenStream`, use [`syn::parse2`] instead.
899808c999fSMiguel Ojeda ///
900808c999fSMiguel Ojeda /// [`syn::parse2`]: parse2
901808c999fSMiguel Ojeda ///
902808c999fSMiguel Ojeda /// This function enforces that the input is fully parsed. If there are any
903808c999fSMiguel Ojeda /// unparsed tokens at the end of the stream, an error is returned.
904808c999fSMiguel Ojeda #[cfg(all(feature = "parsing", feature = "proc-macro"))]
905808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "proc-macro"))))]
parse<T: parse::Parse>(tokens: proc_macro::TokenStream) -> Result<T>906808c999fSMiguel Ojeda pub fn parse<T: parse::Parse>(tokens: proc_macro::TokenStream) -> Result<T> {
907808c999fSMiguel Ojeda parse::Parser::parse(T::parse, tokens)
908808c999fSMiguel Ojeda }
909808c999fSMiguel Ojeda
910808c999fSMiguel Ojeda /// Parse a proc-macro2 token stream into the chosen syntax tree node.
911808c999fSMiguel Ojeda ///
912808c999fSMiguel Ojeda /// This function parses a `proc_macro2::TokenStream` which is commonly useful
913808c999fSMiguel Ojeda /// when the input comes from a node of the Syn syntax tree, for example the
914808c999fSMiguel Ojeda /// body tokens of a [`Macro`] node. When in a procedural macro parsing the
915808c999fSMiguel Ojeda /// `proc_macro::TokenStream` provided by the compiler, use [`syn::parse`]
916808c999fSMiguel Ojeda /// instead.
917808c999fSMiguel Ojeda ///
918808c999fSMiguel Ojeda /// [`syn::parse`]: parse()
919808c999fSMiguel Ojeda ///
920808c999fSMiguel Ojeda /// This function enforces that the input is fully parsed. If there are any
921808c999fSMiguel Ojeda /// unparsed tokens at the end of the stream, an error is returned.
922808c999fSMiguel Ojeda #[cfg(feature = "parsing")]
923808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
parse2<T: parse::Parse>(tokens: proc_macro2::TokenStream) -> Result<T>924808c999fSMiguel Ojeda pub fn parse2<T: parse::Parse>(tokens: proc_macro2::TokenStream) -> Result<T> {
925808c999fSMiguel Ojeda parse::Parser::parse2(T::parse, tokens)
926808c999fSMiguel Ojeda }
927808c999fSMiguel Ojeda
928808c999fSMiguel Ojeda /// Parse a string of Rust code into the chosen syntax tree node.
929808c999fSMiguel Ojeda ///
930808c999fSMiguel Ojeda /// This function enforces that the input is fully parsed. If there are any
931808c999fSMiguel Ojeda /// unparsed tokens at the end of the stream, an error is returned.
932808c999fSMiguel Ojeda ///
933808c999fSMiguel Ojeda /// # Hygiene
934808c999fSMiguel Ojeda ///
935808c999fSMiguel Ojeda /// Every span in the resulting syntax tree will be set to resolve at the macro
936808c999fSMiguel Ojeda /// call site.
937808c999fSMiguel Ojeda ///
938808c999fSMiguel Ojeda /// # Examples
939808c999fSMiguel Ojeda ///
940808c999fSMiguel Ojeda /// ```
941808c999fSMiguel Ojeda /// use syn::{Expr, Result};
942808c999fSMiguel Ojeda ///
943808c999fSMiguel Ojeda /// fn run() -> Result<()> {
944808c999fSMiguel Ojeda /// let code = "assert_eq!(u8::max_value(), 255)";
945808c999fSMiguel Ojeda /// let expr = syn::parse_str::<Expr>(code)?;
946808c999fSMiguel Ojeda /// println!("{:#?}", expr);
947808c999fSMiguel Ojeda /// Ok(())
948808c999fSMiguel Ojeda /// }
949808c999fSMiguel Ojeda /// #
950808c999fSMiguel Ojeda /// # run().unwrap();
951808c999fSMiguel Ojeda /// ```
952808c999fSMiguel Ojeda #[cfg(feature = "parsing")]
953808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
parse_str<T: parse::Parse>(s: &str) -> Result<T>954808c999fSMiguel Ojeda pub fn parse_str<T: parse::Parse>(s: &str) -> Result<T> {
955808c999fSMiguel Ojeda parse::Parser::parse_str(T::parse, s)
956808c999fSMiguel Ojeda }
957808c999fSMiguel Ojeda
958808c999fSMiguel Ojeda /// Parse the content of a file of Rust code.
959808c999fSMiguel Ojeda ///
960808c999fSMiguel Ojeda /// This is different from `syn::parse_str::<File>(content)` in two ways:
961808c999fSMiguel Ojeda ///
962808c999fSMiguel Ojeda /// - It discards a leading byte order mark `\u{FEFF}` if the file has one.
963808c999fSMiguel Ojeda /// - It preserves the shebang line of the file, such as `#!/usr/bin/env rustx`.
964808c999fSMiguel Ojeda ///
965808c999fSMiguel Ojeda /// If present, either of these would be an error using `from_str`.
966808c999fSMiguel Ojeda ///
967808c999fSMiguel Ojeda /// # Examples
968808c999fSMiguel Ojeda ///
969808c999fSMiguel Ojeda /// ```no_run
970808c999fSMiguel Ojeda /// use std::error::Error;
971808c999fSMiguel Ojeda /// use std::fs;
972808c999fSMiguel Ojeda /// use std::io::Read;
973808c999fSMiguel Ojeda ///
974808c999fSMiguel Ojeda /// fn run() -> Result<(), Box<dyn Error>> {
975808c999fSMiguel Ojeda /// let content = fs::read_to_string("path/to/code.rs")?;
976808c999fSMiguel Ojeda /// let ast = syn::parse_file(&content)?;
977808c999fSMiguel Ojeda /// if let Some(shebang) = ast.shebang {
978808c999fSMiguel Ojeda /// println!("{}", shebang);
979808c999fSMiguel Ojeda /// }
980808c999fSMiguel Ojeda /// println!("{} items", ast.items.len());
981808c999fSMiguel Ojeda ///
982808c999fSMiguel Ojeda /// Ok(())
983808c999fSMiguel Ojeda /// }
984808c999fSMiguel Ojeda /// #
985808c999fSMiguel Ojeda /// # run().unwrap();
986808c999fSMiguel Ojeda /// ```
987808c999fSMiguel Ojeda #[cfg(all(feature = "parsing", feature = "full"))]
988808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "full"))))]
parse_file(mut content: &str) -> Result<File>989808c999fSMiguel Ojeda pub fn parse_file(mut content: &str) -> Result<File> {
990808c999fSMiguel Ojeda // Strip the BOM if it is present
991808c999fSMiguel Ojeda const BOM: &str = "\u{feff}";
992808c999fSMiguel Ojeda if content.starts_with(BOM) {
993808c999fSMiguel Ojeda content = &content[BOM.len()..];
994808c999fSMiguel Ojeda }
995808c999fSMiguel Ojeda
996808c999fSMiguel Ojeda let mut shebang = None;
997808c999fSMiguel Ojeda if content.starts_with("#!") {
998808c999fSMiguel Ojeda let rest = whitespace::skip(&content[2..]);
999808c999fSMiguel Ojeda if !rest.starts_with('[') {
1000808c999fSMiguel Ojeda if let Some(idx) = content.find('\n') {
1001808c999fSMiguel Ojeda shebang = Some(content[..idx].to_string());
1002808c999fSMiguel Ojeda content = &content[idx..];
1003808c999fSMiguel Ojeda } else {
1004808c999fSMiguel Ojeda shebang = Some(content.to_string());
1005808c999fSMiguel Ojeda content = "";
1006808c999fSMiguel Ojeda }
1007808c999fSMiguel Ojeda }
1008808c999fSMiguel Ojeda }
1009808c999fSMiguel Ojeda
1010808c999fSMiguel Ojeda let mut file: File = parse_str(content)?;
1011808c999fSMiguel Ojeda file.shebang = shebang;
1012808c999fSMiguel Ojeda Ok(file)
1013808c999fSMiguel Ojeda }
1014