blob: 2f05a3aa57556d54c29cc7440bbd18c8cf57ab5e [file] [log] [blame]
David Tolnay55535012018-01-05 16:39:23 -08001// Copyright 2018 Syn Developers
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
David Tolnay5e84e972018-01-05 17:51:06 -08009//! Syn is a parsing library for parsing a stream of Rust tokens into a syntax
10//! tree of Rust source code.
11//!
12//! Currently this library is geared toward the [custom derive] use case but
13//! contains some APIs that may be useful for Rust procedural macros more
14//! generally.
15//!
16//! [custom derive]: https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md
17//!
18//! - **Data structures** — Syn provides a complete syntax tree that can
19//! represent any valid Rust source code. The syntax tree is rooted at
20//! [`syn::File`] which represents a full source file, but there are other
21//! entry points that may be useful to procedural macros including
22//! [`syn::Item`], [`syn::Expr`] and [`syn::Type`].
23//!
24//! - **Custom derives** — Of particular interest to custom derives is
25//! [`syn::DeriveInput`] which is any of the three legal input items to a
26//! derive macro. An example below shows using this type in a library that can
27//! derive implementations of a trait of your own.
28//!
29//! - **Parser combinators** — Parsing in Syn is built on a suite of public
30//! parser combinator macros that you can use for parsing any token-based
31//! syntax you dream up within a `functionlike!(...)` procedural macro. Every
32//! syntax tree node defined by Syn is individually parsable and may be used
33//! as a building block for custom syntaxes, or you may do it all yourself
34//! working from the most primitive tokens.
35//!
36//! - **Location information** — Every token parsed by Syn is associated with a
37//! `Span` that tracks line and column information back to the source of that
38//! token. These spans allow a procedural macro to display detailed error
39//! messages pointing to all the right places in the user's code. There is an
40//! example of this below.
41//!
42//! - **Feature flags** — Functionality is aggressively feature gated so your
43//! procedural macros enable only what they need, and do not pay in compile
44//! time for all the rest.
45//!
46//! [`syn::File`]: struct.File.html
47//! [`syn::Item`]: enum.Item.html
48//! [`syn::Expr`]: enum.Expr.html
49//! [`syn::Type`]: enum.Type.html
50//! [`syn::DeriveInput`]: struct.DeriveInput.html
51//!
52//! *Version requirement: Syn supports any compiler version back to Rust's very
53//! first support for procedural macros in Rust 1.15.0. Some features especially
54//! around error reporting are only available in newer compilers or on the
55//! nightly channel.*
56//!
57//! ## Example of a custom derive
58//!
59//! The canonical custom derive using Syn looks like this. We write an ordinary
60//! Rust function tagged with a `proc_macro_derive` attribute and the name of
61//! the trait we are deriving. Any time that derive appears in the user's code,
62//! the Rust compiler passes their data structure as tokens into our macro. We
63//! get to execute arbitrary Rust code to figure out what to do with those
64//! tokens, then hand some tokens back to the compiler to compile into the
65//! user's crate.
66//!
67//! [`TokenStream`]: https://doc.rust-lang.org/proc_macro/struct.TokenStream.html
68//!
69//! ```toml
70//! [dependencies]
David Tolnay87003d02018-05-20 19:45:13 -070071//! syn = "0.14"
72//! quote = "0.6"
David Tolnay5e84e972018-01-05 17:51:06 -080073//!
74//! [lib]
75//! proc-macro = true
76//! ```
77//!
78//! ```rust
David Tolnay9b00f652018-09-01 10:31:02 -070079//! # extern crate proc_macro;
80//! # extern crate quote;
81//! # extern crate syn;
82//! #
David Tolnay5e84e972018-01-05 17:51:06 -080083//! use proc_macro::TokenStream;
David Tolnay9b00f652018-09-01 10:31:02 -070084//! use quote::quote;
David Tolnay5e84e972018-01-05 17:51:06 -080085//! use syn::DeriveInput;
86//!
87//! # const IGNORE_TOKENS: &str = stringify! {
88//! #[proc_macro_derive(MyMacro)]
89//! # };
90//! pub fn my_macro(input: TokenStream) -> TokenStream {
91//! // Parse the input tokens into a syntax tree
92//! let input: DeriveInput = syn::parse(input).unwrap();
93//!
94//! // Build the output, possibly using quasi-quotation
95//! let expanded = quote! {
96//! // ...
97//! };
98//!
99//! // Hand the output tokens back to the compiler
100//! expanded.into()
101//! }
102//! #
103//! # fn main() {}
104//! ```
105//!
106//! The [`heapsize`] example directory shows a complete working Macros 1.1
107//! implementation of a custom derive. It works on any Rust compiler \>=1.15.0.
108//! The example derives a `HeapSize` trait which computes an estimate of the
109//! amount of heap memory owned by a value.
110//!
111//! [`heapsize`]: https://github.com/dtolnay/syn/tree/master/examples/heapsize
112//!
113//! ```rust
114//! pub trait HeapSize {
115//! /// Total number of bytes of heap memory owned by `self`.
116//! fn heap_size_of_children(&self) -> usize;
117//! }
118//! ```
119//!
120//! The custom derive allows users to write `#[derive(HeapSize)]` on data
121//! structures in their program.
122//!
123//! ```rust
124//! # const IGNORE_TOKENS: &str = stringify! {
125//! #[derive(HeapSize)]
126//! # };
127//! struct Demo<'a, T: ?Sized> {
128//! a: Box<T>,
129//! b: u8,
130//! c: &'a str,
131//! d: String,
132//! }
133//! ```
134//!
135//! ## Spans and error reporting
136//!
137//! The [`heapsize2`] example directory is an extension of the `heapsize`
138//! example that demonstrates some of the hygiene and error reporting properties
139//! of Macros 2.0. This example currently requires a nightly Rust compiler
140//! \>=1.24.0-nightly but we are working to stabilize all of the APIs involved.
141//!
142//! [`heapsize2`]: https://github.com/dtolnay/syn/tree/master/examples/heapsize2
143//!
144//! The token-based procedural macro API provides great control over where the
145//! compiler's error messages are displayed in user code. Consider the error the
146//! user sees if one of their field types does not implement `HeapSize`.
147//!
148//! ```rust
149//! # const IGNORE_TOKENS: &str = stringify! {
150//! #[derive(HeapSize)]
151//! # };
152//! struct Broken {
153//! ok: String,
154//! bad: std::thread::Thread,
155//! }
156//! ```
157//!
158//! In the Macros 1.1 string-based procedural macro world, the resulting error
159//! would point unhelpfully to the invocation of the derive macro and not to the
160//! actual problematic field.
161//!
162//! ```text
163//! error[E0599]: no method named `heap_size_of_children` found for type `std::thread::Thread` in the current scope
164//! --> src/main.rs:4:10
165//! |
166//! 4 | #[derive(HeapSize)]
167//! | ^^^^^^^^
168//! ```
169//!
170//! By tracking span information all the way through the expansion of a
171//! procedural macro as shown in the `heapsize2` example, token-based macros in
172//! Syn are able to trigger errors that directly pinpoint the source of the
173//! problem.
174//!
175//! ```text
176//! error[E0277]: the trait bound `std::thread::Thread: HeapSize` is not satisfied
177//! --> src/main.rs:7:5
178//! |
179//! 7 | bad: std::thread::Thread,
David Tolnayefff2ff2018-01-07 11:49:52 -0800180//! | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HeapSize` is not implemented for `Thread`
David Tolnay5e84e972018-01-05 17:51:06 -0800181//! ```
182//!
183//! ## Parsing a custom syntax using combinators
184//!
185//! The [`lazy-static`] example directory shows the implementation of a
186//! `functionlike!(...)` procedural macro in which the input tokens are parsed
187//! using [`nom`]-style parser combinators.
188//!
189//! [`lazy-static`]: https://github.com/dtolnay/syn/tree/master/examples/lazy-static
190//! [`nom`]: https://github.com/Geal/nom
191//!
192//! The example reimplements the popular `lazy_static` crate from crates.io as a
193//! procedural macro.
194//!
195//! ```
196//! # macro_rules! lazy_static {
197//! # ($($tt:tt)*) => {}
198//! # }
199//! #
200//! lazy_static! {
201//! static ref USERNAME: Regex = Regex::new("^[a-z0-9_-]{3,16}$").unwrap();
202//! }
203//! ```
204//!
205//! The implementation shows how to trigger custom warnings and error messages
206//! on the macro input.
207//!
208//! ```text
209//! warning: come on, pick a more creative name
210//! --> src/main.rs:10:16
211//! |
212//! 10 | static ref FOO: String = "lazy_static".to_owned();
213//! | ^^^
214//! ```
215//!
216//! ## Debugging
217//!
218//! When developing a procedural macro it can be helpful to look at what the
219//! generated code looks like. Use `cargo rustc -- -Zunstable-options
220//! --pretty=expanded` or the [`cargo expand`] subcommand.
221//!
David Tolnay324db2d2018-01-07 11:51:09 -0800222//! [`cargo expand`]: https://github.com/dtolnay/cargo-expand
David Tolnay5e84e972018-01-05 17:51:06 -0800223//!
224//! To show the expanded code for some crate that uses your procedural macro,
225//! run `cargo expand` from that crate. To show the expanded code for one of
226//! your own test cases, run `cargo expand --test the_test_case` where the last
227//! argument is the name of the test file without the `.rs` extension.
228//!
229//! This write-up by Brandon W Maister discusses debugging in more detail:
230//! [Debugging Rust's new Custom Derive system][debugging].
231//!
232//! [debugging]: https://quodlibetor.github.io/posts/debugging-rusts-new-custom-derive-system/
233//!
234//! ## Optional features
235//!
236//! Syn puts a lot of functionality behind optional features in order to
237//! optimize compile time for the most common use cases. The following features
238//! are available.
239//!
240//! - **`derive`** *(enabled by default)* — Data structures for representing the
241//! possible input to a custom derive, including structs and enums and types.
242//! - **`full`** — Data structures for representing the syntax tree of all valid
243//! Rust source code, including items and expressions.
244//! - **`parsing`** *(enabled by default)* — Ability to parse input tokens into
245//! a syntax tree node of a chosen type.
246//! - **`printing`** *(enabled by default)* — Ability to print a syntax tree
247//! node as tokens of Rust source code.
248//! - **`visit`** — Trait for traversing a syntax tree.
David Tolnay34981cf2018-01-06 16:22:35 -0800249//! - **`visit-mut`** — Trait for traversing and mutating in place a syntax
David Tolnay5e84e972018-01-05 17:51:06 -0800250//! tree.
251//! - **`fold`** — Trait for transforming an owned syntax tree.
252//! - **`clone-impls`** *(enabled by default)* — Clone impls for all syntax tree
253//! types.
254//! - **`extra-traits`** — Debug, Eq, PartialEq, Hash impls for all syntax tree
255//! types.
hcpl4b72a382018-04-04 14:50:24 +0300256//! - **`proc-macro`** *(enabled by default)* — Runtime dependency on the
257//! dynamic library libproc_macro from rustc toolchain.
David Tolnay5e84e972018-01-05 17:51:06 -0800258
David Tolnay4cf7db82018-01-07 15:22:01 -0800259// Syn types in rustdoc of other crates get linked to here.
David Tolnaye6ec9e02018-08-21 21:32:03 -0400260#![doc(html_root_url = "https://docs.rs/syn/0.14.9")]
David Tolnay34071ba2018-05-20 20:00:41 -0700261#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
David Tolnay34071ba2018-05-20 20:00:41 -0700262// Ignored clippy lints.
David Tolnay94d2b792018-04-29 12:26:10 -0700263#![cfg_attr(
264 feature = "cargo-clippy",
265 allow(
David Tolnay4831ac62018-08-30 21:04:16 -0700266 block_in_if_condition_stmt,
David Tolnay0cec3e62018-07-21 09:08:30 -0700267 const_static_lifetime,
David Tolnay24b079d2018-08-27 08:28:10 -0700268 cyclomatic_complexity,
David Tolnay0cec3e62018-07-21 09:08:30 -0700269 doc_markdown,
David Tolnay24b079d2018-08-27 08:28:10 -0700270 eval_order_dependence,
David Tolnay0cec3e62018-07-21 09:08:30 -0700271 large_enum_variant,
272 match_bool,
David Tolnay6fb87462018-09-01 16:51:49 -0700273 never_loop,
David Tolnay0cec3e62018-07-21 09:08:30 -0700274 redundant_closure,
275 needless_pass_by_value,
276 redundant_field_names,
277 trivially_copy_pass_by_ref
David Tolnay94d2b792018-04-29 12:26:10 -0700278 )
279)]
David Tolnay34071ba2018-05-20 20:00:41 -0700280// Ignored clippy_pedantic lints.
281#![cfg_attr(
282 feature = "cargo-clippy",
283 allow(
David Tolnay0cec3e62018-07-21 09:08:30 -0700284 cast_possible_truncation,
285 cast_possible_wrap,
David Tolnayb1617752018-08-24 21:16:33 -0400286 empty_enum,
David Tolnay0cec3e62018-07-21 09:08:30 -0700287 if_not_else,
288 indexing_slicing,
289 items_after_statements,
David Tolnay151f92f2018-08-14 22:44:53 -0700290 shadow_unrelated,
David Tolnay0cec3e62018-07-21 09:08:30 -0700291 similar_names,
292 single_match_else,
293 stutter,
294 unseparated_literal_suffix,
295 use_self,
296 used_underscore_binding
David Tolnay34071ba2018-05-20 20:00:41 -0700297 )
298)]
David Tolnayad2836d2017-04-20 10:11:43 -0700299
David Tolnay278f9e32018-08-14 22:41:11 -0700300#[cfg(all(
301 not(all(target_arch = "wasm32", target_os = "unknown")),
302 feature = "proc-macro"
303))]
David Tolnay51382052017-12-27 13:46:21 -0500304extern crate proc_macro;
David Tolnay94d2b792018-04-29 12:26:10 -0700305extern crate proc_macro2;
David Tolnay570695e2017-06-03 16:15:13 -0700306extern crate unicode_xid;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700307
David Tolnay1cf80912017-12-31 18:35:12 -0500308#[cfg(feature = "printing")]
David Tolnay87d0b442016-09-04 11:52:12 -0700309extern crate quote;
310
Alex Crichton62a0a592017-05-22 13:58:53 -0700311#[macro_use]
312mod macros;
313
David Tolnay734079e2018-09-01 02:03:37 -0700314// Not public API.
David Tolnay852bff72018-08-27 08:24:02 -0700315#[cfg(feature = "parsing")]
David Tolnay734079e2018-09-01 02:03:37 -0700316#[doc(hidden)]
David Tolnay852bff72018-08-27 08:24:02 -0700317#[macro_use]
David Tolnay734079e2018-09-01 02:03:37 -0700318pub mod group;
David Tolnay852bff72018-08-27 08:24:02 -0700319
David Tolnayc5ab8c62017-12-26 16:43:39 -0500320#[macro_use]
David Tolnay32954ef2017-12-26 22:43:16 -0500321pub mod token;
David Tolnayc5ab8c62017-12-26 16:43:39 -0500322
David Tolnay4fb71232018-08-25 23:14:50 -0400323mod ident;
324pub use ident::Ident;
David Tolnaye303b7c2018-05-20 16:46:35 -0700325
David Tolnay3cfd1d32018-01-03 00:22:08 -0800326#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayb79ee962016-09-04 09:39:20 -0700327mod attr;
David Tolnay3cfd1d32018-01-03 00:22:08 -0800328#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayaaadd782018-01-06 22:58:13 -0800329pub use attr::{AttrStyle, Attribute, Meta, MetaList, MetaNameValue, NestedMeta};
David Tolnay35161ff2016-09-03 11:33:15 -0700330
David Tolnay3cfd1d32018-01-03 00:22:08 -0800331#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayf38cdf62016-09-23 19:07:09 -0700332mod data;
David Tolnay3cfd1d32018-01-03 00:22:08 -0800333#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayb57c8492018-05-05 00:32:04 -0700334pub use data::{
335 Field, Fields, FieldsNamed, FieldsUnnamed, Variant, VisCrate, VisPublic, VisRestricted,
336 Visibility,
337};
David Tolnayf38cdf62016-09-23 19:07:09 -0700338
David Tolnay3cfd1d32018-01-03 00:22:08 -0800339#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayf4bbbd92016-09-23 14:41:55 -0700340mod expr;
David Tolnay3cfd1d32018-01-03 00:22:08 -0800341#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayb57c8492018-05-05 00:32:04 -0700342pub use expr::{
David Tolnay02a9c6f2018-08-24 18:58:45 -0400343 Expr, ExprArray, ExprAssign, ExprAssignOp, ExprAsync, ExprBinary, ExprBlock, ExprBox,
344 ExprBreak, ExprCall, ExprCast, ExprClosure, ExprContinue, ExprField, ExprForLoop, ExprGroup,
David Tolnay9c119122018-09-01 18:47:02 -0700345 ExprIf, ExprInPlace, ExprIndex, ExprLet, ExprLit, ExprLoop, ExprMacro, ExprMatch,
David Tolnay02a9c6f2018-08-24 18:58:45 -0400346 ExprMethodCall, ExprParen, ExprPath, ExprRange, ExprReference, ExprRepeat, ExprReturn,
347 ExprStruct, ExprTry, ExprTryBlock, ExprTuple, ExprType, ExprUnary, ExprUnsafe, ExprVerbatim,
David Tolnay9c119122018-09-01 18:47:02 -0700348 ExprWhile, ExprYield, Index, Member,
David Tolnayb57c8492018-05-05 00:32:04 -0700349};
Michael Layzell734adb42017-06-07 16:58:31 -0400350
351#[cfg(feature = "full")]
David Tolnayb57c8492018-05-05 00:32:04 -0700352pub use expr::{
353 Arm, Block, FieldPat, FieldValue, GenericMethodArgument, Label, Local, MethodTurbofish, Pat,
354 PatBox, PatIdent, PatLit, PatMacro, PatPath, PatRange, PatRef, PatSlice, PatStruct, PatTuple,
355 PatTupleStruct, PatVerbatim, PatWild, RangeLimits, Stmt,
356};
David Tolnayf4bbbd92016-09-23 14:41:55 -0700357
David Tolnay3cfd1d32018-01-03 00:22:08 -0800358#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayb79ee962016-09-04 09:39:20 -0700359mod generics;
David Tolnay3cfd1d32018-01-03 00:22:08 -0800360#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayb57c8492018-05-05 00:32:04 -0700361pub use generics::{
362 BoundLifetimes, ConstParam, GenericParam, Generics, LifetimeDef, PredicateEq,
363 PredicateLifetime, PredicateType, TraitBound, TraitBoundModifier, TypeParam, TypeParamBound,
364 WhereClause, WherePredicate,
365};
David Tolnay278f9e32018-08-14 22:41:11 -0700366#[cfg(all(
367 any(feature = "full", feature = "derive"),
368 feature = "printing"
369))]
David Tolnayfd6bf5c2017-11-12 09:41:14 -0800370pub use generics::{ImplGenerics, Turbofish, TypeGenerics};
David Tolnay35161ff2016-09-03 11:33:15 -0700371
David Tolnayf38cdf62016-09-23 19:07:09 -0700372#[cfg(feature = "full")]
David Tolnayb79ee962016-09-04 09:39:20 -0700373mod item;
David Tolnayf38cdf62016-09-23 19:07:09 -0700374#[cfg(feature = "full")]
David Tolnayb57c8492018-05-05 00:32:04 -0700375pub use item::{
David Tolnay435c1782018-08-24 16:15:44 -0400376 ArgCaptured, ArgSelf, ArgSelfRef, FnArg, FnDecl, ForeignItem, ForeignItemFn, ForeignItemMacro,
377 ForeignItemStatic, ForeignItemType, ForeignItemVerbatim, ImplItem, ImplItemConst,
David Tolnaybb82ef02018-08-24 20:15:45 -0400378 ImplItemExistential, ImplItemMacro, ImplItemMethod, ImplItemType, ImplItemVerbatim, Item,
379 ItemConst, ItemEnum, ItemExistential, ItemExternCrate, ItemFn, ItemForeignMod, ItemImpl,
David Tolnayc6b04dd2018-08-30 23:22:51 -0700380 ItemMacro, ItemMacro2, ItemMod, ItemStatic, ItemStruct, ItemTrait, ItemTraitAlias, ItemType,
381 ItemUnion, ItemUse, ItemVerbatim, MethodSig, TraitItem, TraitItemConst, TraitItemMacro,
382 TraitItemMethod, TraitItemType, TraitItemVerbatim, UseGlob, UseGroup, UseName, UsePath,
383 UseRename, UseTree,
David Tolnayb57c8492018-05-05 00:32:04 -0700384};
David Tolnay35161ff2016-09-03 11:33:15 -0700385
David Tolnay631cb8c2016-11-10 17:16:41 -0800386#[cfg(feature = "full")]
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700387mod file;
David Tolnay631cb8c2016-11-10 17:16:41 -0800388#[cfg(feature = "full")]
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700389pub use file::File;
David Tolnay631cb8c2016-11-10 17:16:41 -0800390
David Tolnay63e3dee2017-06-03 20:13:17 -0700391mod lifetime;
392pub use lifetime::Lifetime;
393
David Tolnay3cfd1d32018-01-03 00:22:08 -0800394#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayf4bbbd92016-09-23 14:41:55 -0700395mod lit;
David Tolnay3cfd1d32018-01-03 00:22:08 -0800396#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayb57c8492018-05-05 00:32:04 -0700397pub use lit::{
398 FloatSuffix, IntSuffix, Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr,
399 LitVerbatim, StrStyle,
400};
David Tolnayf4bbbd92016-09-23 14:41:55 -0700401
David Tolnay3cfd1d32018-01-03 00:22:08 -0800402#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayf4bbbd92016-09-23 14:41:55 -0700403mod mac;
David Tolnay3cfd1d32018-01-03 00:22:08 -0800404#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayab919512017-12-30 23:31:51 -0500405pub use mac::{Macro, MacroDelimiter};
David Tolnayf4bbbd92016-09-23 14:41:55 -0700406
David Tolnay3cfd1d32018-01-03 00:22:08 -0800407#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay0e837402016-12-22 17:25:55 -0500408mod derive;
David Tolnay3cfd1d32018-01-03 00:22:08 -0800409#[cfg(feature = "derive")]
David Tolnaye3d41b72017-12-31 15:24:00 -0500410pub use derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput};
David Tolnayf38cdf62016-09-23 19:07:09 -0700411
David Tolnay3cfd1d32018-01-03 00:22:08 -0800412#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay3cb23a92016-10-07 23:02:21 -0700413mod op;
David Tolnay3cfd1d32018-01-03 00:22:08 -0800414#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay3cb23a92016-10-07 23:02:21 -0700415pub use op::{BinOp, UnOp};
416
David Tolnay3cfd1d32018-01-03 00:22:08 -0800417#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayb79ee962016-09-04 09:39:20 -0700418mod ty;
David Tolnay3cfd1d32018-01-03 00:22:08 -0800419#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayb57c8492018-05-05 00:32:04 -0700420pub use ty::{
421 Abi, BareFnArg, BareFnArgName, ReturnType, Type, TypeArray, TypeBareFn, TypeGroup,
422 TypeImplTrait, TypeInfer, TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, TypeReference,
423 TypeSlice, TypeTraitObject, TypeTuple, TypeVerbatim,
424};
David Tolnay056de302018-01-05 14:29:05 -0800425
426#[cfg(any(feature = "full", feature = "derive"))]
427mod path;
428#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayb57c8492018-05-05 00:32:04 -0700429pub use path::{
430 AngleBracketedGenericArguments, Binding, GenericArgument, ParenthesizedGenericArguments, Path,
431 PathArguments, PathSegment, QSelf,
432};
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700433
David Tolnay1b752fb2017-12-26 21:41:39 -0500434#[cfg(feature = "parsing")]
David Tolnaydfc886b2018-01-06 08:03:09 -0800435pub mod buffer;
David Tolnay94d304f2018-08-30 23:43:53 -0700436#[cfg(feature = "parsing")]
437pub mod ext;
David Tolnay94d2b792018-04-29 12:26:10 -0700438pub mod punctuated;
David Tolnay3779bb72018-08-26 18:46:07 -0700439#[cfg(all(
440 any(feature = "full", feature = "derive"),
441 feature = "extra-traits"
442))]
David Tolnaye0824032017-12-27 15:25:56 -0500443mod tt;
David Tolnayc5ab8c62017-12-26 16:43:39 -0500444
David Tolnaye83ef5a2018-01-11 15:18:36 -0800445// Not public API except the `parse_quote!` macro.
David Tolnay491680a2018-01-23 00:34:40 -0800446#[cfg(feature = "parsing")]
David Tolnaye83ef5a2018-01-11 15:18:36 -0800447#[doc(hidden)]
448pub mod parse_quote;
449
David Tolnay4d942b42018-01-02 22:14:04 -0800450#[cfg(all(feature = "parsing", feature = "printing"))]
David Tolnayf790b612017-12-31 18:46:57 -0500451pub mod spanned;
452
Nika Layzella6f46c42017-10-26 15:26:16 -0400453mod gen {
David Tolnayded2d682018-01-06 18:53:53 -0800454 /// Syntax tree traversal to walk a shared borrow of a syntax tree.
455 ///
456 /// Each method of the [`Visit`] trait is a hook that can be overridden to
457 /// customize the behavior when visiting the corresponding type of node. By
458 /// default, every method recursively visits the substructure of the input
459 /// by invoking the right visitor method of each of its fields.
460 ///
461 /// [`Visit`]: trait.Visit.html
462 ///
463 /// ```rust
464 /// # use syn::{Attribute, BinOp, Expr, ExprBinary};
465 /// #
466 /// pub trait Visit<'ast> {
467 /// /* ... */
468 ///
469 /// fn visit_expr_binary(&mut self, node: &'ast ExprBinary) {
470 /// for attr in &node.attrs {
471 /// self.visit_attribute(attr);
472 /// }
473 /// self.visit_expr(&*node.left);
474 /// self.visit_bin_op(&node.op);
475 /// self.visit_expr(&*node.right);
476 /// }
477 ///
478 /// /* ... */
479 /// # fn visit_attribute(&mut self, node: &'ast Attribute);
480 /// # fn visit_expr(&mut self, node: &'ast Expr);
481 /// # fn visit_bin_op(&mut self, node: &'ast BinOp);
482 /// }
483 /// ```
David Tolnay461d98e2018-01-07 11:07:19 -0800484 ///
485 /// *This module is available if Syn is built with the `"visit"` feature.*
Nika Layzella6f46c42017-10-26 15:26:16 -0400486 #[cfg(feature = "visit")]
487 pub mod visit;
David Tolnay55337722016-09-11 12:58:56 -0700488
David Tolnayded2d682018-01-06 18:53:53 -0800489 /// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in
490 /// place.
491 ///
492 /// Each method of the [`VisitMut`] trait is a hook that can be overridden
493 /// to customize the behavior when mutating the corresponding type of node.
494 /// By default, every method recursively visits the substructure of the
495 /// input by invoking the right visitor method of each of its fields.
496 ///
497 /// [`VisitMut`]: trait.VisitMut.html
498 ///
499 /// ```rust
500 /// # use syn::{Attribute, BinOp, Expr, ExprBinary};
501 /// #
502 /// pub trait VisitMut {
503 /// /* ... */
504 ///
505 /// fn visit_expr_binary_mut(&mut self, node: &mut ExprBinary) {
506 /// for attr in &mut node.attrs {
507 /// self.visit_attribute_mut(attr);
508 /// }
509 /// self.visit_expr_mut(&mut *node.left);
510 /// self.visit_bin_op_mut(&mut node.op);
511 /// self.visit_expr_mut(&mut *node.right);
512 /// }
513 ///
514 /// /* ... */
515 /// # fn visit_attribute_mut(&mut self, node: &mut Attribute);
516 /// # fn visit_expr_mut(&mut self, node: &mut Expr);
517 /// # fn visit_bin_op_mut(&mut self, node: &mut BinOp);
518 /// }
519 /// ```
David Tolnay461d98e2018-01-07 11:07:19 -0800520 ///
521 /// *This module is available if Syn is built with the `"visit-mut"`
522 /// feature.*
David Tolnay9df02c42018-01-06 13:52:48 -0800523 #[cfg(feature = "visit-mut")]
Nika Layzella6f46c42017-10-26 15:26:16 -0400524 pub mod visit_mut;
Nika Layzell27726662017-10-24 23:16:35 -0400525
David Tolnayded2d682018-01-06 18:53:53 -0800526 /// Syntax tree traversal to transform the nodes of an owned syntax tree.
527 ///
528 /// Each method of the [`Fold`] trait is a hook that can be overridden to
529 /// customize the behavior when transforming the corresponding type of node.
530 /// By default, every method recursively visits the substructure of the
531 /// input by invoking the right visitor method of each of its fields.
532 ///
533 /// [`Fold`]: trait.Fold.html
534 ///
535 /// ```rust
536 /// # use syn::{Attribute, BinOp, Expr, ExprBinary};
537 /// #
538 /// pub trait Fold {
539 /// /* ... */
540 ///
541 /// fn fold_expr_binary(&mut self, node: ExprBinary) -> ExprBinary {
542 /// ExprBinary {
543 /// attrs: node.attrs
544 /// .into_iter()
545 /// .map(|attr| self.fold_attribute(attr))
546 /// .collect(),
547 /// left: Box::new(self.fold_expr(*node.left)),
548 /// op: self.fold_bin_op(node.op),
549 /// right: Box::new(self.fold_expr(*node.right)),
550 /// }
551 /// }
552 ///
553 /// /* ... */
554 /// # fn fold_attribute(&mut self, node: Attribute) -> Attribute;
555 /// # fn fold_expr(&mut self, node: Expr) -> Expr;
556 /// # fn fold_bin_op(&mut self, node: BinOp) -> BinOp;
557 /// }
558 /// ```
David Tolnay461d98e2018-01-07 11:07:19 -0800559 ///
560 /// *This module is available if Syn is built with the `"fold"` feature.*
Nika Layzella6f46c42017-10-26 15:26:16 -0400561 #[cfg(feature = "fold")]
562 pub mod fold;
David Tolnayf60f4262017-12-28 19:17:58 -0500563
David Tolnay0a0d78c2018-01-05 15:24:01 -0800564 #[cfg(any(feature = "full", feature = "derive"))]
David Tolnayf60f4262017-12-28 19:17:58 -0500565 #[path = "../gen_helper.rs"]
566 mod helper;
Nika Layzella6f46c42017-10-26 15:26:16 -0400567}
568pub use gen::*;
gnzlbg9ae88d82017-01-26 20:45:17 +0100569
David Tolnay456c9822018-08-25 08:09:46 -0400570// Not public API.
571#[doc(hidden)]
572pub mod export;
573
David Tolnay776f8e02018-08-24 22:32:10 -0400574#[cfg(feature = "parsing")]
David Tolnayb6254182018-08-25 08:44:54 -0400575mod lookahead;
576
577#[cfg(feature = "parsing")]
578pub mod parse;
579
David Tolnay776f8e02018-08-24 22:32:10 -0400580mod span;
581
David Tolnay64023912018-08-31 09:51:12 -0700582#[cfg(all(
583 any(feature = "full", feature = "derive"),
584 feature = "printing"
585))]
586mod print;
587
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700588////////////////////////////////////////////////////////////////////////////////
589
David Tolnayaa77a852018-08-31 11:15:10 -0700590#[cfg(any(feature = "parsing", feature = "full", feature = "derive"))]
David Tolnay94f06632018-08-31 10:17:17 -0700591#[allow(non_camel_case_types)]
David Tolnay10951d52018-08-31 10:27:39 -0700592struct private;
David Tolnay94f06632018-08-31 10:17:17 -0700593
594////////////////////////////////////////////////////////////////////////////////
595
David Tolnay55337722016-09-11 12:58:56 -0700596#[cfg(feature = "parsing")]
David Tolnayb6254182018-08-25 08:44:54 -0400597mod error;
David Tolnayc5ab8c62017-12-26 16:43:39 -0500598#[cfg(feature = "parsing")]
David Tolnayad4b2472018-08-25 08:25:24 -0400599use error::Error;
David Tolnayc5ab8c62017-12-26 16:43:39 -0500600
David Tolnayccab0be2018-01-06 22:24:47 -0800601/// Parse tokens of source code into the chosen syntax tree node.
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700602///
603/// This is preferred over parsing a string because tokens are able to preserve
604/// information about where in the user's code they were originally written (the
605/// "span" of the token), possibly allowing the compiler to produce better error
606/// messages.
607///
David Tolnayccab0be2018-01-06 22:24:47 -0800608/// This function parses a `proc_macro::TokenStream` which is the type used for
609/// interop with the compiler in a procedural macro. To parse a
610/// `proc_macro2::TokenStream`, use [`syn::parse2`] instead.
611///
612/// [`syn::parse2`]: fn.parse2.html
613///
hcpl4b72a382018-04-04 14:50:24 +0300614/// *This function is available if Syn is built with both the `"parsing"` and
615/// `"proc-macro"` features.*
David Tolnay461d98e2018-01-07 11:07:19 -0800616///
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700617/// # Examples
618///
David Tolnaybcf26022017-12-25 22:10:52 -0500619/// ```rust
David Tolnay9b00f652018-09-01 10:31:02 -0700620/// # extern crate proc_macro;
621/// # extern crate quote;
622/// # extern crate syn;
623/// #
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700624/// use proc_macro::TokenStream;
David Tolnay9b00f652018-09-01 10:31:02 -0700625/// use quote::quote;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700626/// use syn::DeriveInput;
627///
David Tolnaybcf26022017-12-25 22:10:52 -0500628/// # const IGNORE_TOKENS: &str = stringify! {
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700629/// #[proc_macro_derive(MyMacro)]
David Tolnaybcf26022017-12-25 22:10:52 -0500630/// # };
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700631/// pub fn my_macro(input: TokenStream) -> TokenStream {
632/// // Parse the tokens into a syntax tree
633/// let ast: DeriveInput = syn::parse(input).unwrap();
634///
635/// // Build the output, possibly using quasi-quotation
636/// let expanded = quote! {
637/// /* ... */
638/// };
639///
David Tolnaybcf26022017-12-25 22:10:52 -0500640/// // Convert into a token stream and return it
641/// expanded.into()
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700642/// }
David Tolnaybcf26022017-12-25 22:10:52 -0500643/// #
644/// # fn main() {}
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700645/// ```
David Tolnay278f9e32018-08-14 22:41:11 -0700646#[cfg(all(
647 not(all(target_arch = "wasm32", target_os = "unknown")),
648 feature = "parsing",
649 feature = "proc-macro"
650))]
David Tolnaye82a2b12018-08-30 16:31:10 -0700651pub fn parse<T: parse::Parse>(tokens: proc_macro::TokenStream) -> Result<T, Error> {
David Tolnay80a914f2018-08-30 23:49:53 -0700652 parse::Parser::parse(T::parse, tokens)
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700653}
654
David Tolnayccab0be2018-01-06 22:24:47 -0800655/// Parse a proc-macro2 token stream into the chosen syntax tree node.
656///
657/// This function parses a `proc_macro2::TokenStream` which is commonly useful
658/// when the input comes from a node of the Syn syntax tree, for example the tts
659/// of a [`Macro`] node. When in a procedural macro parsing the
660/// `proc_macro::TokenStream` provided by the compiler, use [`syn::parse`]
661/// instead.
662///
663/// [`Macro`]: struct.Macro.html
664/// [`syn::parse`]: fn.parse.html
David Tolnay461d98e2018-01-07 11:07:19 -0800665///
666/// *This function is available if Syn is built with the `"parsing"` feature.*
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700667#[cfg(feature = "parsing")]
David Tolnaye82a2b12018-08-30 16:31:10 -0700668pub fn parse2<T: parse::Parse>(tokens: proc_macro2::TokenStream) -> Result<T, Error> {
David Tolnay80a914f2018-08-30 23:49:53 -0700669 parse::Parser::parse2(T::parse, tokens)
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700670}
Alex Crichton954046c2017-05-30 21:49:42 -0700671
David Tolnayccab0be2018-01-06 22:24:47 -0800672/// Parse a string of Rust code into the chosen syntax tree node.
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700673///
David Tolnay461d98e2018-01-07 11:07:19 -0800674/// *This function is available if Syn is built with the `"parsing"` feature.*
675///
David Tolnay3f5b06f2018-01-11 21:02:00 -0800676/// # Hygiene
677///
678/// Every span in the resulting syntax tree will be set to resolve at the macro
679/// call site.
680///
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700681/// # Examples
682///
683/// ```rust
David Tolnay9b00f652018-09-01 10:31:02 -0700684/// # extern crate syn;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700685/// #
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700686/// use syn::Expr;
David Tolnay9b00f652018-09-01 10:31:02 -0700687/// use syn::parse::Result;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700688///
689/// fn run() -> Result<()> {
690/// let code = "assert_eq!(u8::max_value(), 255)";
691/// let expr = syn::parse_str::<Expr>(code)?;
692/// println!("{:#?}", expr);
693/// Ok(())
694/// }
695/// #
696/// # fn main() { run().unwrap() }
697/// ```
698#[cfg(feature = "parsing")]
David Tolnaye82a2b12018-08-30 16:31:10 -0700699pub fn parse_str<T: parse::Parse>(s: &str) -> Result<T, Error> {
David Tolnay80a914f2018-08-30 23:49:53 -0700700 parse::Parser::parse_str(T::parse, s)
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700701}
Alex Crichton954046c2017-05-30 21:49:42 -0700702
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700703// FIXME the name parse_file makes it sound like you might pass in a path to a
704// file, rather than the content.
705/// Parse the content of a file of Rust code.
706///
707/// This is different from `syn::parse_str::<File>(content)` in two ways:
708///
709/// - It discards a leading byte order mark `\u{FEFF}` if the file has one.
710/// - It preserves the shebang line of the file, such as `#!/usr/bin/env rustx`.
711///
712/// If present, either of these would be an error using `from_str`.
713///
Christopher Serr9727ef22018-02-03 16:42:12 +0100714/// *This function is available if Syn is built with the `"parsing"` and `"full"` features.*
David Tolnay461d98e2018-01-07 11:07:19 -0800715///
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700716/// # Examples
717///
718/// ```rust,no_run
David Tolnay9b00f652018-09-01 10:31:02 -0700719/// # extern crate syn;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700720/// #
David Tolnay9b00f652018-09-01 10:31:02 -0700721/// use std::error::Error;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700722/// use std::fs::File;
723/// use std::io::Read;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700724///
David Tolnay9b00f652018-09-01 10:31:02 -0700725/// fn run() -> Result<(), Box<Error>> {
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700726/// let mut file = File::open("path/to/code.rs")?;
727/// let mut content = String::new();
728/// file.read_to_string(&mut content)?;
729///
730/// let ast = syn::parse_file(&content)?;
731/// if let Some(shebang) = ast.shebang {
732/// println!("{}", shebang);
733/// }
734/// println!("{} items", ast.items.len());
735///
736/// Ok(())
737/// }
738/// #
739/// # fn main() { run().unwrap() }
740/// ```
741#[cfg(all(feature = "parsing", feature = "full"))]
David Tolnayad4b2472018-08-25 08:25:24 -0400742pub fn parse_file(mut content: &str) -> Result<File, Error> {
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700743 // Strip the BOM if it is present
744 const BOM: &'static str = "\u{feff}";
745 if content.starts_with(BOM) {
746 content = &content[BOM.len()..];
David Tolnay35161ff2016-09-03 11:33:15 -0700747 }
Michael Layzell5e107ff2017-01-24 19:58:39 -0500748
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700749 let mut shebang = None;
750 if content.starts_with("#!") && !content.starts_with("#![") {
751 if let Some(idx) = content.find('\n') {
752 shebang = Some(content[..idx].to_string());
753 content = &content[idx..];
754 } else {
755 shebang = Some(content.to_string());
756 content = "";
757 }
Alex Crichton954046c2017-05-30 21:49:42 -0700758 }
David Tolnay0a8972b2017-02-27 02:10:01 -0800759
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700760 let mut file: File = parse_str(content)?;
761 file.shebang = shebang;
762 Ok(file)
Michael Layzell5e107ff2017-01-24 19:58:39 -0500763}
Alex Crichton259ee532017-07-14 06:51:02 -0700764
David Tolnayd641ee32018-08-30 17:11:09 -0700765/// Parse the input TokenStream of a macro, triggering a compile error if the
766/// tokens fail to parse.
767///
David Tolnay8580f972018-09-01 17:53:03 -0700768/// Refer to the [`parse` module] documentation for more details about parsing
769/// in Syn.
770///
771/// [`parse` module]: parse/index.html
772///
David Tolnayd641ee32018-08-30 17:11:09 -0700773/// # Intended usage
774///
775/// ```rust
776/// # extern crate proc_macro;
777/// # extern crate syn;
778/// #
779/// use proc_macro::TokenStream;
780/// use syn::parse_macro_input;
781/// use syn::parse::{Parse, ParseStream, Result};
782///
783/// struct MyMacroInput {
784/// /* ... */
785/// }
786///
787/// impl Parse for MyMacroInput {
788/// fn parse(input: ParseStream) -> Result<Self> {
789/// /* ... */
790/// # Ok(MyMacroInput {})
791/// }
792/// }
793///
794/// # const IGNORE: &str = stringify! {
795/// #[proc_macro]
796/// # };
797/// pub fn my_macro(tokens: TokenStream) -> TokenStream {
798/// let input = parse_macro_input!(tokens as MyMacroInput);
799///
800/// /* ... */
801/// # "".parse().unwrap()
802/// }
803/// #
804/// # fn main() {}
805/// ```
806#[cfg(feature = "proc-macro")]
807#[macro_export]
808macro_rules! parse_macro_input {
809 ($tokenstream:ident as $ty:ty) => {
David Tolnay02465352018-08-30 23:38:00 -0700810 match $crate::parse::<$ty>($tokenstream) {
David Tolnayd641ee32018-08-30 17:11:09 -0700811 $crate::export::Ok(data) => data,
812 $crate::export::Err(err) => {
813 return $crate::export::TokenStream::from(err.into_compile_error());
814 }
815 };
816 };
817}