1 //! [![github]](https://github.com/dtolnay/syn) [![crates-io]](https://crates.io/crates/syn) [![docs-rs]](crate)
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&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K
9 //! Syn is a parsing library for parsing a stream of Rust tokens into a syntax
10 //! tree of Rust source code.
12 //! Currently this library is geared toward use in Rust procedural macros, but
13 //! contains some APIs that may be useful more generally.
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`].
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.
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.
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.
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.
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
51 //! # Example of a derive macro
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
61 //! [`TokenStream`]: proc_macro::TokenStream
73 //! # extern crate proc_macro;
75 //! use proc_macro::TokenStream;
77 //! use syn::{parse_macro_input, DeriveInput};
79 //! # const IGNORE_TOKENS: &str = stringify! {
80 //! #[proc_macro_derive(MyMacro)]
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);
86 //! // Build the output, possibly using quasi-quotation
87 //! let expanded = quote! {
91 //! // Hand the output tokens back to the compiler
92 //! TokenStream::from(expanded)
96 //! The [`heapsize`] example directory shows a complete working implementation
97 //! of a derive macro. It works on any Rust compiler 1.31+. The example derives
98 //! a `HeapSize` trait which computes an estimate of the amount of heap memory
101 //! [`heapsize`]: https://github.com/dtolnay/syn/tree/master/examples/heapsize
104 //! pub trait HeapSize {
105 //! /// Total number of bytes of heap memory owned by `self`.
106 //! fn heap_size_of_children(&self) -> usize;
110 //! The derive macro allows users to write `#[derive(HeapSize)]` on data
111 //! structures in their program.
114 //! # const IGNORE_TOKENS: &str = stringify! {
115 //! #[derive(HeapSize)]
117 //! struct Demo<'a, T: ?Sized> {
127 //! # Spans and error reporting
129 //! The token-based procedural macro API provides great control over where the
130 //! compiler's error messages are displayed in user code. Consider the error the
131 //! user sees if one of their field types does not implement `HeapSize`.
134 //! # const IGNORE_TOKENS: &str = stringify! {
135 //! #[derive(HeapSize)]
139 //! bad: std::thread::Thread,
143 //! By tracking span information all the way through the expansion of a
144 //! procedural macro as shown in the `heapsize` example, token-based macros in
145 //! Syn are able to trigger errors that directly pinpoint the source of the
149 //! error[E0277]: the trait bound `std::thread::Thread: HeapSize` is not satisfied
150 //! --> src/main.rs:7:5
152 //! 7 | bad: std::thread::Thread,
153 //! | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HeapSize` is not implemented for `Thread`
158 //! # Parsing a custom syntax
160 //! The [`lazy-static`] example directory shows the implementation of a
161 //! `functionlike!(...)` procedural macro in which the input tokens are parsed
162 //! using Syn's parsing API.
164 //! [`lazy-static`]: https://github.com/dtolnay/syn/tree/master/examples/lazy-static
166 //! The example reimplements the popular `lazy_static` crate from crates.io as a
167 //! procedural macro.
170 //! # macro_rules! lazy_static {
171 //! # ($($tt:tt)*) => {}
175 //! static ref USERNAME: Regex = Regex::new("^[a-z0-9_-]{3,16}$").unwrap();
179 //! The implementation shows how to trigger custom warnings and error messages
180 //! on the macro input.
183 //! warning: come on, pick a more creative name
184 //! --> src/main.rs:10:16
186 //! 10 | static ref FOO: String = "lazy_static".to_owned();
194 //! When testing macros, we often care not just that the macro can be used
195 //! successfully but also that when the macro is provided with invalid input it
196 //! produces maximally helpful error messages. Consider using the [`trybuild`]
197 //! crate to write tests for errors that are emitted by your macro or errors
198 //! detected by the Rust compiler in the expanded code following misuse of the
199 //! macro. Such tests help avoid regressions from later refactors that
200 //! mistakenly make an error no longer trigger or be less helpful than it used
203 //! [`trybuild`]: https://github.com/dtolnay/trybuild
209 //! When developing a procedural macro it can be helpful to look at what the
210 //! generated code looks like. Use `cargo rustc -- -Zunstable-options
211 //! --pretty=expanded` or the [`cargo expand`] subcommand.
213 //! [`cargo expand`]: https://github.com/dtolnay/cargo-expand
215 //! To show the expanded code for some crate that uses your procedural macro,
216 //! run `cargo expand` from that crate. To show the expanded code for one of
217 //! your own test cases, run `cargo expand --test the_test_case` where the last
218 //! argument is the name of the test file without the `.rs` extension.
220 //! This write-up by Brandon W Maister discusses debugging in more detail:
221 //! [Debugging Rust's new Custom Derive system][debugging].
223 //! [debugging]: https://quodlibetor.github.io/posts/debugging-rusts-new-custom-derive-system/
227 //! # Optional features
229 //! Syn puts a lot of functionality behind optional features in order to
230 //! optimize compile time for the most common use cases. The following features
233 //! - **`derive`** *(enabled by default)* — Data structures for representing the
234 //! possible input to a derive macro, including structs and enums and types.
235 //! - **`full`** — Data structures for representing the syntax tree of all valid
236 //! Rust source code, including items and expressions.
237 //! - **`parsing`** *(enabled by default)* — Ability to parse input tokens into
238 //! a syntax tree node of a chosen type.
239 //! - **`printing`** *(enabled by default)* — Ability to print a syntax tree
240 //! node as tokens of Rust source code.
241 //! - **`visit`** — Trait for traversing a syntax tree.
242 //! - **`visit-mut`** — Trait for traversing and mutating in place a syntax
244 //! - **`fold`** — Trait for transforming an owned syntax tree.
245 //! - **`clone-impls`** *(enabled by default)* — Clone impls for all syntax tree
247 //! - **`extra-traits`** — Debug, Eq, PartialEq, Hash impls for all syntax tree
249 //! - **`proc-macro`** *(enabled by default)* — Runtime dependency on the
250 //! dynamic library libproc_macro from rustc toolchain.
252 // Syn types in rustdoc of other crates get linked to here.
253 #![doc(html_root_url = "https://docs.rs/syn/1.0.74")]
254 #![cfg_attr(doc_cfg, feature(doc_cfg))]
255 #![allow(non_camel_case_types)]
256 // Ignored clippy lints.
258 clippy
::doc_markdown
,
259 clippy
::eval_order_dependence
,
260 clippy
::inherent_to_string
,
261 clippy
::large_enum_variant
,
262 clippy
::manual_map
, // https://github.com/rust-lang/rust-clippy/issues/6795
263 clippy
::match_on_vec_items
,
264 clippy
::missing_panics_doc
,
265 clippy
::needless_doctest_main
,
266 clippy
::needless_pass_by_value
,
268 clippy
::too_many_arguments
,
269 clippy
::trivially_copy_pass_by_ref
,
270 clippy
::unnecessary_unwrap
,
271 // clippy bug: https://github.com/rust-lang/rust-clippy/issues/6983
272 clippy
::wrong_self_convention
274 // Ignored clippy_pedantic lints.
276 clippy
::cast_possible_truncation
,
277 // clippy bug: https://github.com/rust-lang/rust-clippy/issues/7127
278 clippy
::cloned_instead_of_copied
,
279 clippy
::default_trait_access
,
281 clippy
::expl_impl_clone_on_copy
,
283 clippy
::match_same_arms
,
284 // clippy bug: https://github.com/rust-lang/rust-clippy/issues/6984
285 clippy
::match_wildcard_for_single_variants
,
286 clippy
::missing_errors_doc
,
287 clippy
::module_name_repetitions
,
288 clippy
::must_use_candidate
,
289 clippy
::option_if_let_else
,
290 clippy
::redundant_else
,
291 clippy
::shadow_unrelated
,
292 clippy
::similar_names
,
293 clippy
::single_match_else
,
294 clippy
::too_many_lines
,
295 clippy
::unseparated_literal_suffix
,
296 clippy
::used_underscore_binding
,
297 clippy
::wildcard_imports
301 not(all(target_arch
= "wasm32", any(target_os
= "unknown", target_os
= "wasi"))),
302 feature
= "proc-macro"
304 extern crate proc_macro
;
305 extern crate proc_macro2
;
306 extern crate unicode_xid
;
308 #[cfg(feature = "printing")]
315 #[cfg(feature = "parsing")]
324 pub use crate::ident
::Ident
;
326 #[cfg(any(feature = "full", feature = "derive"))]
328 #[cfg(any(feature = "full", feature = "derive"))]
329 pub use crate::attr
::{
330 AttrStyle
, Attribute
, AttributeArgs
, Meta
, MetaList
, MetaNameValue
, NestedMeta
,
335 #[cfg(any(feature = "full", feature = "derive"))]
337 #[cfg(any(feature = "full", feature = "derive"))]
338 pub use crate::data
::{
339 Field
, Fields
, FieldsNamed
, FieldsUnnamed
, Variant
, VisCrate
, VisPublic
, VisRestricted
,
343 #[cfg(any(feature = "full", feature = "derive"))]
345 #[cfg(feature = "full")]
346 pub use crate::expr
::{
347 Arm
, FieldValue
, GenericMethodArgument
, Label
, MethodTurbofish
, RangeLimits
,
349 #[cfg(any(feature = "full", feature = "derive"))]
350 pub use crate::expr
::{
351 Expr
, ExprArray
, ExprAssign
, ExprAssignOp
, ExprAsync
, ExprAwait
, ExprBinary
, ExprBlock
,
352 ExprBox
, ExprBreak
, ExprCall
, ExprCast
, ExprClosure
, ExprContinue
, ExprField
, ExprForLoop
,
353 ExprGroup
, ExprIf
, ExprIndex
, ExprLet
, ExprLit
, ExprLoop
, ExprMacro
, ExprMatch
, ExprMethodCall
,
354 ExprParen
, ExprPath
, ExprRange
, ExprReference
, ExprRepeat
, ExprReturn
, ExprStruct
, ExprTry
,
355 ExprTryBlock
, ExprTuple
, ExprType
, ExprUnary
, ExprUnsafe
, ExprWhile
, ExprYield
, Index
, Member
,
358 #[cfg(any(feature = "full", feature = "derive"))]
360 #[cfg(any(feature = "full", feature = "derive"))]
361 pub use crate::generics
::{
362 BoundLifetimes
, ConstParam
, GenericParam
, Generics
, LifetimeDef
, PredicateEq
,
363 PredicateLifetime
, PredicateType
, TraitBound
, TraitBoundModifier
, TypeParam
, TypeParamBound
,
364 WhereClause
, WherePredicate
,
366 #[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))]
367 pub use crate::generics
::{ImplGenerics, Turbofish, TypeGenerics}
;
369 #[cfg(feature = "full")]
371 #[cfg(feature = "full")]
372 pub use crate::item
::{
373 FnArg
, ForeignItem
, ForeignItemFn
, ForeignItemMacro
, ForeignItemStatic
, ForeignItemType
,
374 ImplItem
, ImplItemConst
, ImplItemMacro
, ImplItemMethod
, ImplItemType
, Item
, ItemConst
,
375 ItemEnum
, ItemExternCrate
, ItemFn
, ItemForeignMod
, ItemImpl
, ItemMacro
, ItemMacro2
, ItemMod
,
376 ItemStatic
, ItemStruct
, ItemTrait
, ItemTraitAlias
, ItemType
, ItemUnion
, ItemUse
, Receiver
,
377 Signature
, TraitItem
, TraitItemConst
, TraitItemMacro
, TraitItemMethod
, TraitItemType
, UseGlob
,
378 UseGroup
, UseName
, UsePath
, UseRename
, UseTree
,
381 #[cfg(feature = "full")]
383 #[cfg(feature = "full")]
384 pub use crate::file
::File
;
387 pub use crate::lifetime
::Lifetime
;
390 pub use crate::lit
::{
391 Lit
, LitBool
, LitByte
, LitByteStr
, LitChar
, LitFloat
, LitInt
, LitStr
, StrStyle
,
394 #[cfg(any(feature = "full", feature = "derive"))]
396 #[cfg(any(feature = "full", feature = "derive"))]
397 pub use crate::mac
::{Macro, MacroDelimiter}
;
399 #[cfg(any(feature = "full", feature = "derive"))]
401 #[cfg(feature = "derive")]
402 pub use crate::derive
::{Data, DataEnum, DataStruct, DataUnion, DeriveInput}
;
404 #[cfg(any(feature = "full", feature = "derive"))]
406 #[cfg(any(feature = "full", feature = "derive"))]
407 pub use crate::op
::{BinOp, UnOp}
;
409 #[cfg(feature = "full")]
411 #[cfg(feature = "full")]
412 pub use crate::stmt
::{Block, Local, Stmt}
;
414 #[cfg(any(feature = "full", feature = "derive"))]
416 #[cfg(any(feature = "full", feature = "derive"))]
418 Abi
, BareFnArg
, ReturnType
, Type
, TypeArray
, TypeBareFn
, TypeGroup
, TypeImplTrait
, TypeInfer
,
419 TypeMacro
, TypeNever
, TypeParen
, TypePath
, TypePtr
, TypeReference
, TypeSlice
, TypeTraitObject
,
423 #[cfg(feature = "full")]
425 #[cfg(feature = "full")]
426 pub use crate::pat
::{
427 FieldPat
, Pat
, PatBox
, PatIdent
, PatLit
, PatMacro
, PatOr
, PatPath
, PatRange
, PatReference
,
428 PatRest
, PatSlice
, PatStruct
, PatTuple
, PatTupleStruct
, PatType
, PatWild
,
431 #[cfg(any(feature = "full", feature = "derive"))]
433 #[cfg(any(feature = "full", feature = "derive"))]
434 pub use crate::path
::{
435 AngleBracketedGenericArguments
, Binding
, Constraint
, GenericArgument
,
436 ParenthesizedGenericArguments
, Path
, PathArguments
, PathSegment
, QSelf
,
439 #[cfg(feature = "parsing")]
440 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
442 #[cfg(feature = "parsing")]
443 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
446 #[cfg(all(any(feature = "full", feature = "derive"), feature = "extra-traits"))]
449 // Not public API except the `parse_quote!` macro.
450 #[cfg(feature = "parsing")]
454 // Not public API except the `parse_macro_input!` macro.
456 not(all(target_arch
= "wasm32", any(target_os
= "unknown", target_os
= "wasi"))),
458 feature
= "proc-macro"
461 pub mod parse_macro_input
;
463 #[cfg(all(feature = "parsing", feature = "printing"))]
464 #[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "printing"))))]
467 #[cfg(all(feature = "parsing", feature = "full"))]
471 /// Syntax tree traversal to walk a shared borrow of a syntax tree.
473 /// Each method of the [`Visit`] trait is a hook that can be overridden to
474 /// customize the behavior when visiting the corresponding type of node. By
475 /// default, every method recursively visits the substructure of the input
476 /// by invoking the right visitor method of each of its fields.
478 /// [`Visit`]: visit::Visit
481 /// # use syn::{Attribute, BinOp, Expr, ExprBinary};
483 /// pub trait Visit<'ast> {
486 /// fn visit_expr_binary(&mut self, node: &'ast ExprBinary) {
487 /// visit_expr_binary(self, node);
491 /// # fn visit_attribute(&mut self, node: &'ast Attribute);
492 /// # fn visit_expr(&mut self, node: &'ast Expr);
493 /// # fn visit_bin_op(&mut self, node: &'ast BinOp);
496 /// pub fn visit_expr_binary<'ast, V>(v: &mut V, node: &'ast ExprBinary)
498 /// V: Visit<'ast> + ?Sized,
500 /// for attr in &node.attrs {
501 /// v.visit_attribute(attr);
503 /// v.visit_expr(&*node.left);
504 /// v.visit_bin_op(&node.op);
505 /// v.visit_expr(&*node.right);
511 /// *This module is available only if Syn is built with the `"visit"` feature.*
517 /// This visitor will print the name of every freestanding function in the
518 /// syntax tree, including nested functions.
521 /// // [dependencies]
523 /// // syn = { version = "1.0", features = ["full", "visit"] }
525 /// use quote::quote;
526 /// use syn::visit::{self, Visit};
527 /// use syn::{File, ItemFn};
529 /// struct FnVisitor;
531 /// impl<'ast> Visit<'ast> for FnVisitor {
532 /// fn visit_item_fn(&mut self, node: &'ast ItemFn) {
533 /// println!("Function with name={}", node.sig.ident);
535 /// // Delegate to the default impl to visit any nested functions.
536 /// visit::visit_item_fn(self, node);
541 /// let code = quote! {
547 /// let syntax_tree: File = syn::parse2(code).unwrap();
548 /// FnVisitor.visit_file(&syntax_tree);
552 /// The `'ast` lifetime on the input references means that the syntax tree
553 /// outlives the complete recursive visit call, so the visitor is allowed to
554 /// hold on to references into the syntax tree.
557 /// use quote::quote;
558 /// use syn::visit::{self, Visit};
559 /// use syn::{File, ItemFn};
561 /// struct FnVisitor<'ast> {
562 /// functions: Vec<&'ast ItemFn>,
565 /// impl<'ast> Visit<'ast> for FnVisitor<'ast> {
566 /// fn visit_item_fn(&mut self, node: &'ast ItemFn) {
567 /// self.functions.push(node);
568 /// visit::visit_item_fn(self, node);
573 /// let code = quote! {
579 /// let syntax_tree: File = syn::parse2(code).unwrap();
580 /// let mut visitor = FnVisitor { functions: Vec::new() };
581 /// visitor.visit_file(&syntax_tree);
582 /// for f in visitor.functions {
583 /// println!("Function with name={}", f.sig.ident);
587 #[cfg(feature = "visit")]
588 #[cfg_attr(doc_cfg, doc(cfg(feature = "visit")))]
592 /// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in
595 /// Each method of the [`VisitMut`] trait is a hook that can be overridden
596 /// to customize the behavior when mutating the corresponding type of node.
597 /// By default, every method recursively visits the substructure of the
598 /// input by invoking the right visitor method of each of its fields.
600 /// [`VisitMut`]: visit_mut::VisitMut
603 /// # use syn::{Attribute, BinOp, Expr, ExprBinary};
605 /// pub trait VisitMut {
608 /// fn visit_expr_binary_mut(&mut self, node: &mut ExprBinary) {
609 /// visit_expr_binary_mut(self, node);
613 /// # fn visit_attribute_mut(&mut self, node: &mut Attribute);
614 /// # fn visit_expr_mut(&mut self, node: &mut Expr);
615 /// # fn visit_bin_op_mut(&mut self, node: &mut BinOp);
618 /// pub fn visit_expr_binary_mut<V>(v: &mut V, node: &mut ExprBinary)
620 /// V: VisitMut + ?Sized,
622 /// for attr in &mut node.attrs {
623 /// v.visit_attribute_mut(attr);
625 /// v.visit_expr_mut(&mut *node.left);
626 /// v.visit_bin_op_mut(&mut node.op);
627 /// v.visit_expr_mut(&mut *node.right);
633 /// *This module is available only if Syn is built with the `"visit-mut"`
640 /// This mut visitor replace occurrences of u256 suffixed integer literals
641 /// like `999u256` with a macro invocation `bigint::u256!(999)`.
644 /// // [dependencies]
646 /// // syn = { version = "1.0", features = ["full", "visit-mut"] }
648 /// use quote::quote;
649 /// use syn::visit_mut::{self, VisitMut};
650 /// use syn::{parse_quote, Expr, File, Lit, LitInt};
652 /// struct BigintReplace;
654 /// impl VisitMut for BigintReplace {
655 /// fn visit_expr_mut(&mut self, node: &mut Expr) {
656 /// if let Expr::Lit(expr) = &node {
657 /// if let Lit::Int(int) = &expr.lit {
658 /// if int.suffix() == "u256" {
659 /// let digits = int.base10_digits();
660 /// let unsuffixed: LitInt = syn::parse_str(digits).unwrap();
661 /// *node = parse_quote!(bigint::u256!(#unsuffixed));
667 /// // Delegate to the default impl to visit nested expressions.
668 /// visit_mut::visit_expr_mut(self, node);
673 /// let code = quote! {
679 /// let mut syntax_tree: File = syn::parse2(code).unwrap();
680 /// BigintReplace.visit_file_mut(&mut syntax_tree);
681 /// println!("{}", quote!(#syntax_tree));
684 #[cfg(feature = "visit-mut")]
685 #[cfg_attr(doc_cfg, doc(cfg(feature = "visit-mut")))]
689 /// Syntax tree traversal to transform the nodes of an owned syntax tree.
691 /// Each method of the [`Fold`] trait is a hook that can be overridden to
692 /// customize the behavior when transforming the corresponding type of node.
693 /// By default, every method recursively visits the substructure of the
694 /// input by invoking the right visitor method of each of its fields.
696 /// [`Fold`]: fold::Fold
699 /// # use syn::{Attribute, BinOp, Expr, ExprBinary};
704 /// fn fold_expr_binary(&mut self, node: ExprBinary) -> ExprBinary {
705 /// fold_expr_binary(self, node)
709 /// # fn fold_attribute(&mut self, node: Attribute) -> Attribute;
710 /// # fn fold_expr(&mut self, node: Expr) -> Expr;
711 /// # fn fold_bin_op(&mut self, node: BinOp) -> BinOp;
714 /// pub fn fold_expr_binary<V>(v: &mut V, node: ExprBinary) -> ExprBinary
716 /// V: Fold + ?Sized,
722 /// .map(|attr| v.fold_attribute(attr))
724 /// left: Box::new(v.fold_expr(*node.left)),
725 /// op: v.fold_bin_op(node.op),
726 /// right: Box::new(v.fold_expr(*node.right)),
733 /// *This module is available only if Syn is built with the `"fold"` feature.*
739 /// This fold inserts parentheses to fully parenthesizes any expression.
742 /// // [dependencies]
744 /// // syn = { version = "1.0", features = ["fold", "full"] }
746 /// use quote::quote;
747 /// use syn::fold::{fold_expr, Fold};
748 /// use syn::{token, Expr, ExprParen};
750 /// struct ParenthesizeEveryExpr;
752 /// impl Fold for ParenthesizeEveryExpr {
753 /// fn fold_expr(&mut self, expr: Expr) -> Expr {
754 /// Expr::Paren(ExprParen {
755 /// attrs: Vec::new(),
756 /// expr: Box::new(fold_expr(self, expr)),
757 /// paren_token: token::Paren::default(),
763 /// let code = quote! { a() + b(1) * c.d };
764 /// let expr: Expr = syn::parse2(code).unwrap();
765 /// let parenthesized = ParenthesizeEveryExpr.fold_expr(expr);
766 /// println!("{}", quote!(#parenthesized));
768 /// // Output: (((a)()) + (((b)((1))) * ((c).d)))
771 #[cfg(feature = "fold")]
772 #[cfg_attr(doc_cfg, doc(cfg(feature = "fold")))]
776 #[cfg(feature = "clone-impls")]
780 #[cfg(feature = "extra-traits")]
784 #[cfg(feature = "extra-traits")]
788 #[cfg(feature = "extra-traits")]
792 #[cfg(any(feature = "full", feature = "derive"))]
793 #[path = "../gen_helper.rs"]
796 pub use crate::gen
::*;
800 #[path = "export.rs"]
804 mod custom_punctuation
;
809 #[cfg(feature = "parsing")]
812 #[cfg(feature = "parsing")]
813 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
816 #[cfg(feature = "full")]
819 #[cfg(all(any(feature = "full", feature = "derive"), feature = "parsing"))]
822 #[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))]
825 use crate::__private
::private
;
827 ////////////////////////////////////////////////////////////////////////////////
829 // https://github.com/rust-lang/rust/issues/62830
830 #[cfg(feature = "parsing")]
831 mod rustdoc_workaround
{
832 pub use crate::parse
::{self as parse_module}
;
835 ////////////////////////////////////////////////////////////////////////////////
838 pub use crate::error
::{Error, Result}
;
840 /// Parse tokens of source code into the chosen syntax tree node.
842 /// This is preferred over parsing a string because tokens are able to preserve
843 /// information about where in the user's code they were originally written (the
844 /// "span" of the token), possibly allowing the compiler to produce better error
847 /// This function parses a `proc_macro::TokenStream` which is the type used for
848 /// interop with the compiler in a procedural macro. To parse a
849 /// `proc_macro2::TokenStream`, use [`syn::parse2`] instead.
851 /// [`syn::parse2`]: parse2
853 /// *This function is available only if Syn is built with both the `"parsing"` and
854 /// `"proc-macro"` features.*
859 /// # extern crate proc_macro;
861 /// use proc_macro::TokenStream;
862 /// use quote::quote;
863 /// use syn::DeriveInput;
865 /// # const IGNORE_TOKENS: &str = stringify! {
866 /// #[proc_macro_derive(MyMacro)]
868 /// pub fn my_macro(input: TokenStream) -> TokenStream {
869 /// // Parse the tokens into a syntax tree
870 /// let ast: DeriveInput = syn::parse(input).unwrap();
872 /// // Build the output, possibly using quasi-quotation
873 /// let expanded = quote! {
877 /// // Convert into a token stream and return it
882 not(all(target_arch
= "wasm32", any(target_os
= "unknown", target_os
= "wasi"))),
884 feature
= "proc-macro"
886 #[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "proc-macro"))))]
887 pub fn parse
<T
: parse
::Parse
>(tokens
: proc_macro
::TokenStream
) -> Result
<T
> {
888 parse
::Parser
::parse(T
::parse
, tokens
)
891 /// Parse a proc-macro2 token stream into the chosen syntax tree node.
893 /// This function parses a `proc_macro2::TokenStream` which is commonly useful
894 /// when the input comes from a node of the Syn syntax tree, for example the
895 /// body tokens of a [`Macro`] node. When in a procedural macro parsing the
896 /// `proc_macro::TokenStream` provided by the compiler, use [`syn::parse`]
899 /// [`syn::parse`]: parse()
901 /// *This function is available only if Syn is built with the `"parsing"` feature.*
902 #[cfg(feature = "parsing")]
903 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
904 pub fn parse2
<T
: parse
::Parse
>(tokens
: proc_macro2
::TokenStream
) -> Result
<T
> {
905 parse
::Parser
::parse2(T
::parse
, tokens
)
908 /// Parse a string of Rust code into the chosen syntax tree node.
910 /// *This function is available only if Syn is built with the `"parsing"` feature.*
914 /// Every span in the resulting syntax tree will be set to resolve at the macro
920 /// use syn::{Expr, Result};
922 /// fn run() -> Result<()> {
923 /// let code = "assert_eq!(u8::max_value(), 255)";
924 /// let expr = syn::parse_str::<Expr>(code)?;
925 /// println!("{:#?}", expr);
929 /// # run().unwrap();
931 #[cfg(feature = "parsing")]
932 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
933 pub fn parse_str
<T
: parse
::Parse
>(s
: &str) -> Result
<T
> {
934 parse
::Parser
::parse_str(T
::parse
, s
)
937 // FIXME the name parse_file makes it sound like you might pass in a path to a
938 // file, rather than the content.
939 /// Parse the content of a file of Rust code.
941 /// This is different from `syn::parse_str::<File>(content)` in two ways:
943 /// - It discards a leading byte order mark `\u{FEFF}` if the file has one.
944 /// - It preserves the shebang line of the file, such as `#!/usr/bin/env rustx`.
946 /// If present, either of these would be an error using `from_str`.
948 /// *This function is available only if Syn is built with the `"parsing"` and
949 /// `"full"` features.*
954 /// use std::error::Error;
955 /// use std::fs::File;
956 /// use std::io::Read;
958 /// fn run() -> Result<(), Box<Error>> {
959 /// let mut file = File::open("path/to/code.rs")?;
960 /// let mut content = String::new();
961 /// file.read_to_string(&mut content)?;
963 /// let ast = syn::parse_file(&content)?;
964 /// if let Some(shebang) = ast.shebang {
965 /// println!("{}", shebang);
967 /// println!("{} items", ast.items.len());
972 /// # run().unwrap();
974 #[cfg(all(feature = "parsing", feature = "full"))]
975 #[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "full"))))]
976 pub fn parse_file(mut content
: &str) -> Result
<File
> {
977 // Strip the BOM if it is present
978 const BOM
: &str = "\u{feff}";
979 if content
.starts_with(BOM
) {
980 content
= &content
[BOM
.len()..];
983 let mut shebang
= None
;
984 if content
.starts_with("#!") {
985 let rest
= whitespace
::skip(&content
[2..]);
986 if !rest
.starts_with('
['
) {
987 if let Some(idx
) = content
.find('
\n'
) {
988 shebang
= Some(content
[..idx
].to_string());
989 content
= &content
[idx
..];
991 shebang
= Some(content
.to_string());
997 let mut file
: File
= parse_str(content
)?
;
998 file
.shebang
= shebang
;