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