blob: 8459cac4cf830945abaf401afbf9e37fb9c8e2f3 [file] [log] [blame] [view]
David Tolnay35161ff2016-09-03 11:33:15 -07001Nom parser for Rust items
2=========================
3
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 Tolnaya3faf252016-09-27 09:52:30 -070020syn = "0.8"
21quote = "0.2"
David Tolnay69b538e2016-09-23 19:59:48 -070022
23[lib]
24rustc-macro = true
25```
26
White-Oak82d0db72016-09-13 21:45:58 +030027```rust
David Tolnay6c9f5b62016-09-13 15:19:22 -070028#![feature(rustc_macro, rustc_macro_lib)]
White-Oak82d0db72016-09-13 21:45:58 +030029
30extern crate rustc_macro;
David Tolnayb4c63262016-09-23 20:03:06 -070031use rustc_macro::TokenStream;
32
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 Tolnayb4c63262016-09-23 20:03:06 -070038#[rustc_macro_derive(MyMacro)]
39pub 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
70#![feature(rustc_macro, rustc_macro_lib)]
71
72extern crate rustc_macro;
73use rustc_macro::TokenStream;
74
75extern crate syn;
76
77#[macro_use]
78extern crate quote;
79
80#[rustc_macro_derive(NumFields)]
81pub 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 Tolnay35161ff2016-09-03 11:33:15 -0700120## License
121
122Licensed under either of
123
124 * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
125 * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
126
127at your option.
128
129### Contribution
130
131Unless you explicitly state otherwise, any contribution intentionally submitted
132for inclusion in this crate by you, as defined in the Apache-2.0 license, shall
133be dual licensed as above, without any additional terms or conditions.