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