David Tolnay | 6eacaff | 2016-10-23 15:20:23 -0700 | [diff] [blame] | 1 | Nom parser for Rust source code |
| 2 | =============================== |
David Tolnay | 35161ff | 2016-09-03 11:33:15 -0700 | [diff] [blame] | 3 | |
David Tolnay | ac9953b | 2016-09-07 08:37:12 -0700 | [diff] [blame] | 4 | [](https://travis-ci.org/dtolnay/syn) |
| 5 | [](https://crates.io/crates/syn) |
David Tolnay | 87003d0 | 2018-05-20 19:45:13 -0700 | [diff] [blame] | 6 | [](https://docs.rs/syn/0.14/syn/) |
David Tolnay | 8659a23 | 2018-03-31 22:54:03 +0200 | [diff] [blame] | 7 | [](https://blog.rust-lang.org/2017/02/02/Rust-1.15.html) |
David Tolnay | ac9953b | 2016-09-07 08:37:12 -0700 | [diff] [blame] | 8 | |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 9 | Syn is a parsing library for parsing a stream of Rust tokens into a syntax tree |
| 10 | of Rust source code. |
David Tolnay | 35161ff | 2016-09-03 11:33:15 -0700 | [diff] [blame] | 11 | |
David Tolnay | f594f18 | 2018-09-01 20:10:08 -0700 | [diff] [blame] | 12 | Currently this library is geared toward use in Rust procedural macros, but |
| 13 | contains some APIs that may be useful more generally. |
David Tolnay | f939f35 | 2016-09-11 18:00:09 -0700 | [diff] [blame] | 14 | |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 15 | [custom derive]: https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md |
David Tolnay | f939f35 | 2016-09-11 18:00:09 -0700 | [diff] [blame] | 16 | |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 17 | - **Data structures** — Syn provides a complete syntax tree that can represent |
| 18 | any valid Rust source code. The syntax tree is rooted at [`syn::File`] which |
| 19 | represents a full source file, but there are other entry points that may be |
| 20 | useful to procedural macros including [`syn::Item`], [`syn::Expr`] and |
| 21 | [`syn::Type`]. |
David Tolnay | fb9f704 | 2016-12-22 12:31:39 -0500 | [diff] [blame] | 22 | |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 23 | - **Custom derives** — Of particular interest to custom derives is |
| 24 | [`syn::DeriveInput`] which is any of the three legal input items to a derive |
| 25 | macro. An example below shows using this type in a library that can derive |
| 26 | implementations of a trait of your own. |
| 27 | |
David Tolnay | f594f18 | 2018-09-01 20:10:08 -0700 | [diff] [blame] | 28 | - **Parsing** — Parsing in Syn is built around [parser functions] with the |
| 29 | signature `fn(ParseStream) -> Result<T>`. Every syntax tree node defined by |
| 30 | Syn is individually parsable and may be used as a building block for custom |
| 31 | syntaxes, or you may dream up your own brand new syntax without involving any |
| 32 | of our syntax tree types. |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 33 | |
| 34 | - **Location information** — Every token parsed by Syn is associated with a |
| 35 | `Span` that tracks line and column information back to the source of that |
| 36 | token. These spans allow a procedural macro to display detailed error messages |
| 37 | pointing to all the right places in the user's code. There is an example of |
| 38 | this below. |
| 39 | |
| 40 | - **Feature flags** — Functionality is aggressively feature gated so your |
| 41 | procedural macros enable only what they need, and do not pay in compile time |
| 42 | for all the rest. |
| 43 | |
David Tolnay | 87003d0 | 2018-05-20 19:45:13 -0700 | [diff] [blame] | 44 | [`syn::File`]: https://docs.rs/syn/0.14/syn/struct.File.html |
| 45 | [`syn::Item`]: https://docs.rs/syn/0.14/syn/enum.Item.html |
| 46 | [`syn::Expr`]: https://docs.rs/syn/0.14/syn/enum.Expr.html |
| 47 | [`syn::Type`]: https://docs.rs/syn/0.14/syn/enum.Type.html |
| 48 | [`syn::DeriveInput`]: https://docs.rs/syn/0.14/syn/struct.DeriveInput.html |
David Tolnay | f594f18 | 2018-09-01 20:10:08 -0700 | [diff] [blame] | 49 | [parser functions]: https://docs.rs/syn/0.14/syn/parse/index.html |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 50 | |
| 51 | If you get stuck with anything involving procedural macros in Rust I am happy to |
| 52 | provide help even if the issue is not related to Syn. Please file a ticket in |
| 53 | this repo. |
| 54 | |
| 55 | *Version requirement: Syn supports any compiler version back to Rust's very |
| 56 | first support for procedural macros in Rust 1.15.0. Some features especially |
| 57 | around error reporting are only available in newer compilers or on the nightly |
| 58 | channel.* |
| 59 | |
David Tolnay | 8603156 | 2018-05-20 22:39:09 -0700 | [diff] [blame] | 60 | [*Release notes*](https://github.com/dtolnay/syn/releases) |
| 61 | |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 62 | ## Example of a custom derive |
| 63 | |
| 64 | The canonical custom derive using Syn looks like this. We write an ordinary Rust |
| 65 | function tagged with a `proc_macro_derive` attribute and the name of the trait |
| 66 | we are deriving. Any time that derive appears in the user's code, the Rust |
| 67 | compiler passes their data structure as tokens into our macro. We get to execute |
| 68 | arbitrary Rust code to figure out what to do with those tokens, then hand some |
| 69 | tokens back to the compiler to compile into the user's crate. |
| 70 | |
| 71 | [`TokenStream`]: https://doc.rust-lang.org/proc_macro/struct.TokenStream.html |
David Tolnay | 6c9f5b6 | 2016-09-13 15:19:22 -0700 | [diff] [blame] | 72 | |
David Tolnay | 69b538e | 2016-09-23 19:59:48 -0700 | [diff] [blame] | 73 | ```toml |
| 74 | [dependencies] |
David Tolnay | 87003d0 | 2018-05-20 19:45:13 -0700 | [diff] [blame] | 75 | syn = "0.14" |
| 76 | quote = "0.6" |
David Tolnay | 69b538e | 2016-09-23 19:59:48 -0700 | [diff] [blame] | 77 | |
| 78 | [lib] |
David Tolnay | 45cc849 | 2016-10-08 20:52:03 -0700 | [diff] [blame] | 79 | proc-macro = true |
David Tolnay | 69b538e | 2016-09-23 19:59:48 -0700 | [diff] [blame] | 80 | ``` |
| 81 | |
White-Oak | 82d0db7 | 2016-09-13 21:45:58 +0300 | [diff] [blame] | 82 | ```rust |
David Tolnay | 45cc849 | 2016-10-08 20:52:03 -0700 | [diff] [blame] | 83 | extern crate proc_macro; |
David Tolnay | b4c6326 | 2016-09-23 20:03:06 -0700 | [diff] [blame] | 84 | extern crate syn; |
David Tolnay | 6c9f5b6 | 2016-09-13 15:19:22 -0700 | [diff] [blame] | 85 | |
White-Oak | 82d0db7 | 2016-09-13 21:45:58 +0300 | [diff] [blame] | 86 | #[macro_use] |
| 87 | extern crate quote; |
White-Oak | 82d0db7 | 2016-09-13 21:45:58 +0300 | [diff] [blame] | 88 | |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 89 | use proc_macro::TokenStream; |
David Tolnay | f594f18 | 2018-09-01 20:10:08 -0700 | [diff] [blame] | 90 | use syn::{parse_macro_input, DeriveInput}; |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 91 | |
David Tolnay | 45cc849 | 2016-10-08 20:52:03 -0700 | [diff] [blame] | 92 | #[proc_macro_derive(MyMacro)] |
David Tolnay | b4c6326 | 2016-09-23 20:03:06 -0700 | [diff] [blame] | 93 | pub fn my_macro(input: TokenStream) -> TokenStream { |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 94 | // Parse the input tokens into a syntax tree |
David Tolnay | f594f18 | 2018-09-01 20:10:08 -0700 | [diff] [blame] | 95 | let input = parse_macro_input!(input as DeriveInput); |
White-Oak | 82d0db7 | 2016-09-13 21:45:58 +0300 | [diff] [blame] | 96 | |
David Tolnay | 6c9f5b6 | 2016-09-13 15:19:22 -0700 | [diff] [blame] | 97 | // Build the output, possibly using quasi-quotation |
| 98 | let expanded = quote! { |
| 99 | // ... |
| 100 | }; |
| 101 | |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 102 | // Hand the output tokens back to the compiler |
David Tolnay | 35b498e | 2018-09-01 20:10:40 -0700 | [diff] [blame^] | 103 | TokenStream::from(expanded) |
White-Oak | 82d0db7 | 2016-09-13 21:45:58 +0300 | [diff] [blame] | 104 | } |
| 105 | ``` |
David Tolnay | 6c9f5b6 | 2016-09-13 15:19:22 -0700 | [diff] [blame] | 106 | |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 107 | The [`heapsize`] example directory shows a complete working Macros 1.1 |
| 108 | implementation of a custom derive. It works on any Rust compiler \>=1.15.0. The |
| 109 | example derives a `HeapSize` trait which computes an estimate of the amount of |
| 110 | heap memory owned by a value. |
David Tolnay | b988b6d | 2016-10-05 00:12:37 -0700 | [diff] [blame] | 111 | |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 112 | [`heapsize`]: examples/heapsize |
David Tolnay | b988b6d | 2016-10-05 00:12:37 -0700 | [diff] [blame] | 113 | |
| 114 | ```rust |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 115 | pub trait HeapSize { |
| 116 | /// Total number of bytes of heap memory owned by `self`. |
| 117 | fn heap_size_of_children(&self) -> usize; |
David Tolnay | b988b6d | 2016-10-05 00:12:37 -0700 | [diff] [blame] | 118 | } |
| 119 | ``` |
| 120 | |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 121 | The custom derive allows users to write `#[derive(HeapSize)]` on data structures |
| 122 | in their program. |
David Tolnay | b988b6d | 2016-10-05 00:12:37 -0700 | [diff] [blame] | 123 | |
| 124 | ```rust |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 125 | #[derive(HeapSize)] |
| 126 | struct Demo<'a, T: ?Sized> { |
| 127 | a: Box<T>, |
| 128 | b: u8, |
| 129 | c: &'a str, |
| 130 | d: String, |
David Tolnay | b988b6d | 2016-10-05 00:12:37 -0700 | [diff] [blame] | 131 | } |
| 132 | ``` |
| 133 | |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 134 | ## Spans and error reporting |
David Tolnay | c2263f3 | 2017-03-09 19:20:52 -0800 | [diff] [blame] | 135 | |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 136 | The [`heapsize2`] example directory is an extension of the `heapsize` example |
| 137 | that demonstrates some of the hygiene and error reporting properties of Macros |
| 138 | 2.0. This example currently requires a nightly Rust compiler \>=1.24.0-nightly |
| 139 | but we are working to stabilize all of the APIs involved. |
David Tolnay | c2263f3 | 2017-03-09 19:20:52 -0800 | [diff] [blame] | 140 | |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 141 | [`heapsize2`]: examples/heapsize2 |
David Tolnay | 736829a | 2016-12-22 15:55:53 -0500 | [diff] [blame] | 142 | |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 143 | The token-based procedural macro API provides great control over where the |
| 144 | compiler's error messages are displayed in user code. Consider the error the |
| 145 | user sees if one of their field types does not implement `HeapSize`. |
David Tolnay | 736829a | 2016-12-22 15:55:53 -0500 | [diff] [blame] | 146 | |
| 147 | ```rust |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 148 | #[derive(HeapSize)] |
| 149 | struct Broken { |
| 150 | ok: String, |
| 151 | bad: std::thread::Thread, |
David Tolnay | 736829a | 2016-12-22 15:55:53 -0500 | [diff] [blame] | 152 | } |
| 153 | ``` |
| 154 | |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 155 | In the Macros 1.1 string-based procedural macro world, the resulting error would |
| 156 | point unhelpfully to the invocation of the derive macro and not to the actual |
| 157 | problematic field. |
| 158 | |
| 159 | ``` |
| 160 | error[E0599]: no method named `heap_size_of_children` found for type `std::thread::Thread` in the current scope |
| 161 | --> src/main.rs:4:10 |
| 162 | | |
| 163 | 4 | #[derive(HeapSize)] |
| 164 | | ^^^^^^^^ |
| 165 | ``` |
| 166 | |
| 167 | By tracking span information all the way through the expansion of a procedural |
| 168 | macro as shown in the `heapsize2` example, token-based macros in Syn are able to |
| 169 | trigger errors that directly pinpoint the source of the problem. |
| 170 | |
| 171 | ``` |
| 172 | error[E0277]: the trait bound `std::thread::Thread: HeapSize` is not satisfied |
| 173 | --> src/main.rs:7:5 |
| 174 | | |
| 175 | 7 | bad: std::thread::Thread, |
| 176 | | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HeapSize` is not implemented for `std::thread::Thread` |
| 177 | ``` |
| 178 | |
David Tolnay | f594f18 | 2018-09-01 20:10:08 -0700 | [diff] [blame] | 179 | ## Parsing a custom syntax |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 180 | |
| 181 | The [`lazy-static`] example directory shows the implementation of a |
| 182 | `functionlike!(...)` procedural macro in which the input tokens are parsed using |
David Tolnay | f594f18 | 2018-09-01 20:10:08 -0700 | [diff] [blame] | 183 | Syn's parsing API. |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 184 | |
| 185 | [`lazy-static`]: examples/lazy-static |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 186 | |
| 187 | The example reimplements the popular `lazy_static` crate from crates.io as a |
| 188 | procedural macro. |
| 189 | |
| 190 | ``` |
| 191 | lazy_static! { |
| 192 | static ref USERNAME: Regex = Regex::new("^[a-z0-9_-]{3,16}$").unwrap(); |
| 193 | } |
| 194 | ``` |
| 195 | |
| 196 | The implementation shows how to trigger custom warnings and error messages on |
| 197 | the macro input. |
| 198 | |
| 199 | ``` |
| 200 | warning: come on, pick a more creative name |
| 201 | --> src/main.rs:10:16 |
| 202 | | |
| 203 | 10 | static ref FOO: String = "lazy_static".to_owned(); |
| 204 | | ^^^ |
| 205 | ``` |
| 206 | |
David Tolnay | 941c092 | 2016-12-22 16:06:27 -0500 | [diff] [blame] | 207 | ## Debugging |
| 208 | |
| 209 | When developing a procedural macro it can be helpful to look at what the |
| 210 | generated code looks like. Use `cargo rustc -- -Zunstable-options |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 211 | --pretty=expanded` or the [`cargo expand`] subcommand. |
| 212 | |
| 213 | [`cargo expand`]: https://github.com/dtolnay/cargo-expand |
David Tolnay | 941c092 | 2016-12-22 16:06:27 -0500 | [diff] [blame] | 214 | |
| 215 | To show the expanded code for some crate that uses your procedural macro, run |
| 216 | `cargo expand` from that crate. To show the expanded code for one of your own |
| 217 | test cases, run `cargo expand --test the_test_case` where the last argument is |
| 218 | the name of the test file without the `.rs` extension. |
| 219 | |
David Tolnay | 3bfbd54 | 2017-01-16 14:57:53 -0800 | [diff] [blame] | 220 | This write-up by Brandon W Maister discusses debugging in more detail: |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 221 | [Debugging Rust's new Custom Derive system][debugging]. |
| 222 | |
| 223 | [debugging]: https://quodlibetor.github.io/posts/debugging-rusts-new-custom-derive-system/ |
David Tolnay | 3bfbd54 | 2017-01-16 14:57:53 -0800 | [diff] [blame] | 224 | |
David Tolnay | 686f504 | 2016-10-30 19:24:51 -0700 | [diff] [blame] | 225 | ## Optional features |
| 226 | |
| 227 | Syn puts a lot of functionality behind optional features in order to optimize |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 228 | compile time for the most common use cases. The following features are |
| 229 | available. |
David Tolnay | 686f504 | 2016-10-30 19:24:51 -0700 | [diff] [blame] | 230 | |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 231 | - **`derive`** *(enabled by default)* — Data structures for representing the |
| 232 | possible input to a custom derive, including structs and enums and types. |
| 233 | - **`full`** — Data structures for representing the syntax tree of all valid |
| 234 | Rust source code, including items and expressions. |
| 235 | - **`parsing`** *(enabled by default)* — Ability to parse input tokens into a |
| 236 | syntax tree node of a chosen type. |
| 237 | - **`printing`** *(enabled by default)* — Ability to print a syntax tree node as |
| 238 | tokens of Rust source code. |
| 239 | - **`visit`** — Trait for traversing a syntax tree. |
| 240 | - **`visit-mut`** — Trait for traversing and mutating in place a syntax tree. |
| 241 | - **`fold`** — Trait for transforming an owned syntax tree. |
| 242 | - **`clone-impls`** *(enabled by default)* — Clone impls for all syntax tree |
| 243 | types. |
| 244 | - **`extra-traits`** — Debug, Eq, PartialEq, Hash impls for all syntax tree |
| 245 | types. |
David Tolnay | d236b55 | 2018-04-08 09:02:55 -0700 | [diff] [blame] | 246 | - **`proc-macro`** *(enabled by default)* — Runtime dependency on the dynamic |
| 247 | library libproc_macro from rustc toolchain. |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 248 | |
| 249 | ## Nightly features |
| 250 | |
| 251 | By default Syn uses the [`proc-macro2`] crate to emulate the nightly compiler's |
| 252 | procedural macro API in a stable way that works all the way back to Rust 1.15.0. |
| 253 | This shim makes it possible to write code without regard for whether the current |
| 254 | compiler version supports the features we use. |
| 255 | |
| 256 | [`proc-macro2`]: https://github.com/alexcrichton/proc-macro2 |
| 257 | |
| 258 | On a nightly compiler, to eliminate the stable shim and use the compiler's |
| 259 | `proc-macro` directly, add `proc-macro2` to your Cargo.toml and set its |
| 260 | `"nightly"` feature which bypasses the stable shim. |
| 261 | |
| 262 | ```toml |
| 263 | [dependencies] |
David Tolnay | 87003d0 | 2018-05-20 19:45:13 -0700 | [diff] [blame] | 264 | syn = "0.14" |
| 265 | proc-macro2 = { version = "0.4", features = ["nightly"] } |
David Tolnay | c088adb | 2018-01-01 00:26:05 -0500 | [diff] [blame] | 266 | ``` |
David Tolnay | ed7a508 | 2016-10-30 20:06:29 -0700 | [diff] [blame] | 267 | |
David Tolnay | 35161ff | 2016-09-03 11:33:15 -0700 | [diff] [blame] | 268 | ## License |
| 269 | |
| 270 | Licensed under either of |
| 271 | |
| 272 | * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) |
| 273 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) |
| 274 | |
| 275 | at your option. |
| 276 | |
| 277 | ### Contribution |
| 278 | |
| 279 | Unless you explicitly state otherwise, any contribution intentionally submitted |
| 280 | for inclusion in this crate by you, as defined in the Apache-2.0 license, shall |
| 281 | be dual licensed as above, without any additional terms or conditions. |