// SPDX-License-Identifier: Apache-2.0 OR MIT12//! [![github]](https://github.com/dtolnay/syn) [![crates-io]](https://crates.io/crates/syn) [![docs-rs]](crate)3//!4//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github5//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust6//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs7//!8//! <br>9//!10//! Syn is a parsing library for parsing a stream of Rust tokens into a syntax11//! tree of Rust source code.12//!13//! Currently this library is geared toward use in Rust procedural macros, but14//! contains some APIs that may be useful more generally.15//!16//! - **Data structures** — Syn provides a complete syntax tree that can17//! represent any valid Rust source code. The syntax tree is rooted at18//! [`syn::File`] which represents a full source file, but there are other19//! entry points that may be useful to procedural macros including20//! [`syn::Item`], [`syn::Expr`] and [`syn::Type`].21//!22//! - **Derives** — Of particular interest to derive macros is23//! [`syn::DeriveInput`] which is any of the three legal input items to a24//! derive macro. An example below shows using this type in a library that can25//! derive implementations of a user-defined trait.26//!27//! - **Parsing** — Parsing in Syn is built around [parser functions] with the28//! signature `fn(ParseStream) -> Result<T>`. Every syntax tree node defined29//! by Syn is individually parsable and may be used as a building block for30//! custom syntaxes, or you may dream up your own brand new syntax without31//! involving any of our syntax tree types.32//!33//! - **Location information** — Every token parsed by Syn is associated with a34//! `Span` that tracks line and column information back to the source of that35//! token. These spans allow a procedural macro to display detailed error36//! messages pointing to all the right places in the user's code. There is an37//! example of this below.38//!39//! - **Feature flags** — Functionality is aggressively feature gated so your40//! procedural macros enable only what they need, and do not pay in compile41//! time for all the rest.42//!43//! [`syn::File`]: File44//! [`syn::Item`]: Item45//! [`syn::Expr`]: Expr46//! [`syn::Type`]: Type47//! [`syn::DeriveInput`]: DeriveInput48//! [parser functions]: mod@parse49//!50//! <br>51//!52//! # Example of a derive macro53//!54//! The canonical derive macro using Syn looks like this. We write an ordinary55//! Rust function tagged with a `proc_macro_derive` attribute and the name of56//! the trait we are deriving. Any time that derive appears in the user's code,57//! the Rust compiler passes their data structure as tokens into our macro. We58//! get to execute arbitrary Rust code to figure out what to do with those59//! tokens, then hand some tokens back to the compiler to compile into the60//! user's crate.61//!62//! [`TokenStream`]: proc_macro::TokenStream63//!64//! ```toml65//! [dependencies]66//! syn = "2.0"67//! quote = "1.0"68//!69//! [lib]70//! proc-macro = true71//! ```72//!73//! ```74//! # extern crate proc_macro;75//! #76//! use proc_macro::TokenStream;77//! use quote::quote;78//! use syn::{parse_macro_input, DeriveInput};79//!80//! # const IGNORE_TOKENS: &str = stringify! {81//! #[proc_macro_derive(MyMacro)]82//! # };83//! pub fn my_macro(input: TokenStream) -> TokenStream {84//! // Parse the input tokens into a syntax tree85//! let input = parse_macro_input!(input as DeriveInput);86//!87//! // Build the output, possibly using quasi-quotation88//! let expanded = quote! {89//! // ...90//! };91//!92//! // Hand the output tokens back to the compiler93//! TokenStream::from(expanded)94//! }95//! ```96//!97//! The [`heapsize`] example directory shows a complete working implementation98//! of a derive macro. The example derives a `HeapSize` trait which computes an99//! estimate of the amount of heap memory owned by a value.100//!101//! [`heapsize`]: https://github.com/dtolnay/syn/tree/master/examples/heapsize102//!103//! ```104//! pub trait HeapSize {105//! /// Total number of bytes of heap memory owned by `self`.106//! fn heap_size_of_children(&self) -> usize;107//! }108//! ```109//!110//! The derive macro allows users to write `#[derive(HeapSize)]` on data111//! structures in their program.112//!113//! ```114//! # const IGNORE_TOKENS: &str = stringify! {115//! #[derive(HeapSize)]116//! # };117//! struct Demo<'a, T: ?Sized> {118//! a: Box<T>,119//! b: u8,120//! c: &'a str,121//! d: String,122//! }123//! ```124//!125//! <p><br></p>126//!127//! # Spans and error reporting128//!129//! The token-based procedural macro API provides great control over where the130//! compiler's error messages are displayed in user code. Consider the error the131//! user sees if one of their field types does not implement `HeapSize`.132//!133//! ```134//! # const IGNORE_TOKENS: &str = stringify! {135//! #[derive(HeapSize)]136//! # };137//! struct Broken {138//! ok: String,139//! bad: std::thread::Thread,140//! }141//! ```142//!143//! By tracking span information all the way through the expansion of a144//! procedural macro as shown in the `heapsize` example, token-based macros in145//! Syn are able to trigger errors that directly pinpoint the source of the146//! problem.147//!148//! ```text149//! error[E0277]: the trait bound `std::thread::Thread: HeapSize` is not satisfied150//! --> src/main.rs:7:5151//! |152//! 7 | bad: std::thread::Thread,153//! | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HeapSize` is not implemented for `Thread`154//! ```155//!156//! <br>157//!158//! # Parsing a custom syntax159//!160//! The [`lazy-static`] example directory shows the implementation of a161//! `functionlike!(...)` procedural macro in which the input tokens are parsed162//! using Syn's parsing API.163//!164//! [`lazy-static`]: https://github.com/dtolnay/syn/tree/master/examples/lazy-static165//!166//! The example reimplements the popular `lazy_static` crate from crates.io as a167//! procedural macro.168//!169//! ```170//! # macro_rules! lazy_static {171//! # ($($tt:tt)*) => {}172//! # }173//! #174//! lazy_static! {175//! static ref USERNAME: Regex = Regex::new("^[a-z0-9_-]{3,16}$").unwrap();176//! }177//! ```178//!179//! The implementation shows how to trigger custom warnings and error messages180//! on the macro input.181//!182//! ```text183//! warning: come on, pick a more creative name184//! --> src/main.rs:10:16185//! |186//! 10 | static ref FOO: String = "lazy_static".to_owned();187//! | ^^^188//! ```189//!190//! <br>191//!192//! # Testing193//!194//! When testing macros, we often care not just that the macro can be used195//! successfully but also that when the macro is provided with invalid input it196//! produces maximally helpful error messages. Consider using the [`trybuild`]197//! crate to write tests for errors that are emitted by your macro or errors198//! detected by the Rust compiler in the expanded code following misuse of the199//! macro. Such tests help avoid regressions from later refactors that200//! mistakenly make an error no longer trigger or be less helpful than it used201//! to be.202//!203//! [`trybuild`]: https://github.com/dtolnay/trybuild204//!205//! <br>206//!207//! # Debugging208//!209//! When developing a procedural macro it can be helpful to look at what the210//! generated code looks like. Use `cargo rustc -- -Zunstable-options211//! --pretty=expanded` or the [`cargo expand`] subcommand.212//!213//! [`cargo expand`]: https://github.com/dtolnay/cargo-expand214//!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 of217//! your own test cases, run `cargo expand --test the_test_case` where the last218//! argument is the name of the test file without the `.rs` extension.219//!220//! This write-up by Brandon W Maister discusses debugging in more detail:221//! [Debugging Rust's new Custom Derive system][debugging].222//!223//! [debugging]: https://quodlibetor.github.io/posts/debugging-rusts-new-custom-derive-system/224//!225//! <br>226//!227//! # Optional features228//!229//! Syn puts a lot of functionality behind optional features in order to230//! optimize compile time for the most common use cases. The following features231//! are available.232//!233//! - **`derive`** *(enabled by default)* — Data structures for representing the234//! possible input to a derive macro, including structs and enums and types.235//! - **`full`** — Data structures for representing the syntax tree of all valid236//! Rust source code, including items and expressions.237//! - **`parsing`** *(enabled by default)* — Ability to parse input tokens into238//! a syntax tree node of a chosen type.239//! - **`printing`** *(enabled by default)* — Ability to print a syntax tree240//! 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 syntax243//! tree.244//! - **`fold`** — Trait for transforming an owned syntax tree.245//! - **`clone-impls`** *(enabled by default)* — Clone impls for all syntax tree246//! types.247//! - **`extra-traits`** — Debug, Eq, PartialEq, Hash impls for all syntax tree248//! types.249//! - **`proc-macro`** *(enabled by default)* — Runtime dependency on the250//! dynamic library libproc_macro from rustc toolchain.251252// Syn types in rustdoc of other crates get linked to here.253#![doc(html_root_url = "https://docs.rs/syn/2.0.106")]254#![cfg_attr(docsrs, feature(doc_cfg))]255#![deny(unsafe_op_in_unsafe_fn)]256#![allow(non_camel_case_types)]257#![cfg_attr(not(check_cfg), allow(unexpected_cfgs))]258#![allow(259clippy::bool_to_int_with_if,260clippy::cast_lossless,261clippy::cast_possible_truncation,262clippy::cast_possible_wrap,263clippy::cast_ptr_alignment,264clippy::default_trait_access,265clippy::derivable_impls,266clippy::diverging_sub_expression,267clippy::doc_markdown,268clippy::elidable_lifetime_names,269clippy::enum_glob_use,270clippy::expl_impl_clone_on_copy,271clippy::explicit_auto_deref,272clippy::fn_params_excessive_bools,273clippy::if_not_else,274clippy::inherent_to_string,275clippy::into_iter_without_iter,276clippy::items_after_statements,277clippy::large_enum_variant,278clippy::let_underscore_untyped, // https://github.com/rust-lang/rust-clippy/issues/10410279clippy::manual_assert,280clippy::manual_let_else,281clippy::manual_map,282clippy::match_like_matches_macro,283clippy::match_same_arms,284clippy::match_wildcard_for_single_variants, // clippy bug: https://github.com/rust-lang/rust-clippy/issues/6984285clippy::missing_errors_doc,286clippy::missing_panics_doc,287clippy::module_name_repetitions,288clippy::must_use_candidate,289clippy::needless_doctest_main,290clippy::needless_lifetimes,291clippy::needless_pass_by_value,292clippy::needless_update,293clippy::never_loop,294clippy::range_plus_one,295clippy::redundant_else,296clippy::ref_option,297clippy::return_self_not_must_use,298clippy::similar_names,299clippy::single_match_else,300clippy::struct_excessive_bools,301clippy::too_many_arguments,302clippy::too_many_lines,303clippy::trivially_copy_pass_by_ref,304clippy::unconditional_recursion, // https://github.com/rust-lang/rust-clippy/issues/12133305clippy::uninhabited_references,306clippy::uninlined_format_args,307clippy::unnecessary_box_returns,308clippy::unnecessary_unwrap,309clippy::used_underscore_binding,310clippy::wildcard_imports,311)]312#![allow(unknown_lints, mismatched_lifetime_syntaxes)]313314extern crate self as syn;315316#[cfg(feature = "proc-macro")]317extern crate proc_macro;318319#[macro_use]320mod macros;321322#[cfg(feature = "parsing")]323#[macro_use]324mod group;325326#[macro_use]327pub mod token;328329#[cfg(any(feature = "full", feature = "derive"))]330mod attr;331#[cfg(any(feature = "full", feature = "derive"))]332#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]333pub use crate::attr::{AttrStyle, Attribute, Meta, MetaList, MetaNameValue};334335mod bigint;336337#[cfg(feature = "parsing")]338#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]339pub mod buffer;340341#[cfg(any(342all(feature = "parsing", feature = "full"),343all(feature = "printing", any(feature = "full", feature = "derive")),344))]345mod classify;346347mod custom_keyword;348349mod custom_punctuation;350351#[cfg(any(feature = "full", feature = "derive"))]352mod data;353#[cfg(any(feature = "full", feature = "derive"))]354#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]355pub use crate::data::{Field, Fields, FieldsNamed, FieldsUnnamed, Variant};356357#[cfg(any(feature = "full", feature = "derive"))]358mod derive;359#[cfg(feature = "derive")]360#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]361pub use crate::derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput};362363mod drops;364365mod error;366pub use crate::error::{Error, Result};367368#[cfg(any(feature = "full", feature = "derive"))]369mod expr;370#[cfg(feature = "full")]371#[cfg_attr(docsrs, doc(cfg(feature = "full")))]372pub use crate::expr::{Arm, Label, PointerMutability, RangeLimits};373#[cfg(any(feature = "full", feature = "derive"))]374#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]375pub use crate::expr::{376Expr, ExprBinary, ExprCall, ExprCast, ExprField, ExprIndex, ExprLit, ExprMacro, ExprMethodCall,377ExprParen, ExprPath, ExprReference, ExprStruct, ExprUnary, FieldValue, Index, Member,378};379#[cfg(any(feature = "full", feature = "derive"))]380#[cfg_attr(docsrs, doc(cfg(feature = "full")))]381pub use crate::expr::{382ExprArray, ExprAssign, ExprAsync, ExprAwait, ExprBlock, ExprBreak, ExprClosure, ExprConst,383ExprContinue, ExprForLoop, ExprGroup, ExprIf, ExprInfer, ExprLet, ExprLoop, ExprMatch,384ExprRange, ExprRawAddr, ExprRepeat, ExprReturn, ExprTry, ExprTryBlock, ExprTuple, ExprUnsafe,385ExprWhile, ExprYield,386};387388#[cfg(feature = "parsing")]389#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]390pub mod ext;391392#[cfg(feature = "full")]393mod file;394#[cfg(feature = "full")]395#[cfg_attr(docsrs, doc(cfg(feature = "full")))]396pub use crate::file::File;397398#[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))]399mod fixup;400401#[cfg(any(feature = "full", feature = "derive"))]402mod generics;403#[cfg(any(feature = "full", feature = "derive"))]404#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]405pub use crate::generics::{406BoundLifetimes, ConstParam, GenericParam, Generics, LifetimeParam, PredicateLifetime,407PredicateType, TraitBound, TraitBoundModifier, TypeParam, TypeParamBound, WhereClause,408WherePredicate,409};410#[cfg(feature = "full")]411#[cfg_attr(docsrs, doc(cfg(feature = "full")))]412pub use crate::generics::{CapturedParam, PreciseCapture};413#[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))]414#[cfg_attr(415docsrs,416doc(cfg(all(any(feature = "full", feature = "derive"), feature = "printing")))417)]418pub use crate::generics::{ImplGenerics, Turbofish, TypeGenerics};419420mod ident;421#[doc(inline)]422pub use crate::ident::Ident;423424#[cfg(feature = "full")]425mod item;426#[cfg(feature = "full")]427#[cfg_attr(docsrs, doc(cfg(feature = "full")))]428pub use crate::item::{429FnArg, ForeignItem, ForeignItemFn, ForeignItemMacro, ForeignItemStatic, ForeignItemType,430ImplItem, ImplItemConst, ImplItemFn, ImplItemMacro, ImplItemType, ImplRestriction, Item,431ItemConst, ItemEnum, ItemExternCrate, ItemFn, ItemForeignMod, ItemImpl, ItemMacro, ItemMod,432ItemStatic, ItemStruct, ItemTrait, ItemTraitAlias, ItemType, ItemUnion, ItemUse, Receiver,433Signature, StaticMutability, TraitItem, TraitItemConst, TraitItemFn, TraitItemMacro,434TraitItemType, UseGlob, UseGroup, UseName, UsePath, UseRename, UseTree, Variadic,435};436437mod lifetime;438#[doc(inline)]439pub use crate::lifetime::Lifetime;440441mod lit;442#[doc(hidden)] // https://github.com/dtolnay/syn/issues/1566443pub use crate::lit::StrStyle;444#[doc(inline)]445pub use crate::lit::{446Lit, LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitInt, LitStr,447};448449#[cfg(feature = "parsing")]450mod lookahead;451452#[cfg(any(feature = "full", feature = "derive"))]453mod mac;454#[cfg(any(feature = "full", feature = "derive"))]455#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]456pub use crate::mac::{Macro, MacroDelimiter};457458#[cfg(all(feature = "parsing", any(feature = "full", feature = "derive")))]459#[cfg_attr(460docsrs,461doc(cfg(all(feature = "parsing", any(feature = "full", feature = "derive"))))462)]463pub mod meta;464465#[cfg(any(feature = "full", feature = "derive"))]466mod op;467#[cfg(any(feature = "full", feature = "derive"))]468#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]469pub use crate::op::{BinOp, UnOp};470471#[cfg(feature = "parsing")]472#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]473pub mod parse;474475#[cfg(all(feature = "parsing", feature = "proc-macro"))]476mod parse_macro_input;477478#[cfg(all(feature = "parsing", feature = "printing"))]479mod parse_quote;480481#[cfg(feature = "full")]482mod pat;483#[cfg(feature = "full")]484#[cfg_attr(docsrs, doc(cfg(feature = "full")))]485pub use crate::pat::{486FieldPat, Pat, PatConst, PatIdent, PatLit, PatMacro, PatOr, PatParen, PatPath, PatRange,487PatReference, PatRest, PatSlice, PatStruct, PatTuple, PatTupleStruct, PatType, PatWild,488};489490#[cfg(any(feature = "full", feature = "derive"))]491mod path;492#[cfg(any(feature = "full", feature = "derive"))]493#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]494pub use crate::path::{495AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, GenericArgument,496ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf,497};498499#[cfg(all(500any(feature = "full", feature = "derive"),501any(feature = "parsing", feature = "printing")502))]503mod precedence;504505#[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))]506mod print;507508pub mod punctuated;509510#[cfg(any(feature = "full", feature = "derive"))]511mod restriction;512#[cfg(any(feature = "full", feature = "derive"))]513#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]514pub use crate::restriction::{FieldMutability, VisRestricted, Visibility};515516mod sealed;517518#[cfg(all(feature = "parsing", feature = "derive", not(feature = "full")))]519mod scan_expr;520521mod span;522523#[cfg(all(feature = "parsing", feature = "printing"))]524#[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))]525pub mod spanned;526527#[cfg(feature = "full")]528mod stmt;529#[cfg(feature = "full")]530#[cfg_attr(docsrs, doc(cfg(feature = "full")))]531pub use crate::stmt::{Block, Local, LocalInit, Stmt, StmtMacro};532533mod thread;534535#[cfg(all(any(feature = "full", feature = "derive"), feature = "extra-traits"))]536mod tt;537538#[cfg(any(feature = "full", feature = "derive"))]539mod ty;540#[cfg(any(feature = "full", feature = "derive"))]541#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]542pub use crate::ty::{543Abi, BareFnArg, BareVariadic, ReturnType, Type, TypeArray, TypeBareFn, TypeGroup,544TypeImplTrait, TypeInfer, TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, TypeReference,545TypeSlice, TypeTraitObject, TypeTuple,546};547548#[cfg(all(any(feature = "full", feature = "derive"), feature = "parsing"))]549mod verbatim;550551#[cfg(all(feature = "parsing", feature = "full"))]552mod whitespace;553554#[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/6176555mod gen {556/// Syntax tree traversal to transform the nodes of an owned syntax tree.557///558/// Each method of the [`Fold`] trait is a hook that can be overridden to559/// customize the behavior when transforming the corresponding type of node.560/// By default, every method recursively visits the substructure of the561/// input by invoking the right visitor method of each of its fields.562///563/// [`Fold`]: fold::Fold564///565/// ```566/// # use syn::{Attribute, BinOp, Expr, ExprBinary};567/// #568/// pub trait Fold {569/// /* ... */570///571/// fn fold_expr_binary(&mut self, node: ExprBinary) -> ExprBinary {572/// fold_expr_binary(self, node)573/// }574///575/// /* ... */576/// # fn fold_attribute(&mut self, node: Attribute) -> Attribute;577/// # fn fold_expr(&mut self, node: Expr) -> Expr;578/// # fn fold_bin_op(&mut self, node: BinOp) -> BinOp;579/// }580///581/// pub fn fold_expr_binary<V>(v: &mut V, node: ExprBinary) -> ExprBinary582/// where583/// V: Fold + ?Sized,584/// {585/// ExprBinary {586/// attrs: node587/// .attrs588/// .into_iter()589/// .map(|attr| v.fold_attribute(attr))590/// .collect(),591/// left: Box::new(v.fold_expr(*node.left)),592/// op: v.fold_bin_op(node.op),593/// right: Box::new(v.fold_expr(*node.right)),594/// }595/// }596///597/// /* ... */598/// ```599///600/// <br>601///602/// # Example603///604/// This fold inserts parentheses to fully parenthesizes any expression.605///606/// ```607/// // [dependencies]608/// // quote = "1.0"609/// // syn = { version = "2.0", features = ["fold", "full"] }610///611/// use quote::quote;612/// use syn::fold::{fold_expr, Fold};613/// use syn::{token, Expr, ExprParen};614///615/// struct ParenthesizeEveryExpr;616///617/// impl Fold for ParenthesizeEveryExpr {618/// fn fold_expr(&mut self, expr: Expr) -> Expr {619/// Expr::Paren(ExprParen {620/// attrs: Vec::new(),621/// expr: Box::new(fold_expr(self, expr)),622/// paren_token: token::Paren::default(),623/// })624/// }625/// }626///627/// fn main() {628/// let code = quote! { a() + b(1) * c.d };629/// let expr: Expr = syn::parse2(code).unwrap();630/// let parenthesized = ParenthesizeEveryExpr.fold_expr(expr);631/// println!("{}", quote!(#parenthesized));632///633/// // Output: (((a)()) + (((b)((1))) * ((c).d)))634/// }635/// ```636#[cfg(feature = "fold")]637#[cfg_attr(docsrs, doc(cfg(feature = "fold")))]638#[rustfmt::skip]639pub mod fold;640641/// Syntax tree traversal to walk a shared borrow of a syntax tree.642///643/// Each method of the [`Visit`] trait is a hook that can be overridden to644/// customize the behavior when visiting the corresponding type of node. By645/// default, every method recursively visits the substructure of the input646/// by invoking the right visitor method of each of its fields.647///648/// [`Visit`]: visit::Visit649///650/// ```651/// # use syn::{Attribute, BinOp, Expr, ExprBinary};652/// #653/// pub trait Visit<'ast> {654/// /* ... */655///656/// fn visit_expr_binary(&mut self, node: &'ast ExprBinary) {657/// visit_expr_binary(self, node);658/// }659///660/// /* ... */661/// # fn visit_attribute(&mut self, node: &'ast Attribute);662/// # fn visit_expr(&mut self, node: &'ast Expr);663/// # fn visit_bin_op(&mut self, node: &'ast BinOp);664/// }665///666/// pub fn visit_expr_binary<'ast, V>(v: &mut V, node: &'ast ExprBinary)667/// where668/// V: Visit<'ast> + ?Sized,669/// {670/// for attr in &node.attrs {671/// v.visit_attribute(attr);672/// }673/// v.visit_expr(&*node.left);674/// v.visit_bin_op(&node.op);675/// v.visit_expr(&*node.right);676/// }677///678/// /* ... */679/// ```680///681/// <br>682///683/// # Example684///685/// This visitor will print the name of every freestanding function in the686/// syntax tree, including nested functions.687///688/// ```689/// // [dependencies]690/// // quote = "1.0"691/// // syn = { version = "2.0", features = ["full", "visit"] }692///693/// use quote::quote;694/// use syn::visit::{self, Visit};695/// use syn::{File, ItemFn};696///697/// struct FnVisitor;698///699/// impl<'ast> Visit<'ast> for FnVisitor {700/// fn visit_item_fn(&mut self, node: &'ast ItemFn) {701/// println!("Function with name={}", node.sig.ident);702///703/// // Delegate to the default impl to visit any nested functions.704/// visit::visit_item_fn(self, node);705/// }706/// }707///708/// fn main() {709/// let code = quote! {710/// pub fn f() {711/// fn g() {}712/// }713/// };714///715/// let syntax_tree: File = syn::parse2(code).unwrap();716/// FnVisitor.visit_file(&syntax_tree);717/// }718/// ```719///720/// The `'ast` lifetime on the input references means that the syntax tree721/// outlives the complete recursive visit call, so the visitor is allowed to722/// hold on to references into the syntax tree.723///724/// ```725/// use quote::quote;726/// use syn::visit::{self, Visit};727/// use syn::{File, ItemFn};728///729/// struct FnVisitor<'ast> {730/// functions: Vec<&'ast ItemFn>,731/// }732///733/// impl<'ast> Visit<'ast> for FnVisitor<'ast> {734/// fn visit_item_fn(&mut self, node: &'ast ItemFn) {735/// self.functions.push(node);736/// visit::visit_item_fn(self, node);737/// }738/// }739///740/// fn main() {741/// let code = quote! {742/// pub fn f() {743/// fn g() {}744/// }745/// };746///747/// let syntax_tree: File = syn::parse2(code).unwrap();748/// let mut visitor = FnVisitor { functions: Vec::new() };749/// visitor.visit_file(&syntax_tree);750/// for f in visitor.functions {751/// println!("Function with name={}", f.sig.ident);752/// }753/// }754/// ```755#[cfg(feature = "visit")]756#[cfg_attr(docsrs, doc(cfg(feature = "visit")))]757#[rustfmt::skip]758pub mod visit;759760/// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in761/// place.762///763/// Each method of the [`VisitMut`] trait is a hook that can be overridden764/// to customize the behavior when mutating the corresponding type of node.765/// By default, every method recursively visits the substructure of the766/// input by invoking the right visitor method of each of its fields.767///768/// [`VisitMut`]: visit_mut::VisitMut769///770/// ```771/// # use syn::{Attribute, BinOp, Expr, ExprBinary};772/// #773/// pub trait VisitMut {774/// /* ... */775///776/// fn visit_expr_binary_mut(&mut self, node: &mut ExprBinary) {777/// visit_expr_binary_mut(self, node);778/// }779///780/// /* ... */781/// # fn visit_attribute_mut(&mut self, node: &mut Attribute);782/// # fn visit_expr_mut(&mut self, node: &mut Expr);783/// # fn visit_bin_op_mut(&mut self, node: &mut BinOp);784/// }785///786/// pub fn visit_expr_binary_mut<V>(v: &mut V, node: &mut ExprBinary)787/// where788/// V: VisitMut + ?Sized,789/// {790/// for attr in &mut node.attrs {791/// v.visit_attribute_mut(attr);792/// }793/// v.visit_expr_mut(&mut *node.left);794/// v.visit_bin_op_mut(&mut node.op);795/// v.visit_expr_mut(&mut *node.right);796/// }797///798/// /* ... */799/// ```800///801/// <br>802///803/// # Example804///805/// This mut visitor replace occurrences of u256 suffixed integer literals806/// like `999u256` with a macro invocation `bigint::u256!(999)`.807///808/// ```809/// // [dependencies]810/// // quote = "1.0"811/// // syn = { version = "2.0", features = ["full", "visit-mut"] }812///813/// use quote::quote;814/// use syn::visit_mut::{self, VisitMut};815/// use syn::{parse_quote, Expr, File, Lit, LitInt};816///817/// struct BigintReplace;818///819/// impl VisitMut for BigintReplace {820/// fn visit_expr_mut(&mut self, node: &mut Expr) {821/// if let Expr::Lit(expr) = &node {822/// if let Lit::Int(int) = &expr.lit {823/// if int.suffix() == "u256" {824/// let digits = int.base10_digits();825/// let unsuffixed: LitInt = syn::parse_str(digits).unwrap();826/// *node = parse_quote!(bigint::u256!(#unsuffixed));827/// return;828/// }829/// }830/// }831///832/// // Delegate to the default impl to visit nested expressions.833/// visit_mut::visit_expr_mut(self, node);834/// }835/// }836///837/// fn main() {838/// let code = quote! {839/// fn main() {840/// let _ = 999u256;841/// }842/// };843///844/// let mut syntax_tree: File = syn::parse2(code).unwrap();845/// BigintReplace.visit_file_mut(&mut syntax_tree);846/// println!("{}", quote!(#syntax_tree));847/// }848/// ```849#[cfg(feature = "visit-mut")]850#[cfg_attr(docsrs, doc(cfg(feature = "visit-mut")))]851#[rustfmt::skip]852pub mod visit_mut;853854#[cfg(feature = "clone-impls")]855#[rustfmt::skip]856mod clone;857858#[cfg(feature = "extra-traits")]859#[rustfmt::skip]860mod debug;861862#[cfg(feature = "extra-traits")]863#[rustfmt::skip]864mod eq;865866#[cfg(feature = "extra-traits")]867#[rustfmt::skip]868mod hash;869}870871#[cfg(feature = "fold")]872#[cfg_attr(docsrs, doc(cfg(feature = "fold")))]873pub use crate::gen::fold;874875#[cfg(feature = "visit")]876#[cfg_attr(docsrs, doc(cfg(feature = "visit")))]877pub use crate::gen::visit;878879#[cfg(feature = "visit-mut")]880#[cfg_attr(docsrs, doc(cfg(feature = "visit-mut")))]881pub use crate::gen::visit_mut;882883// Not public API.884#[doc(hidden)]885#[path = "export.rs"]886pub mod __private;887888/// Parse tokens of source code into the chosen syntax tree node.889///890/// This is preferred over parsing a string because tokens are able to preserve891/// information about where in the user's code they were originally written (the892/// "span" of the token), possibly allowing the compiler to produce better error893/// messages.894///895/// This function parses a `proc_macro::TokenStream` which is the type used for896/// interop with the compiler in a procedural macro. To parse a897/// `proc_macro2::TokenStream`, use [`syn::parse2`] instead.898///899/// [`syn::parse2`]: parse2900///901/// This function enforces that the input is fully parsed. If there are any902/// unparsed tokens at the end of the stream, an error is returned.903#[cfg(all(feature = "parsing", feature = "proc-macro"))]904#[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "proc-macro"))))]905pub fn parse<T: parse::Parse>(tokens: proc_macro::TokenStream) -> Result<T> {906parse::Parser::parse(T::parse, tokens)907}908909/// Parse a proc-macro2 token stream into the chosen syntax tree node.910///911/// This function parses a `proc_macro2::TokenStream` which is commonly useful912/// when the input comes from a node of the Syn syntax tree, for example the913/// body tokens of a [`Macro`] node. When in a procedural macro parsing the914/// `proc_macro::TokenStream` provided by the compiler, use [`syn::parse`]915/// instead.916///917/// [`syn::parse`]: parse()918///919/// This function enforces that the input is fully parsed. If there are any920/// unparsed tokens at the end of the stream, an error is returned.921#[cfg(feature = "parsing")]922#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]923pub fn parse2<T: parse::Parse>(tokens: proc_macro2::TokenStream) -> Result<T> {924parse::Parser::parse2(T::parse, tokens)925}926927/// Parse a string of Rust code into the chosen syntax tree node.928///929/// This function enforces that the input is fully parsed. If there are any930/// unparsed tokens at the end of the stream, an error is returned.931///932/// # Hygiene933///934/// Every span in the resulting syntax tree will be set to resolve at the macro935/// call site.936///937/// # Examples938///939/// ```940/// use syn::{Expr, Result};941///942/// fn run() -> Result<()> {943/// let code = "assert_eq!(u8::max_value(), 255)";944/// let expr = syn::parse_str::<Expr>(code)?;945/// println!("{:#?}", expr);946/// Ok(())947/// }948/// #949/// # run().unwrap();950/// ```951#[cfg(feature = "parsing")]952#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]953pub fn parse_str<T: parse::Parse>(s: &str) -> Result<T> {954parse::Parser::parse_str(T::parse, s)955}956957/// Parse the content of a file of Rust code.958///959/// This is different from `syn::parse_str::<File>(content)` in two ways:960///961/// - It discards a leading byte order mark `\u{FEFF}` if the file has one.962/// - It preserves the shebang line of the file, such as `#!/usr/bin/env rustx`.963///964/// If present, either of these would be an error using `from_str`.965///966/// # Examples967///968/// ```no_run969/// use std::error::Error;970/// use std::fs;971/// use std::io::Read;972///973/// fn run() -> Result<(), Box<dyn Error>> {974/// let content = fs::read_to_string("path/to/code.rs")?;975/// let ast = syn::parse_file(&content)?;976/// if let Some(shebang) = ast.shebang {977/// println!("{}", shebang);978/// }979/// println!("{} items", ast.items.len());980///981/// Ok(())982/// }983/// #984/// # run().unwrap();985/// ```986#[cfg(all(feature = "parsing", feature = "full"))]987#[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "full"))))]988pub fn parse_file(mut content: &str) -> Result<File> {989// Strip the BOM if it is present990const BOM: &str = "\u{feff}";991if content.starts_with(BOM) {992content = &content[BOM.len()..];993}994995let mut shebang = None;996if content.starts_with("#!") {997let rest = whitespace::skip(&content[2..]);998if !rest.starts_with('[') {999if let Some(idx) = content.find('\n') {1000shebang = Some(content[..idx].to_string());1001content = &content[idx..];1002} else {1003shebang = Some(content.to_string());1004content = "";1005}1006}1007}10081009let mut file: File = parse_str(content)?;1010file.shebang = shebang;1011Ok(file)1012}101310141015