1fad3a1d3Sopenharmony_ciParser for Rust source code 2fad3a1d3Sopenharmony_ci=========================== 3fad3a1d3Sopenharmony_ci 4fad3a1d3Sopenharmony_ci[<img alt="github" src="https://img.shields.io/badge/github-dtolnay/syn-8da0cb?style=for-the-badge&labelColor=555555&logo=github" height="20">](https://github.com/dtolnay/syn) 5fad3a1d3Sopenharmony_ci[<img alt="crates.io" src="https://img.shields.io/crates/v/syn.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/syn) 6fad3a1d3Sopenharmony_ci[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-syn-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs" height="20">](https://docs.rs/syn) 7fad3a1d3Sopenharmony_ci[<img alt="build status" src="https://img.shields.io/github/actions/workflow/status/dtolnay/syn/ci.yml?branch=master&style=for-the-badge" height="20">](https://github.com/dtolnay/syn/actions?query=branch%3Amaster) 8fad3a1d3Sopenharmony_ci 9fad3a1d3Sopenharmony_ciSyn is a parsing library for parsing a stream of Rust tokens into a syntax tree 10fad3a1d3Sopenharmony_ciof Rust source code. 11fad3a1d3Sopenharmony_ci 12fad3a1d3Sopenharmony_ciCurrently this library is geared toward use in Rust procedural macros, but 13fad3a1d3Sopenharmony_cicontains some APIs that may be useful more generally. 14fad3a1d3Sopenharmony_ci 15fad3a1d3Sopenharmony_ci- **Data structures** — Syn provides a complete syntax tree that can represent 16fad3a1d3Sopenharmony_ci any valid Rust source code. The syntax tree is rooted at [`syn::File`] which 17fad3a1d3Sopenharmony_ci represents a full source file, but there are other entry points that may be 18fad3a1d3Sopenharmony_ci useful to procedural macros including [`syn::Item`], [`syn::Expr`] and 19fad3a1d3Sopenharmony_ci [`syn::Type`]. 20fad3a1d3Sopenharmony_ci 21fad3a1d3Sopenharmony_ci- **Derives** — Of particular interest to derive macros is [`syn::DeriveInput`] 22fad3a1d3Sopenharmony_ci which is any of the three legal input items to a derive macro. An example 23fad3a1d3Sopenharmony_ci below shows using this type in a library that can derive implementations of a 24fad3a1d3Sopenharmony_ci user-defined trait. 25fad3a1d3Sopenharmony_ci 26fad3a1d3Sopenharmony_ci- **Parsing** — Parsing in Syn is built around [parser functions] with the 27fad3a1d3Sopenharmony_ci signature `fn(ParseStream) -> Result<T>`. Every syntax tree node defined by 28fad3a1d3Sopenharmony_ci Syn is individually parsable and may be used as a building block for custom 29fad3a1d3Sopenharmony_ci syntaxes, or you may dream up your own brand new syntax without involving any 30fad3a1d3Sopenharmony_ci of our syntax tree types. 31fad3a1d3Sopenharmony_ci 32fad3a1d3Sopenharmony_ci- **Location information** — Every token parsed by Syn is associated with a 33fad3a1d3Sopenharmony_ci `Span` that tracks line and column information back to the source of that 34fad3a1d3Sopenharmony_ci token. These spans allow a procedural macro to display detailed error messages 35fad3a1d3Sopenharmony_ci pointing to all the right places in the user's code. There is an example of 36fad3a1d3Sopenharmony_ci this below. 37fad3a1d3Sopenharmony_ci 38fad3a1d3Sopenharmony_ci- **Feature flags** — Functionality is aggressively feature gated so your 39fad3a1d3Sopenharmony_ci procedural macros enable only what they need, and do not pay in compile time 40fad3a1d3Sopenharmony_ci for all the rest. 41fad3a1d3Sopenharmony_ci 42fad3a1d3Sopenharmony_ci[`syn::File`]: https://docs.rs/syn/2.0/syn/struct.File.html 43fad3a1d3Sopenharmony_ci[`syn::Item`]: https://docs.rs/syn/2.0/syn/enum.Item.html 44fad3a1d3Sopenharmony_ci[`syn::Expr`]: https://docs.rs/syn/2.0/syn/enum.Expr.html 45fad3a1d3Sopenharmony_ci[`syn::Type`]: https://docs.rs/syn/2.0/syn/enum.Type.html 46fad3a1d3Sopenharmony_ci[`syn::DeriveInput`]: https://docs.rs/syn/2.0/syn/struct.DeriveInput.html 47fad3a1d3Sopenharmony_ci[parser functions]: https://docs.rs/syn/2.0/syn/parse/index.html 48fad3a1d3Sopenharmony_ci 49fad3a1d3Sopenharmony_ci*Version requirement: Syn supports rustc 1.56 and up.* 50fad3a1d3Sopenharmony_ci 51fad3a1d3Sopenharmony_ci[*Release notes*](https://github.com/dtolnay/syn/releases) 52fad3a1d3Sopenharmony_ci 53fad3a1d3Sopenharmony_ci<br> 54fad3a1d3Sopenharmony_ci 55fad3a1d3Sopenharmony_ci## Resources 56fad3a1d3Sopenharmony_ci 57fad3a1d3Sopenharmony_ciThe best way to learn about procedural macros is by writing some. Consider 58fad3a1d3Sopenharmony_ciworking through [this procedural macro workshop][workshop] to get familiar with 59fad3a1d3Sopenharmony_cithe different types of procedural macros. The workshop contains relevant links 60fad3a1d3Sopenharmony_ciinto the Syn documentation as you work through each project. 61fad3a1d3Sopenharmony_ci 62fad3a1d3Sopenharmony_ci[workshop]: https://github.com/dtolnay/proc-macro-workshop 63fad3a1d3Sopenharmony_ci 64fad3a1d3Sopenharmony_ci<br> 65fad3a1d3Sopenharmony_ci 66fad3a1d3Sopenharmony_ci## Example of a derive macro 67fad3a1d3Sopenharmony_ci 68fad3a1d3Sopenharmony_ciThe canonical derive macro using Syn looks like this. We write an ordinary Rust 69fad3a1d3Sopenharmony_cifunction tagged with a `proc_macro_derive` attribute and the name of the trait 70fad3a1d3Sopenharmony_ciwe are deriving. Any time that derive appears in the user's code, the Rust 71fad3a1d3Sopenharmony_cicompiler passes their data structure as tokens into our macro. We get to execute 72fad3a1d3Sopenharmony_ciarbitrary Rust code to figure out what to do with those tokens, then hand some 73fad3a1d3Sopenharmony_citokens back to the compiler to compile into the user's crate. 74fad3a1d3Sopenharmony_ci 75fad3a1d3Sopenharmony_ci[`TokenStream`]: https://doc.rust-lang.org/proc_macro/struct.TokenStream.html 76fad3a1d3Sopenharmony_ci 77fad3a1d3Sopenharmony_ci```toml 78fad3a1d3Sopenharmony_ci[dependencies] 79fad3a1d3Sopenharmony_cisyn = "2.0" 80fad3a1d3Sopenharmony_ciquote = "1.0" 81fad3a1d3Sopenharmony_ci 82fad3a1d3Sopenharmony_ci[lib] 83fad3a1d3Sopenharmony_ciproc-macro = true 84fad3a1d3Sopenharmony_ci``` 85fad3a1d3Sopenharmony_ci 86fad3a1d3Sopenharmony_ci```rust 87fad3a1d3Sopenharmony_ciuse proc_macro::TokenStream; 88fad3a1d3Sopenharmony_ciuse quote::quote; 89fad3a1d3Sopenharmony_ciuse syn::{parse_macro_input, DeriveInput}; 90fad3a1d3Sopenharmony_ci 91fad3a1d3Sopenharmony_ci#[proc_macro_derive(MyMacro)] 92fad3a1d3Sopenharmony_cipub fn my_macro(input: TokenStream) -> TokenStream { 93fad3a1d3Sopenharmony_ci // Parse the input tokens into a syntax tree 94fad3a1d3Sopenharmony_ci let input = parse_macro_input!(input as DeriveInput); 95fad3a1d3Sopenharmony_ci 96fad3a1d3Sopenharmony_ci // Build the output, possibly using quasi-quotation 97fad3a1d3Sopenharmony_ci let expanded = quote! { 98fad3a1d3Sopenharmony_ci // ... 99fad3a1d3Sopenharmony_ci }; 100fad3a1d3Sopenharmony_ci 101fad3a1d3Sopenharmony_ci // Hand the output tokens back to the compiler 102fad3a1d3Sopenharmony_ci TokenStream::from(expanded) 103fad3a1d3Sopenharmony_ci} 104fad3a1d3Sopenharmony_ci``` 105fad3a1d3Sopenharmony_ci 106fad3a1d3Sopenharmony_ciThe [`heapsize`] example directory shows a complete working implementation of a 107fad3a1d3Sopenharmony_ciderive macro. The example derives a `HeapSize` trait which computes an estimate 108fad3a1d3Sopenharmony_ciof the amount of heap memory owned by a value. 109fad3a1d3Sopenharmony_ci 110fad3a1d3Sopenharmony_ci[`heapsize`]: examples/heapsize 111fad3a1d3Sopenharmony_ci 112fad3a1d3Sopenharmony_ci```rust 113fad3a1d3Sopenharmony_cipub trait HeapSize { 114fad3a1d3Sopenharmony_ci /// Total number of bytes of heap memory owned by `self`. 115fad3a1d3Sopenharmony_ci fn heap_size_of_children(&self) -> usize; 116fad3a1d3Sopenharmony_ci} 117fad3a1d3Sopenharmony_ci``` 118fad3a1d3Sopenharmony_ci 119fad3a1d3Sopenharmony_ciThe derive macro allows users to write `#[derive(HeapSize)]` on data structures 120fad3a1d3Sopenharmony_ciin their program. 121fad3a1d3Sopenharmony_ci 122fad3a1d3Sopenharmony_ci```rust 123fad3a1d3Sopenharmony_ci#[derive(HeapSize)] 124fad3a1d3Sopenharmony_cistruct Demo<'a, T: ?Sized> { 125fad3a1d3Sopenharmony_ci a: Box<T>, 126fad3a1d3Sopenharmony_ci b: u8, 127fad3a1d3Sopenharmony_ci c: &'a str, 128fad3a1d3Sopenharmony_ci d: String, 129fad3a1d3Sopenharmony_ci} 130fad3a1d3Sopenharmony_ci``` 131fad3a1d3Sopenharmony_ci 132fad3a1d3Sopenharmony_ci<br> 133fad3a1d3Sopenharmony_ci 134fad3a1d3Sopenharmony_ci## Spans and error reporting 135fad3a1d3Sopenharmony_ci 136fad3a1d3Sopenharmony_ciThe token-based procedural macro API provides great control over where the 137fad3a1d3Sopenharmony_cicompiler's error messages are displayed in user code. Consider the error the 138fad3a1d3Sopenharmony_ciuser sees if one of their field types does not implement `HeapSize`. 139fad3a1d3Sopenharmony_ci 140fad3a1d3Sopenharmony_ci```rust 141fad3a1d3Sopenharmony_ci#[derive(HeapSize)] 142fad3a1d3Sopenharmony_cistruct Broken { 143fad3a1d3Sopenharmony_ci ok: String, 144fad3a1d3Sopenharmony_ci bad: std::thread::Thread, 145fad3a1d3Sopenharmony_ci} 146fad3a1d3Sopenharmony_ci``` 147fad3a1d3Sopenharmony_ci 148fad3a1d3Sopenharmony_ciBy tracking span information all the way through the expansion of a procedural 149fad3a1d3Sopenharmony_cimacro as shown in the `heapsize` example, token-based macros in Syn are able to 150fad3a1d3Sopenharmony_citrigger errors that directly pinpoint the source of the problem. 151fad3a1d3Sopenharmony_ci 152fad3a1d3Sopenharmony_ci```console 153fad3a1d3Sopenharmony_cierror[E0277]: the trait bound `std::thread::Thread: HeapSize` is not satisfied 154fad3a1d3Sopenharmony_ci --> src/main.rs:7:5 155fad3a1d3Sopenharmony_ci | 156fad3a1d3Sopenharmony_ci7 | bad: std::thread::Thread, 157fad3a1d3Sopenharmony_ci | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HeapSize` is not implemented for `std::thread::Thread` 158fad3a1d3Sopenharmony_ci``` 159fad3a1d3Sopenharmony_ci 160fad3a1d3Sopenharmony_ci<br> 161fad3a1d3Sopenharmony_ci 162fad3a1d3Sopenharmony_ci## Parsing a custom syntax 163fad3a1d3Sopenharmony_ci 164fad3a1d3Sopenharmony_ciThe [`lazy-static`] example directory shows the implementation of a 165fad3a1d3Sopenharmony_ci`functionlike!(...)` procedural macro in which the input tokens are parsed using 166fad3a1d3Sopenharmony_ciSyn's parsing API. 167fad3a1d3Sopenharmony_ci 168fad3a1d3Sopenharmony_ci[`lazy-static`]: examples/lazy-static 169fad3a1d3Sopenharmony_ci 170fad3a1d3Sopenharmony_ciThe example reimplements the popular `lazy_static` crate from crates.io as a 171fad3a1d3Sopenharmony_ciprocedural macro. 172fad3a1d3Sopenharmony_ci 173fad3a1d3Sopenharmony_ci```rust 174fad3a1d3Sopenharmony_cilazy_static! { 175fad3a1d3Sopenharmony_ci static ref USERNAME: Regex = Regex::new("^[a-z0-9_-]{3,16}$").unwrap(); 176fad3a1d3Sopenharmony_ci} 177fad3a1d3Sopenharmony_ci``` 178fad3a1d3Sopenharmony_ci 179fad3a1d3Sopenharmony_ciThe implementation shows how to trigger custom warnings and error messages on 180fad3a1d3Sopenharmony_cithe macro input. 181fad3a1d3Sopenharmony_ci 182fad3a1d3Sopenharmony_ci```console 183fad3a1d3Sopenharmony_ciwarning: come on, pick a more creative name 184fad3a1d3Sopenharmony_ci --> src/main.rs:10:16 185fad3a1d3Sopenharmony_ci | 186fad3a1d3Sopenharmony_ci10 | static ref FOO: String = "lazy_static".to_owned(); 187fad3a1d3Sopenharmony_ci | ^^^ 188fad3a1d3Sopenharmony_ci``` 189fad3a1d3Sopenharmony_ci 190fad3a1d3Sopenharmony_ci<br> 191fad3a1d3Sopenharmony_ci 192fad3a1d3Sopenharmony_ci## Testing 193fad3a1d3Sopenharmony_ci 194fad3a1d3Sopenharmony_ciWhen testing macros, we often care not just that the macro can be used 195fad3a1d3Sopenharmony_cisuccessfully but also that when the macro is provided with invalid input it 196fad3a1d3Sopenharmony_ciproduces maximally helpful error messages. Consider using the [`trybuild`] crate 197fad3a1d3Sopenharmony_cito write tests for errors that are emitted by your macro or errors detected by 198fad3a1d3Sopenharmony_cithe Rust compiler in the expanded code following misuse of the macro. Such tests 199fad3a1d3Sopenharmony_cihelp avoid regressions from later refactors that mistakenly make an error no 200fad3a1d3Sopenharmony_cilonger trigger or be less helpful than it used to be. 201fad3a1d3Sopenharmony_ci 202fad3a1d3Sopenharmony_ci[`trybuild`]: https://github.com/dtolnay/trybuild 203fad3a1d3Sopenharmony_ci 204fad3a1d3Sopenharmony_ci<br> 205fad3a1d3Sopenharmony_ci 206fad3a1d3Sopenharmony_ci## Debugging 207fad3a1d3Sopenharmony_ci 208fad3a1d3Sopenharmony_ciWhen developing a procedural macro it can be helpful to look at what the 209fad3a1d3Sopenharmony_cigenerated code looks like. Use `cargo rustc -- -Zunstable-options 210fad3a1d3Sopenharmony_ci--pretty=expanded` or the [`cargo expand`] subcommand. 211fad3a1d3Sopenharmony_ci 212fad3a1d3Sopenharmony_ci[`cargo expand`]: https://github.com/dtolnay/cargo-expand 213fad3a1d3Sopenharmony_ci 214fad3a1d3Sopenharmony_ciTo show the expanded code for some crate that uses your procedural macro, run 215fad3a1d3Sopenharmony_ci`cargo expand` from that crate. To show the expanded code for one of your own 216fad3a1d3Sopenharmony_citest cases, run `cargo expand --test the_test_case` where the last argument is 217fad3a1d3Sopenharmony_cithe name of the test file without the `.rs` extension. 218fad3a1d3Sopenharmony_ci 219fad3a1d3Sopenharmony_ciThis write-up by Brandon W Maister discusses debugging in more detail: 220fad3a1d3Sopenharmony_ci[Debugging Rust's new Custom Derive system][debugging]. 221fad3a1d3Sopenharmony_ci 222fad3a1d3Sopenharmony_ci[debugging]: https://quodlibetor.github.io/posts/debugging-rusts-new-custom-derive-system/ 223fad3a1d3Sopenharmony_ci 224fad3a1d3Sopenharmony_ci<br> 225fad3a1d3Sopenharmony_ci 226fad3a1d3Sopenharmony_ci## Optional features 227fad3a1d3Sopenharmony_ci 228fad3a1d3Sopenharmony_ciSyn puts a lot of functionality behind optional features in order to optimize 229fad3a1d3Sopenharmony_cicompile time for the most common use cases. The following features are 230fad3a1d3Sopenharmony_ciavailable. 231fad3a1d3Sopenharmony_ci 232fad3a1d3Sopenharmony_ci- **`derive`** *(enabled by default)* — Data structures for representing the 233fad3a1d3Sopenharmony_ci possible input to a derive macro, including structs and enums and types. 234fad3a1d3Sopenharmony_ci- **`full`** — Data structures for representing the syntax tree of all valid 235fad3a1d3Sopenharmony_ci Rust source code, including items and expressions. 236fad3a1d3Sopenharmony_ci- **`parsing`** *(enabled by default)* — Ability to parse input tokens into a 237fad3a1d3Sopenharmony_ci syntax tree node of a chosen type. 238fad3a1d3Sopenharmony_ci- **`printing`** *(enabled by default)* — Ability to print a syntax tree node as 239fad3a1d3Sopenharmony_ci tokens of Rust source code. 240fad3a1d3Sopenharmony_ci- **`visit`** — Trait for traversing a syntax tree. 241fad3a1d3Sopenharmony_ci- **`visit-mut`** — Trait for traversing and mutating in place a syntax tree. 242fad3a1d3Sopenharmony_ci- **`fold`** — Trait for transforming an owned syntax tree. 243fad3a1d3Sopenharmony_ci- **`clone-impls`** *(enabled by default)* — Clone impls for all syntax tree 244fad3a1d3Sopenharmony_ci types. 245fad3a1d3Sopenharmony_ci- **`extra-traits`** — Debug, Eq, PartialEq, Hash impls for all syntax tree 246fad3a1d3Sopenharmony_ci types. 247fad3a1d3Sopenharmony_ci- **`proc-macro`** *(enabled by default)* — Runtime dependency on the dynamic 248fad3a1d3Sopenharmony_ci library libproc_macro from rustc toolchain. 249fad3a1d3Sopenharmony_ci 250fad3a1d3Sopenharmony_ci<br> 251fad3a1d3Sopenharmony_ci 252fad3a1d3Sopenharmony_ci## Proc macro shim 253fad3a1d3Sopenharmony_ci 254fad3a1d3Sopenharmony_ciSyn operates on the token representation provided by the [proc-macro2] crate 255fad3a1d3Sopenharmony_cifrom crates.io rather than using the compiler's built in proc-macro crate 256fad3a1d3Sopenharmony_cidirectly. This enables code using Syn to execute outside of the context of a 257fad3a1d3Sopenharmony_ciprocedural macro, such as in unit tests or build.rs, and we avoid needing 258fad3a1d3Sopenharmony_ciincompatible ecosystems for proc macros vs non-macro use cases. 259fad3a1d3Sopenharmony_ci 260fad3a1d3Sopenharmony_ciIn general all of your code should be written against proc-macro2 rather than 261fad3a1d3Sopenharmony_ciproc-macro. The one exception is in the signatures of procedural macro entry 262fad3a1d3Sopenharmony_cipoints, which are required by the language to use `proc_macro::TokenStream`. 263fad3a1d3Sopenharmony_ci 264fad3a1d3Sopenharmony_ciThe proc-macro2 crate will automatically detect and use the compiler's data 265fad3a1d3Sopenharmony_cistructures when a procedural macro is active. 266fad3a1d3Sopenharmony_ci 267fad3a1d3Sopenharmony_ci[proc-macro2]: https://docs.rs/proc-macro2/1.0/proc_macro2/ 268fad3a1d3Sopenharmony_ci 269fad3a1d3Sopenharmony_ci<br> 270fad3a1d3Sopenharmony_ci 271fad3a1d3Sopenharmony_ci#### License 272fad3a1d3Sopenharmony_ci 273fad3a1d3Sopenharmony_ci<sup> 274fad3a1d3Sopenharmony_ciLicensed under either of <a href="LICENSE-APACHE">Apache License, Version 275fad3a1d3Sopenharmony_ci2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option. 276fad3a1d3Sopenharmony_ci</sup> 277fad3a1d3Sopenharmony_ci 278fad3a1d3Sopenharmony_ci<br> 279fad3a1d3Sopenharmony_ci 280fad3a1d3Sopenharmony_ci<sub> 281fad3a1d3Sopenharmony_ciUnless you explicitly state otherwise, any contribution intentionally submitted 282fad3a1d3Sopenharmony_cifor inclusion in this crate by you, as defined in the Apache-2.0 license, shall 283fad3a1d3Sopenharmony_cibe dual licensed as above, without any additional terms or conditions. 284fad3a1d3Sopenharmony_ci</sub> 285