• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

src/H03-May-2022-10,9069,225

.cargo-checksum.jsonH A D03-May-202289 11

Cargo.tomlH A D20-Apr-2017896 3127

LICENSE-APACHEH A D03-Sep-201610.6 KiB202169

LICENSE-MITH A D03-Sep-20161 KiB2622

README.mdH A D10-Mar-20176.8 KiB206151

README.md

1Nom parser for Rust source code
2===============================
3
4[![Build Status](https://api.travis-ci.org/dtolnay/syn.svg?branch=master)](https://travis-ci.org/dtolnay/syn)
5[![Latest Version](https://img.shields.io/crates/v/syn.svg)](https://crates.io/crates/syn)
6[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://dtolnay.github.io/syn/syn/)
7
8Parse Rust source code without a Syntex dependency, intended for use with
9[Macros 1.1](https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md).
10
11Designed for fast compile time.
12
13- Compile time for `syn` (from scratch including all dependencies): **6 seconds**
14- Compile time for the `syntex`/`quasi`/`aster` stack: **60+ seconds**
15
16If you get stuck with Macros 1.1 I am happy to provide help even if the issue is
17not related to syn. Please file a ticket in this repo.
18
19## Usage with Macros 1.1
20
21```toml
22[dependencies]
23syn = "0.11"
24quote = "0.3"
25
26[lib]
27proc-macro = true
28```
29
30```rust
31extern crate proc_macro;
32use proc_macro::TokenStream;
33
34extern crate syn;
35
36#[macro_use]
37extern crate quote;
38
39#[proc_macro_derive(MyMacro)]
40pub fn my_macro(input: TokenStream) -> TokenStream {
41    let source = input.to_string();
42
43    // Parse the string representation into a syntax tree
44    let ast = syn::parse_derive_input(&source).unwrap();
45
46    // Build the output, possibly using quasi-quotation
47    let expanded = quote! {
48        // ...
49    };
50
51    // Parse back to a token stream and return it
52    expanded.parse().unwrap()
53}
54```
55
56## Complete example
57
58Suppose we have the following simple trait which returns the number of fields in
59a struct:
60
61```rust
62trait NumFields {
63    fn num_fields() -> usize;
64}
65```
66
67A complete Macros 1.1 implementation of `#[derive(NumFields)]` based on `syn`
68and [`quote`](https://github.com/dtolnay/quote) looks like this:
69
70```rust
71extern crate proc_macro;
72use proc_macro::TokenStream;
73
74extern crate syn;
75
76#[macro_use]
77extern crate quote;
78
79#[proc_macro_derive(NumFields)]
80pub fn num_fields(input: TokenStream) -> TokenStream {
81    let source = input.to_string();
82
83    // Parse the string representation into a syntax tree
84    let ast = syn::parse_derive_input(&source).unwrap();
85
86    // Build the output
87    let expanded = expand_num_fields(&ast);
88
89    // Return the generated impl as a TokenStream
90    expanded.parse().unwrap()
91}
92
93fn expand_num_fields(ast: &syn::DeriveInput) -> quote::Tokens {
94    let n = match ast.body {
95        syn::Body::Struct(ref data) => data.fields().len(),
96        syn::Body::Enum(_) => panic!("#[derive(NumFields)] can only be used with structs"),
97    };
98
99    // Used in the quasi-quotation below as `#name`
100    let name = &ast.ident;
101
102    // Helper is provided for handling complex generic types correctly and effortlessly
103    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
104
105    quote! {
106        // The generated impl
107        impl #impl_generics ::mycrate::NumFields for #name #ty_generics #where_clause {
108            fn num_fields() -> usize {
109                #n
110            }
111        }
112    }
113}
114```
115
116For a more elaborate example that involves trait bounds, enums, and different
117kinds of structs, check out [`DeepClone`] and [`deep-clone-derive`].
118
119[`DeepClone`]: https://github.com/asajeffrey/deep-clone
120[`deep-clone-derive`]: https://github.com/asajeffrey/deep-clone/blob/master/deep-clone-derive/lib.rs
121
122## Testing
123
124Macros 1.1 has a restriction that your proc-macro crate must export nothing but
125`proc_macro_derive` functions, and also `proc_macro_derive` procedural macros
126cannot be used from the same crate in which they are defined. These restrictions
127may be lifted in the future but for now they make writing tests a bit trickier
128than for other types of code.
129
130In particular, you will not be able to write test functions like `#[test] fn
131it_works() { ... }` in line with your code. Instead, either put tests in a
132[`tests` directory](https://doc.rust-lang.org/book/testing.html#the-tests-directory)
133or in a separate crate entirely.
134
135Additionally, if your procedural macro implements a particular trait, that trait
136must be defined in a separate crate from the procedural macro.
137
138As a concrete example, suppose your procedural macro crate is called `my_derive`
139and it implements a trait called `my_crate::MyTrait`. Your unit tests for the
140procedural macro can go in `my_derive/tests/test.rs` or into a separate crate
141`my_tests/tests/test.rs`. Either way the test would look something like this:
142
143```rust
144#[macro_use]
145extern crate my_derive;
146
147extern crate my_crate;
148use my_crate::MyTrait;
149
150#[test]
151fn it_works() {
152    #[derive(MyTrait)]
153    struct S { /* ... */ }
154
155    /* test the thing */
156}
157```
158
159## Debugging
160
161When developing a procedural macro it can be helpful to look at what the
162generated code looks like. Use `cargo rustc -- -Zunstable-options
163--pretty=expanded` or the
164[`cargo expand`](https://github.com/dtolnay/cargo-expand) subcommand.
165
166To show the expanded code for some crate that uses your procedural macro, run
167`cargo expand` from that crate. To show the expanded code for one of your own
168test cases, run `cargo expand --test the_test_case` where the last argument is
169the name of the test file without the `.rs` extension.
170
171This write-up by Brandon W Maister discusses debugging in more detail:
172[Debugging Rust's new Custom Derive
173system](https://quodlibetor.github.io/posts/debugging-rusts-new-custom-derive-system/).
174
175## Optional features
176
177Syn puts a lot of functionality behind optional features in order to optimize
178compile time for the most common use cases. These are the available features and
179their effect on compile time. Dependencies are included in the compile times.
180
181Features | Compile time | Functionality
182--- | --- | ---
183*(none)* | 3 sec | The data structures representing the AST of Rust structs, enums, and types.
184parsing | 6 sec | Parsing Rust source code containing structs and enums into an AST.
185printing | 4 sec | Printing an AST of structs and enums as Rust source code.
186**parsing, printing** | **6 sec** | **This is the default.** Parsing and printing of Rust structs and enums. This is typically what you want for implementing Macros 1.1 custom derives.
187full | 4 sec | The data structures representing the full AST of all possible Rust code.
188full, parsing | 9 sec | Parsing any valid Rust source code to an AST.
189full, printing | 6 sec | Turning an AST into Rust source code.
190full, parsing, printing | 11 sec | Parsing and printing any Rust syntax.
191
192## License
193
194Licensed under either of
195
196 * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
197 * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
198
199at your option.
200
201### Contribution
202
203Unless you explicitly state otherwise, any contribution intentionally submitted
204for inclusion in this crate by you, as defined in the Apache-2.0 license, shall
205be dual licensed as above, without any additional terms or conditions.
206