blob: c3627e4572ab725cb9eef9ca716197d88395b1f2 [file] [log] [blame] [view]
David Tolnay6eacaff2016-10-23 15:20:23 -07001Nom parser for Rust source code
2===============================
David Tolnay35161ff2016-09-03 11:33:15 -07003
David Tolnayac9953b2016-09-07 08:37:12 -07004[![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)
David Tolnay3150dfb2017-02-19 13:00:54 -08006[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://dtolnay.github.io/syn/syn/)
David Tolnayac9953b2016-09-07 08:37:12 -07007
David Tolnay105f2fd2017-02-09 09:15:26 -08008Parse Rust source code without a Syntex dependency, intended for use with
David Tolnay35161ff2016-09-03 11:33:15 -07009[Macros 1.1](https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md).
10
David Tolnayf939f352016-09-11 18:00:09 -070011Designed for fast compile time.
12
David Tolnay4415eea2017-01-23 18:04:27 -080013- Compile time for `syn` (from scratch including all dependencies): **6 seconds**
David Tolnayf939f352016-09-11 18:00:09 -070014- Compile time for the `syntex`/`quasi`/`aster` stack: **60+ seconds**
15
David Tolnayfb9f7042016-12-22 12:31:39 -050016If 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
David Tolnayed8e23e2016-09-27 08:18:22 -070019## Usage with Macros 1.1
David Tolnay6c9f5b62016-09-13 15:19:22 -070020
David Tolnay69b538e2016-09-23 19:59:48 -070021```toml
22[dependencies]
David Tolnaydf8fa312017-01-23 18:22:29 -080023syn = "0.11"
David Tolnayf8f43072016-10-08 14:58:05 -070024quote = "0.3"
David Tolnay69b538e2016-09-23 19:59:48 -070025
26[lib]
David Tolnay45cc8492016-10-08 20:52:03 -070027proc-macro = true
David Tolnay69b538e2016-09-23 19:59:48 -070028```
29
White-Oak82d0db72016-09-13 21:45:58 +030030```rust
David Tolnay45cc8492016-10-08 20:52:03 -070031extern crate proc_macro;
32use proc_macro::TokenStream;
David Tolnayb4c63262016-09-23 20:03:06 -070033
34extern crate syn;
David Tolnay6c9f5b62016-09-13 15:19:22 -070035
White-Oak82d0db72016-09-13 21:45:58 +030036#[macro_use]
37extern crate quote;
White-Oak82d0db72016-09-13 21:45:58 +030038
David Tolnay45cc8492016-10-08 20:52:03 -070039#[proc_macro_derive(MyMacro)]
David Tolnayb4c63262016-09-23 20:03:06 -070040pub fn my_macro(input: TokenStream) -> TokenStream {
White-Oak82d0db72016-09-13 21:45:58 +030041 let source = input.to_string();
42
David Tolnayd12e4092016-12-27 22:58:43 -050043 // Parse the string representation into a syntax tree
David Tolnay0e837402016-12-22 17:25:55 -050044 let ast = syn::parse_derive_input(&source).unwrap();
White-Oak82d0db72016-09-13 21:45:58 +030045
David Tolnay6c9f5b62016-09-13 15:19:22 -070046 // Build the output, possibly using quasi-quotation
47 let expanded = quote! {
48 // ...
49 };
50
David Tolnayb988b6d2016-10-05 00:12:37 -070051 // Parse back to a token stream and return it
David Tolnay62463ba2016-11-24 13:06:01 -080052 expanded.parse().unwrap()
White-Oak82d0db72016-09-13 21:45:58 +030053}
54```
David Tolnay6c9f5b62016-09-13 15:19:22 -070055
David Tolnayb988b6d2016-10-05 00:12:37 -070056## 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
David Tolnay45cc8492016-10-08 20:52:03 -070071extern crate proc_macro;
72use proc_macro::TokenStream;
David Tolnayb988b6d2016-10-05 00:12:37 -070073
74extern crate syn;
75
76#[macro_use]
77extern crate quote;
78
David Tolnay45cc8492016-10-08 20:52:03 -070079#[proc_macro_derive(NumFields)]
David Tolnayb988b6d2016-10-05 00:12:37 -070080pub fn num_fields(input: TokenStream) -> TokenStream {
81 let source = input.to_string();
82
David Tolnayd12e4092016-12-27 22:58:43 -050083 // Parse the string representation into a syntax tree
David Tolnay0e837402016-12-22 17:25:55 -050084 let ast = syn::parse_derive_input(&source).unwrap();
David Tolnayb988b6d2016-10-05 00:12:37 -070085
86 // Build the output
David Tolnayed7a5082016-10-30 20:06:29 -070087 let expanded = expand_num_fields(&ast);
David Tolnayb988b6d2016-10-05 00:12:37 -070088
David Tolnay7c509bb2016-11-19 13:00:12 -080089 // Return the generated impl as a TokenStream
David Tolnay62463ba2016-11-24 13:06:01 -080090 expanded.parse().unwrap()
David Tolnayb988b6d2016-10-05 00:12:37 -070091}
92
David Tolnay0e837402016-12-22 17:25:55 -050093fn expand_num_fields(ast: &syn::DeriveInput) -> quote::Tokens {
David Tolnayb988b6d2016-10-05 00:12:37 -070094 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! {
David Tolnayb988b6d2016-10-05 00:12:37 -0700106 // 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
David Tolnay736829a2016-12-22 15:55:53 -0500116## Testing
117
118Macros 1.1 has a restriction that your proc-macro crate must export nothing but
119`proc_macro_derive` functions, and also `proc_macro_derive` procedural macros
120cannot be used from the same crate in which they are defined. These restrictions
121may be lifted in the future but for now they make writing tests a bit trickier
122than for other types of code.
123
124In particular, you will not be able to write test functions like `#[test] fn
125it_works() { ... }` in line with your code. Instead, either put tests in a
126[`tests` directory](https://doc.rust-lang.org/book/testing.html#the-tests-directory)
127or in a separate crate entirely.
128
129Additionally, if your procedural macro implements a particular trait, that trait
130must be defined in a separate crate from the procedural macro.
131
132As a concrete example, suppose your procedural macro crate is called `my_derive`
133and it implements a trait called `my_crate::MyTrait`. Your unit tests for the
134procedural macro can go in `my_derive/tests/test.rs` or into a separate crate
135`my_tests/tests/test.rs`. Either way the test would look something like this:
136
137```rust
David Tolnay736829a2016-12-22 15:55:53 -0500138#[macro_use]
139extern crate my_derive;
140
141extern crate my_crate;
142use my_crate::MyTrait;
143
144#[test]
145fn it_works() {
146 #[derive(MyTrait)]
147 struct S { /* ... */ }
148
149 /* test the thing */
150}
151```
152
David Tolnay941c0922016-12-22 16:06:27 -0500153## Debugging
154
155When developing a procedural macro it can be helpful to look at what the
156generated code looks like. Use `cargo rustc -- -Zunstable-options
157--pretty=expanded` or the
158[`cargo expand`](https://github.com/dtolnay/cargo-expand) subcommand.
159
160To show the expanded code for some crate that uses your procedural macro, run
161`cargo expand` from that crate. To show the expanded code for one of your own
162test cases, run `cargo expand --test the_test_case` where the last argument is
163the name of the test file without the `.rs` extension.
164
David Tolnay3bfbd542017-01-16 14:57:53 -0800165This write-up by Brandon W Maister discusses debugging in more detail:
166[Debugging Rust's new Custom Derive
167system](https://quodlibetor.github.io/posts/debugging-rusts-new-custom-derive-system/).
168
David Tolnay686f5042016-10-30 19:24:51 -0700169## Optional features
170
171Syn puts a lot of functionality behind optional features in order to optimize
172compile time for the most common use cases. These are the available features and
173their effect on compile time. Dependencies are included in the compile times.
174
175Features | Compile time | Functionality
176--- | --- | ---
David Tolnay4415eea2017-01-23 18:04:27 -0800177*(none)* | 3 sec | The data structures representing the AST of Rust structs, enums, and types.
178parsing | 6 sec | Parsing Rust source code containing structs and enums into an AST.
179printing | 4 sec | Printing an AST of structs and enums as Rust source code.
180**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.
181full | 4 sec | The data structures representing the full AST of all possible Rust code.
182full, parsing | 9 sec | Parsing any valid Rust source code to an AST.
183full, printing | 6 sec | Turning an AST into Rust source code.
184full, parsing, printing | 11 sec | Parsing and printing any Rust syntax.
David Tolnayed7a5082016-10-30 20:06:29 -0700185
David Tolnay35161ff2016-09-03 11:33:15 -0700186## License
187
188Licensed under either of
189
190 * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
191 * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
192
193at your option.
194
195### Contribution
196
197Unless you explicitly state otherwise, any contribution intentionally submitted
198for inclusion in this crate by you, as defined in the Apache-2.0 license, shall
199be dual licensed as above, without any additional terms or conditions.