//! [![github]](https://github.com/dtolnay/syn) [![crates-io]](https://crates.io/crates/syn) [![docs-rs]](crate) //! //! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github //! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust //! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs //! //! <br> //! //! Syn is a parsing library for parsing a stream of Rust tokens into a syntax //! tree of Rust source code. //! //! Currently this library is geared toward use in Rust procedural macros, but //! contains some APIs that may be useful more generally. //! //! - **Data structures** — Syn provides a complete syntax tree that can //! represent any valid Rust source code. The syntax tree is rooted at //! [`syn::File`] which represents a full source file, but there are other //! entry points that may be useful to procedural macros including //! [`syn::Item`], [`syn::Expr`] and [`syn::Type`]. //! //! - **Derives** — Of particular interest to derive macros is //! [`syn::DeriveInput`] which is any of the three legal input items to a //! derive macro. An example below shows using this type in a library that can //! derive implementations of a user-defined trait. //! //! - **Parsing** — Parsing in Syn is built around [parser functions] with the //! signature `fn(ParseStream) -> Result<T>`. Every syntax tree node defined //! by Syn is individually parsable and may be used as a building block for //! custom syntaxes, or you may dream up your own brand new syntax without //! involving any of our syntax tree types. //! //! - **Location information** — Every token parsed by Syn is associated with a //! `Span` that tracks line and column information back to the source of that //! token. These spans allow a procedural macro to display detailed error //! messages pointing to all the right places in the user's code. There is an //! example of this below. //! //! - **Feature flags** — Functionality is aggressively feature gated so your //! procedural macros enable only what they need, and do not pay in compile //! time for all the rest. //! //! [`syn::File`]: File //! [`syn::Item`]: Item //! [`syn::Expr`]: Expr //! [`syn::Type`]: Type //! [`syn::DeriveInput`]: DeriveInput //! [parser functions]: mod@parse //! //! <br> //! //! # Example of a derive macro //! //! The canonical derive macro using Syn looks like this. We write an ordinary //! Rust function tagged with a `proc_macro_derive` attribute and the name of //! the trait we are deriving. Any time that derive appears in the user's code, //! the Rust compiler passes their data structure as tokens into our macro. We //! get to execute arbitrary Rust code to figure out what to do with those //! tokens, then hand some tokens back to the compiler to compile into the //! user's crate. //! //! [`TokenStream`]: proc_macro::TokenStream //! //! ```toml //! [dependencies] //! syn = "2.0" //! quote = "1.0" //! //! [lib] //! proc-macro = true //! ``` //! //! ``` //! # extern crate proc_macro; //! # //! use proc_macro::TokenStream; //! use quote::quote; //! use syn::{parse_macro_input, DeriveInput}; //! //! # const IGNORE_TOKENS: &str = stringify! { //! #[proc_macro_derive(MyMacro)] //! # }; //! pub fn my_macro(input: TokenStream) -> TokenStream { //! // Parse the input tokens into a syntax tree //! let input = parse_macro_input!(input as DeriveInput); //! //! // Build the output, possibly using quasi-quotation //! let expanded = quote! { //! // ... //! }; //! //! // Hand the output tokens back to the compiler //! TokenStream::from(expanded) //! } //! ``` //! //! The [`heapsize`] example directory shows a complete working implementation //! of a derive macro. The example derives a `HeapSize` trait which computes an //! estimate of the amount of heap memory owned by a value. //! //! [`heapsize`]: https://github.com/dtolnay/syn/tree/master/examples/heapsize //! //! ``` //! pub trait HeapSize { //! /// Total number of bytes of heap memory owned by `self`. //! fn heap_size_of_children(&self) -> usize; //! } //! ``` //! //! The derive macro allows users to write `#[derive(HeapSize)]` on data //! structures in their program. //! //! ``` //! # const IGNORE_TOKENS: &str = stringify! { //! #[derive(HeapSize)] //! # }; //! struct Demo<'a, T: ?Sized> { //! a: Box<T>, //! b: u8, //! c: &'a str, //! d: String, //! } //! ``` //! //! <p><br></p> //! //! # Spans and error reporting //! //! The token-based procedural macro API provides great control over where the //! compiler's error messages are displayed in user code. Consider the error the //! user sees if one of their field types does not implement `HeapSize`. //! //! ``` //! # const IGNORE_TOKENS: &str = stringify! { //! #[derive(HeapSize)] //! # }; //! struct Broken { //! ok: String, //! bad: std::thread::Thread, //! } //! ``` //! //! By tracking span information all the way through the expansion of a //! procedural macro as shown in the `heapsize` example, token-based macros in //! Syn are able to trigger errors that directly pinpoint the source of the //! problem. //! //! ```text //! error[E0277]: the trait bound `std::thread::Thread: HeapSize` is not satisfied //! --> src/main.rs:7:5 //! | //! 7 | bad: std::thread::Thread, //! | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HeapSize` is not implemented for `Thread` //! ``` //! //! <br> //! //! # Parsing a custom syntax //! //! The [`lazy-static`] example directory shows the implementation of a //! `functionlike!(...)` procedural macro in which the input tokens are parsed //! using Syn's parsing API. //! //! [`lazy-static`]: https://github.com/dtolnay/syn/tree/master/examples/lazy-static //! //! The example reimplements the popular `lazy_static` crate from crates.io as a //! procedural macro. //! //! ``` //! # macro_rules! lazy_static { //! # ($($tt:tt)*) => {} //! # } //! # //! lazy_static! { //! static ref USERNAME: Regex = Regex::new("^[a-z0-9_-]{3,16}$").unwrap(); //! } //! ``` //! //! The implementation shows how to trigger custom warnings and error messages //! on the macro input. //! //! ```text //! warning: come on, pick a more creative name //! --> src/main.rs:10:16 //! | //! 10 | static ref FOO: String = "lazy_static".to_owned(); //! | ^^^ //! ``` //! //! <br> //! //! # Testing //! //! When testing macros, we often care not just that the macro can be used //! successfully but also that when the macro is provided with invalid input it //! produces maximally helpful error messages. Consider using the [`trybuild`] //! crate to write tests for errors that are emitted by your macro or errors //! detected by the Rust compiler in the expanded code following misuse of the //! macro. Such tests help avoid regressions from later refactors that //! mistakenly make an error no longer trigger or be less helpful than it used //! to be. //! //! [`trybuild`]: https://github.com/dtolnay/trybuild //! //! <br> //! //! # Debugging //! //! When developing a procedural macro it can be helpful to look at what the //! generated code looks like. Use `cargo rustc -- -Zunstable-options //! --pretty=expanded` or the [`cargo expand`] subcommand. //! //! [`cargo expand`]: https://github.com/dtolnay/cargo-expand //! //! To show the expanded code for some crate that uses your procedural macro, //! run `cargo expand` from that crate. To show the expanded code for one of //! your own test cases, run `cargo expand --test the_test_case` where the last //! argument is the name of the test file without the `.rs` extension. //! //! This write-up by Brandon W Maister discusses debugging in more detail: //! [Debugging Rust's new Custom Derive system][debugging]. //! //! [debugging]: https://quodlibetor.github.io/posts/debugging-rusts-new-custom-derive-system/ //! //! <br> //! //! # Optional features //! //! Syn puts a lot of functionality behind optional features in order to //! optimize compile time for the most common use cases. The following features //! are available. //! //! - **`derive`** *(enabled by default)* — Data structures for representing the //! possible input to a derive macro, including structs and enums and types. //! - **`full`** — Data structures for representing the syntax tree of all valid //! Rust source code, including items and expressions. //! - **`parsing`** *(enabled by default)* — Ability to parse input tokens into //! a syntax tree node of a chosen type. //! - **`printing`** *(enabled by default)* — Ability to print a syntax tree //! node as tokens of Rust source code. //! - **`visit`** — Trait for traversing a syntax tree. //! - **`visit-mut`** — Trait for traversing and mutating in place a syntax //! tree. //! - **`fold`** — Trait for transforming an owned syntax tree. //! - **`clone-impls`** *(enabled by default)* — Clone impls for all syntax tree //! types. //! - **`extra-traits`** — Debug, Eq, PartialEq, Hash impls for all syntax tree //! types. //! - **`proc-macro`** *(enabled by default)* — Runtime dependency on the //! dynamic library libproc_macro from rustc toolchain.
// Not public API. #[doc(hidden)] #[path = "export.rs"] pubmod __private;
/// Parse tokens of source code into the chosen syntax tree node. /// /// This is preferred over parsing a string because tokens are able to preserve /// information about where in the user's code they were originally written (the /// "span" of the token), possibly allowing the compiler to produce better error /// messages. /// /// This function parses a `proc_macro::TokenStream` which is the type used for /// interop with the compiler in a procedural macro. To parse a /// `proc_macro2::TokenStream`, use [`syn::parse2`] instead. /// /// [`syn::parse2`]: parse2 /// /// This function enforces that the input is fully parsed. If there are any /// unparsed tokens at the end of the stream, an error is returned. #[cfg(all(feature = "parsing", feature = "proc-macro"))] #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "proc-macro"))))] pubfn parse<T: parse::Parse>(tokens: proc_macro::TokenStream) -> Result<T> {
parse::Parser::parse(T::parse, tokens)
}
/// Parse a proc-macro2 token stream into the chosen syntax tree node. /// /// This function parses a `proc_macro2::TokenStream` which is commonly useful /// when the input comes from a node of the Syn syntax tree, for example the /// body tokens of a [`Macro`] node. When in a procedural macro parsing the /// `proc_macro::TokenStream` provided by the compiler, use [`syn::parse`] /// instead. /// /// [`syn::parse`]: parse() /// /// This function enforces that the input is fully parsed. If there are any /// unparsed tokens at the end of the stream, an error is returned. #[cfg(feature = "parsing")] #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] pubfn parse2<T: parse::Parse>(tokens: proc_macro2::TokenStream) -> Result<T> {
parse::Parser::parse2(T::parse, tokens)
}
/// Parse a string of Rust code into the chosen syntax tree node. /// /// This function enforces that the input is fully parsed. If there are any /// unparsed tokens at the end of the stream, an error is returned. /// /// # Hygiene /// /// Every span in the resulting syntax tree will be set to resolve at the macro /// call site. /// /// # Examples /// /// ``` /// use syn::{Expr, Result}; /// /// fn run() -> Result<()> { /// let code = "assert_eq!(u8::max_value(), 255)"; /// let expr = syn::parse_str::<Expr>(code)?; /// println!("{:#?}", expr); /// Ok(()) /// } /// # /// # run().unwrap(); /// ``` #[cfg(feature = "parsing")] #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] pubfn parse_str<T: parse::Parse>(s: &str) -> Result<T> {
parse::Parser::parse_str(T::parse, s)
}
/// Parse the content of a file of Rust code. /// /// This is different from `syn::parse_str::<File>(content)` in two ways: /// /// - It discards a leading byte order mark `\u{FEFF}` if the file has one. /// - It preserves the shebang line of the file, such as `#!/usr/bin/env rustx`. /// /// If present, either of these would be an error using `from_str`. /// /// # Examples /// /// ```no_run /// use std::error::Error; /// use std::fs; /// use std::io::Read; /// /// fn run() -> Result<(), Box<dyn Error>> { /// let content = fs::read_to_string("path/to/code.rs")?; /// let ast = syn::parse_file(&content)?; /// if let Some(shebang) = ast.shebang { /// println!("{}", shebang); /// } /// println!("{} items", ast.items.len()); /// /// Ok(()) /// } /// # /// # run().unwrap(); /// ``` #[cfg(all(feature = "parsing", feature = "full"))] #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "full"))))] pubfn parse_file(mut content: &str) -> Result<File> { // Strip the BOM if it is present const BOM: &str = "\u{feff}"; if content.starts_with(BOM) {
content = &content[BOM.len()..];
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.