blob: fd0bcdf782af346cb4c35870807cca3f4c0cf73d [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 Tolnay50e62202016-09-12 09:49:49 -07006[![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 Tolnay35161ff2016-09-03 11:33:15 -07008Parse Rust structs and enums 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
David Tolnayf939f352016-09-11 18:00:09 -070011Designed for fast compile time.
12
David Tolnayb5a7b142016-09-13 22:46:39 -070013- Compile time for `syn` (from scratch including all dependencies): **4 seconds**
David Tolnayf939f352016-09-11 18:00:09 -070014- Compile time for the `syntex`/`quasi`/`aster` stack: **60+ seconds**
15
David Tolnayed8e23e2016-09-27 08:18:22 -070016## Usage with Macros 1.1
David Tolnay6c9f5b62016-09-13 15:19:22 -070017
David Tolnay69b538e2016-09-23 19:59:48 -070018```toml
19[dependencies]
David Tolnayf8f43072016-10-08 14:58:05 -070020syn = "0.9"
21quote = "0.3"
David Tolnay69b538e2016-09-23 19:59:48 -070022
23[lib]
David Tolnay45cc8492016-10-08 20:52:03 -070024proc-macro = true
David Tolnay69b538e2016-09-23 19:59:48 -070025```
26
White-Oak82d0db72016-09-13 21:45:58 +030027```rust
David Tolnay45cc8492016-10-08 20:52:03 -070028#![feature(proc_macro, proc_macro_lib)]
White-Oak82d0db72016-09-13 21:45:58 +030029
David Tolnay45cc8492016-10-08 20:52:03 -070030extern crate proc_macro;
31use proc_macro::TokenStream;
David Tolnayb4c63262016-09-23 20:03:06 -070032
33extern crate syn;
David Tolnay6c9f5b62016-09-13 15:19:22 -070034
White-Oak82d0db72016-09-13 21:45:58 +030035#[macro_use]
36extern crate quote;
White-Oak82d0db72016-09-13 21:45:58 +030037
David Tolnay45cc8492016-10-08 20:52:03 -070038#[proc_macro_derive(MyMacro)]
David Tolnayb4c63262016-09-23 20:03:06 -070039pub fn my_macro(input: TokenStream) -> TokenStream {
White-Oak82d0db72016-09-13 21:45:58 +030040 let source = input.to_string();
41
David Tolnayb988b6d2016-10-05 00:12:37 -070042 // Parse the string representation to an AST
David Tolnayf38cdf62016-09-23 19:07:09 -070043 let ast = syn::parse_macro_input(&source).unwrap();
White-Oak82d0db72016-09-13 21:45:58 +030044
David Tolnay6c9f5b62016-09-13 15:19:22 -070045 // Build the output, possibly using quasi-quotation
46 let expanded = quote! {
47 // ...
48 };
49
David Tolnayb988b6d2016-10-05 00:12:37 -070050 // Parse back to a token stream and return it
David Tolnay6c9f5b62016-09-13 15:19:22 -070051 expanded.to_string().parse().unwrap()
White-Oak82d0db72016-09-13 21:45:58 +030052}
53```
David Tolnay6c9f5b62016-09-13 15:19:22 -070054
David Tolnayb988b6d2016-10-05 00:12:37 -070055## Complete example
56
57Suppose we have the following simple trait which returns the number of fields in
58a struct:
59
60```rust
61trait NumFields {
62 fn num_fields() -> usize;
63}
64```
65
66A complete Macros 1.1 implementation of `#[derive(NumFields)]` based on `syn`
67and [`quote`](https://github.com/dtolnay/quote) looks like this:
68
69```rust
David Tolnay45cc8492016-10-08 20:52:03 -070070#![feature(proc_macro, proc_macro_lib)]
David Tolnayb988b6d2016-10-05 00:12:37 -070071
David Tolnay45cc8492016-10-08 20:52:03 -070072extern crate proc_macro;
73use proc_macro::TokenStream;
David Tolnayb988b6d2016-10-05 00:12:37 -070074
75extern crate syn;
76
77#[macro_use]
78extern crate quote;
79
David Tolnay45cc8492016-10-08 20:52:03 -070080#[proc_macro_derive(NumFields)]
David Tolnayb988b6d2016-10-05 00:12:37 -070081pub fn num_fields(input: TokenStream) -> TokenStream {
82 let source = input.to_string();
83
84 // Parse the string representation to an AST
85 let ast = syn::parse_macro_input(&source).unwrap();
86
87 // Build the output
88 let expanded = expand_num_fields(ast);
89
90 // Parse back to a token stream and return it
91 expanded.to_string().parse().unwrap()
92}
93
94fn expand_num_fields(ast: syn::MacroInput) -> quote::Tokens {
95 let n = match ast.body {
96 syn::Body::Struct(ref data) => data.fields().len(),
97 syn::Body::Enum(_) => panic!("#[derive(NumFields)] can only be used with structs"),
98 };
99
100 // Used in the quasi-quotation below as `#name`
101 let name = &ast.ident;
102
103 // Helper is provided for handling complex generic types correctly and effortlessly
104 let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
105
106 quote! {
107 // Preserve the input struct unmodified
108 #ast
109
110 // The generated impl
111 impl #impl_generics ::mycrate::NumFields for #name #ty_generics #where_clause {
112 fn num_fields() -> usize {
113 #n
114 }
115 }
116 }
117}
118```
119
David Tolnay686f5042016-10-30 19:24:51 -0700120## Optional features
121
122Syn puts a lot of functionality behind optional features in order to optimize
123compile time for the most common use cases. These are the available features and
124their effect on compile time. Dependencies are included in the compile times.
125
126Features | Compile time | Functionality
127--- | --- | ---
128*(none)* | 1 sec | The data structures representing the AST of Rust structs, enums, and types.
129parsing | 4 sec | Parsing Rust source code containing structs and enums into an AST.
130printing | 2 sec | Printing an AST of structs and enums as Rust source code.
131**parsing, printing** | **4 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.
132full | 2 sec | The data structures representing the full AST of all possible Rust code.
133full, parsing | 7 sec | Parsing any valid Rust source code to an AST.
134full, printing | 4 sec | Turning an AST into Rust source code.
135full, parsing, printing | 8 sec | Parsing and printing any Rust syntax.
136full, parsing, printing, expand | 9 sec | Expansion of custom derives in a file of Rust code. This is typically what you want for expanding custom derives on stable Rust using a build script.
137full, parsing, printing, expand, pretty | 60 sec | Expansion of custom derives with pretty-printed output. This is what you want when iterating on or debugging a custom derive, but the pretty printing should be disabled once you get everything working.
138
David Tolnay35161ff2016-09-03 11:33:15 -0700139## License
140
141Licensed under either of
142
143 * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
144 * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
145
146at your option.
147
148### Contribution
149
150Unless you explicitly state otherwise, any contribution intentionally submitted
151for inclusion in this crate by you, as defined in the Apache-2.0 license, shall
152be dual licensed as above, without any additional terms or conditions.