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"))))] 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")))] 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")))] 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"))))] 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