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