]>
Commit | Line | Data |
---|---|---|
83c7162d XL |
1 | // 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 | ||
9 | //! 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] | |
71 | //! syn = "0.12" | |
72 | //! quote = "0.4" | |
73 | //! | |
74 | //! [lib] | |
75 | //! proc-macro = true | |
76 | //! ``` | |
77 | //! | |
78 | //! ```rust | |
79 | //! extern crate proc_macro; | |
80 | //! extern crate syn; | |
81 | //! | |
82 | //! #[macro_use] | |
83 | //! extern crate quote; | |
84 | //! | |
85 | //! use proc_macro::TokenStream; | |
86 | //! use syn::DeriveInput; | |
87 | //! | |
88 | //! # const IGNORE_TOKENS: &str = stringify! { | |
89 | //! #[proc_macro_derive(MyMacro)] | |
90 | //! # }; | |
91 | //! pub fn my_macro(input: TokenStream) -> TokenStream { | |
92 | //! // Parse the input tokens into a syntax tree | |
93 | //! let input: DeriveInput = syn::parse(input).unwrap(); | |
94 | //! | |
95 | //! // Build the output, possibly using quasi-quotation | |
96 | //! let expanded = quote! { | |
97 | //! // ... | |
98 | //! }; | |
99 | //! | |
100 | //! // Hand the output tokens back to the compiler | |
101 | //! expanded.into() | |
102 | //! } | |
103 | //! # | |
104 | //! # fn main() {} | |
105 | //! ``` | |
106 | //! | |
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. | |
109 | //! The example derives a `HeapSize` trait which computes an estimate of the | |
110 | //! amount of heap memory owned by a value. | |
111 | //! | |
112 | //! [`heapsize`]: https://github.com/dtolnay/syn/tree/master/examples/heapsize | |
113 | //! | |
114 | //! ```rust | |
115 | //! pub trait HeapSize { | |
116 | //! /// Total number of bytes of heap memory owned by `self`. | |
117 | //! fn heap_size_of_children(&self) -> usize; | |
118 | //! } | |
119 | //! ``` | |
120 | //! | |
121 | //! The custom derive allows users to write `#[derive(HeapSize)]` on data | |
122 | //! structures in their program. | |
123 | //! | |
124 | //! ```rust | |
125 | //! # const IGNORE_TOKENS: &str = stringify! { | |
126 | //! #[derive(HeapSize)] | |
127 | //! # }; | |
128 | //! struct Demo<'a, T: ?Sized> { | |
129 | //! a: Box<T>, | |
130 | //! b: u8, | |
131 | //! c: &'a str, | |
132 | //! d: String, | |
133 | //! } | |
134 | //! ``` | |
135 | //! | |
136 | //! ## Spans and error reporting | |
137 | //! | |
138 | //! The [`heapsize2`] example directory is an extension of the `heapsize` | |
139 | //! example that demonstrates some of the hygiene and error reporting properties | |
140 | //! of Macros 2.0. This example currently requires a nightly Rust compiler | |
141 | //! \>=1.24.0-nightly but we are working to stabilize all of the APIs involved. | |
142 | //! | |
143 | //! [`heapsize2`]: https://github.com/dtolnay/syn/tree/master/examples/heapsize2 | |
144 | //! | |
145 | //! The token-based procedural macro API provides great control over where the | |
146 | //! compiler's error messages are displayed in user code. Consider the error the | |
147 | //! user sees if one of their field types does not implement `HeapSize`. | |
148 | //! | |
149 | //! ```rust | |
150 | //! # const IGNORE_TOKENS: &str = stringify! { | |
151 | //! #[derive(HeapSize)] | |
152 | //! # }; | |
153 | //! struct Broken { | |
154 | //! ok: String, | |
155 | //! bad: std::thread::Thread, | |
156 | //! } | |
157 | //! ``` | |
158 | //! | |
159 | //! In the Macros 1.1 string-based procedural macro world, the resulting error | |
160 | //! would point unhelpfully to the invocation of the derive macro and not to the | |
161 | //! actual problematic field. | |
162 | //! | |
163 | //! ```text | |
164 | //! error[E0599]: no method named `heap_size_of_children` found for type `std::thread::Thread` in the current scope | |
165 | //! --> src/main.rs:4:10 | |
166 | //! | | |
167 | //! 4 | #[derive(HeapSize)] | |
168 | //! | ^^^^^^^^ | |
169 | //! ``` | |
170 | //! | |
171 | //! By tracking span information all the way through the expansion of a | |
172 | //! procedural macro as shown in the `heapsize2` example, token-based macros in | |
173 | //! Syn are able to trigger errors that directly pinpoint the source of the | |
174 | //! problem. | |
175 | //! | |
176 | //! ```text | |
177 | //! error[E0277]: the trait bound `std::thread::Thread: HeapSize` is not satisfied | |
178 | //! --> src/main.rs:7:5 | |
179 | //! | | |
180 | //! 7 | bad: std::thread::Thread, | |
181 | //! | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HeapSize` is not implemented for `Thread` | |
182 | //! ``` | |
183 | //! | |
184 | //! ## Parsing a custom syntax using combinators | |
185 | //! | |
186 | //! The [`lazy-static`] example directory shows the implementation of a | |
187 | //! `functionlike!(...)` procedural macro in which the input tokens are parsed | |
188 | //! using [`nom`]-style parser combinators. | |
189 | //! | |
190 | //! [`lazy-static`]: https://github.com/dtolnay/syn/tree/master/examples/lazy-static | |
191 | //! [`nom`]: https://github.com/Geal/nom | |
192 | //! | |
193 | //! The example reimplements the popular `lazy_static` crate from crates.io as a | |
194 | //! procedural macro. | |
195 | //! | |
196 | //! ``` | |
197 | //! # macro_rules! lazy_static { | |
198 | //! # ($($tt:tt)*) => {} | |
199 | //! # } | |
200 | //! # | |
201 | //! lazy_static! { | |
202 | //! static ref USERNAME: Regex = Regex::new("^[a-z0-9_-]{3,16}$").unwrap(); | |
203 | //! } | |
204 | //! ``` | |
205 | //! | |
206 | //! The implementation shows how to trigger custom warnings and error messages | |
207 | //! on the macro input. | |
208 | //! | |
209 | //! ```text | |
210 | //! warning: come on, pick a more creative name | |
211 | //! --> src/main.rs:10:16 | |
212 | //! | | |
213 | //! 10 | static ref FOO: String = "lazy_static".to_owned(); | |
214 | //! | ^^^ | |
215 | //! ``` | |
216 | //! | |
217 | //! ## Debugging | |
218 | //! | |
219 | //! When developing a procedural macro it can be helpful to look at what the | |
220 | //! generated code looks like. Use `cargo rustc -- -Zunstable-options | |
221 | //! --pretty=expanded` or the [`cargo expand`] subcommand. | |
222 | //! | |
223 | //! [`cargo expand`]: https://github.com/dtolnay/cargo-expand | |
224 | //! | |
225 | //! To show the expanded code for some crate that uses your procedural macro, | |
226 | //! run `cargo expand` from that crate. To show the expanded code for one of | |
227 | //! your own test cases, run `cargo expand --test the_test_case` where the last | |
228 | //! argument is the name of the test file without the `.rs` extension. | |
229 | //! | |
230 | //! This write-up by Brandon W Maister discusses debugging in more detail: | |
231 | //! [Debugging Rust's new Custom Derive system][debugging]. | |
232 | //! | |
233 | //! [debugging]: https://quodlibetor.github.io/posts/debugging-rusts-new-custom-derive-system/ | |
234 | //! | |
235 | //! ## Optional features | |
236 | //! | |
237 | //! Syn puts a lot of functionality behind optional features in order to | |
238 | //! optimize compile time for the most common use cases. The following features | |
239 | //! are available. | |
240 | //! | |
241 | //! - **`derive`** *(enabled by default)* — Data structures for representing the | |
242 | //! possible input to a custom derive, including structs and enums and types. | |
243 | //! - **`full`** — Data structures for representing the syntax tree of all valid | |
244 | //! Rust source code, including items and expressions. | |
245 | //! - **`parsing`** *(enabled by default)* — Ability to parse input tokens into | |
246 | //! a syntax tree node of a chosen type. | |
247 | //! - **`printing`** *(enabled by default)* — Ability to print a syntax tree | |
248 | //! node as tokens of Rust source code. | |
249 | //! - **`visit`** — Trait for traversing a syntax tree. | |
250 | //! - **`visit-mut`** — Trait for traversing and mutating in place a syntax | |
251 | //! tree. | |
252 | //! - **`fold`** — Trait for transforming an owned syntax tree. | |
253 | //! - **`clone-impls`** *(enabled by default)* — Clone impls for all syntax tree | |
254 | //! types. | |
255 | //! - **`extra-traits`** — Debug, Eq, PartialEq, Hash impls for all syntax tree | |
256 | //! types. | |
257 | ||
258 | // Syn types in rustdoc of other crates get linked to here. | |
259 | #![doc(html_root_url = "https://docs.rs/syn/0.12.15")] | |
260 | #![cfg_attr(feature = "cargo-clippy", | |
261 | allow(const_static_lifetime, doc_markdown, large_enum_variant, match_bool, | |
262 | redundant_closure, needless_pass_by_value, redundant_field_names))] | |
263 | ||
264 | extern crate proc_macro2; | |
265 | extern crate proc_macro; | |
266 | extern crate unicode_xid; | |
267 | ||
268 | #[cfg(feature = "printing")] | |
269 | extern crate quote; | |
270 | ||
271 | #[cfg(feature = "parsing")] | |
272 | #[macro_use] | |
273 | #[doc(hidden)] | |
274 | pub mod parsers; | |
275 | ||
276 | #[macro_use] | |
277 | mod macros; | |
278 | ||
279 | #[macro_use] | |
280 | pub mod token; | |
281 | ||
282 | #[cfg(any(feature = "full", feature = "derive"))] | |
283 | mod attr; | |
284 | #[cfg(any(feature = "full", feature = "derive"))] | |
285 | pub use attr::{AttrStyle, Attribute, Meta, MetaList, MetaNameValue, NestedMeta}; | |
286 | ||
287 | #[cfg(any(feature = "full", feature = "derive"))] | |
288 | mod data; | |
289 | #[cfg(any(feature = "full", feature = "derive"))] | |
290 | pub use data::{Field, Fields, FieldsNamed, FieldsUnnamed, Variant, VisCrate, VisPublic, | |
291 | VisRestricted, Visibility}; | |
292 | ||
293 | #[cfg(any(feature = "full", feature = "derive"))] | |
294 | mod expr; | |
295 | #[cfg(any(feature = "full", feature = "derive"))] | |
296 | pub use expr::{Expr, ExprAddrOf, ExprArray, ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, | |
297 | ExprBox, ExprBreak, ExprCall, ExprCast, ExprCatch, ExprClosure, ExprContinue, | |
298 | ExprField, ExprForLoop, ExprGroup, ExprIf, ExprIfLet, ExprInPlace, ExprIndex, | |
299 | ExprLit, ExprLoop, ExprMacro, ExprMatch, ExprMethodCall, ExprParen, ExprPath, | |
300 | ExprRange, ExprRepeat, ExprReturn, ExprStruct, ExprTry, ExprTuple, ExprType, | |
301 | ExprUnary, ExprUnsafe, ExprVerbatim, ExprWhile, ExprWhileLet, ExprYield, Index, | |
302 | Member}; | |
303 | ||
304 | #[cfg(feature = "full")] | |
305 | pub use expr::{Arm, Block, FieldPat, FieldValue, GenericMethodArgument, Label, Local, | |
306 | MethodTurbofish, Pat, PatBox, PatIdent, PatLit, PatMacro, PatPath, PatRange, | |
307 | PatRef, PatSlice, PatStruct, PatTuple, PatTupleStruct, PatVerbatim, PatWild, | |
308 | RangeLimits, Stmt}; | |
309 | ||
310 | #[cfg(any(feature = "full", feature = "derive"))] | |
311 | mod generics; | |
312 | #[cfg(any(feature = "full", feature = "derive"))] | |
313 | pub use generics::{BoundLifetimes, ConstParam, GenericParam, Generics, LifetimeDef, PredicateEq, | |
314 | PredicateLifetime, PredicateType, TraitBound, TraitBoundModifier, TypeParam, | |
315 | TypeParamBound, WhereClause, WherePredicate}; | |
316 | #[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))] | |
317 | pub use generics::{ImplGenerics, Turbofish, TypeGenerics}; | |
318 | ||
319 | mod ident; | |
320 | pub use ident::Ident; | |
321 | ||
322 | #[cfg(feature = "full")] | |
323 | mod item; | |
324 | #[cfg(feature = "full")] | |
325 | pub use item::{ArgCaptured, ArgSelf, ArgSelfRef, FnArg, FnDecl, ForeignItem, ForeignItemFn, | |
326 | ForeignItemStatic, ForeignItemType, ForeignItemVerbatim, ImplItem, ImplItemConst, | |
327 | ImplItemMacro, ImplItemMethod, ImplItemType, ImplItemVerbatim, Item, ItemConst, | |
328 | ItemEnum, ItemExternCrate, ItemFn, ItemForeignMod, ItemImpl, ItemMacro, ItemMacro2, | |
329 | ItemMod, ItemStatic, ItemStruct, ItemTrait, ItemType, ItemUnion, ItemUse, | |
330 | ItemVerbatim, MethodSig, TraitItem, TraitItemConst, TraitItemMacro, | |
331 | TraitItemMethod, TraitItemType, TraitItemVerbatim, UseGlob, UseList, UsePath, | |
332 | UseTree}; | |
333 | ||
334 | #[cfg(feature = "full")] | |
335 | mod file; | |
336 | #[cfg(feature = "full")] | |
337 | pub use file::File; | |
338 | ||
339 | #[cfg(any(feature = "full", feature = "derive"))] | |
340 | mod lifetime; | |
341 | #[cfg(any(feature = "full", feature = "derive"))] | |
342 | pub use lifetime::Lifetime; | |
343 | ||
344 | #[cfg(any(feature = "full", feature = "derive"))] | |
345 | mod lit; | |
346 | #[cfg(any(feature = "full", feature = "derive"))] | |
347 | pub use lit::{FloatSuffix, IntSuffix, Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, | |
348 | LitInt, LitStr, LitVerbatim, StrStyle}; | |
349 | ||
350 | #[cfg(any(feature = "full", feature = "derive"))] | |
351 | mod mac; | |
352 | #[cfg(any(feature = "full", feature = "derive"))] | |
353 | pub use mac::{Macro, MacroDelimiter}; | |
354 | ||
355 | #[cfg(any(feature = "full", feature = "derive"))] | |
356 | mod derive; | |
357 | #[cfg(feature = "derive")] | |
358 | pub use derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput}; | |
359 | ||
360 | #[cfg(any(feature = "full", feature = "derive"))] | |
361 | mod op; | |
362 | #[cfg(any(feature = "full", feature = "derive"))] | |
363 | pub use op::{BinOp, UnOp}; | |
364 | ||
365 | #[cfg(any(feature = "full", feature = "derive"))] | |
366 | mod ty; | |
367 | #[cfg(any(feature = "full", feature = "derive"))] | |
368 | pub use ty::{Abi, BareFnArg, BareFnArgName, ReturnType, Type, TypeArray, TypeBareFn, TypeGroup, | |
369 | TypeImplTrait, TypeInfer, TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, | |
370 | TypeReference, TypeSlice, TypeTraitObject, TypeTuple, TypeVerbatim}; | |
371 | ||
372 | #[cfg(any(feature = "full", feature = "derive"))] | |
373 | mod path; | |
374 | #[cfg(any(feature = "full", feature = "derive"))] | |
375 | pub use path::{AngleBracketedGenericArguments, Binding, GenericArgument, | |
376 | ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf}; | |
377 | #[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))] | |
378 | pub use path::PathTokens; | |
379 | ||
380 | #[cfg(feature = "parsing")] | |
381 | pub mod buffer; | |
382 | #[cfg(feature = "parsing")] | |
383 | pub mod synom; | |
384 | pub mod punctuated; | |
385 | #[cfg(any(feature = "full", feature = "derive"))] | |
386 | mod tt; | |
387 | ||
388 | // Not public API except the `parse_quote!` macro. | |
389 | #[cfg(feature = "parsing")] | |
390 | #[doc(hidden)] | |
391 | pub mod parse_quote; | |
392 | ||
393 | #[cfg(all(feature = "parsing", feature = "printing"))] | |
394 | pub mod spanned; | |
395 | ||
396 | mod gen { | |
397 | /// Syntax tree traversal to walk a shared borrow of a syntax tree. | |
398 | /// | |
399 | /// Each method of the [`Visit`] trait is a hook that can be overridden to | |
400 | /// customize the behavior when visiting the corresponding type of node. By | |
401 | /// default, every method recursively visits the substructure of the input | |
402 | /// by invoking the right visitor method of each of its fields. | |
403 | /// | |
404 | /// [`Visit`]: trait.Visit.html | |
405 | /// | |
406 | /// ```rust | |
407 | /// # use syn::{Attribute, BinOp, Expr, ExprBinary}; | |
408 | /// # | |
409 | /// pub trait Visit<'ast> { | |
410 | /// /* ... */ | |
411 | /// | |
412 | /// fn visit_expr_binary(&mut self, node: &'ast ExprBinary) { | |
413 | /// for attr in &node.attrs { | |
414 | /// self.visit_attribute(attr); | |
415 | /// } | |
416 | /// self.visit_expr(&*node.left); | |
417 | /// self.visit_bin_op(&node.op); | |
418 | /// self.visit_expr(&*node.right); | |
419 | /// } | |
420 | /// | |
421 | /// /* ... */ | |
422 | /// # fn visit_attribute(&mut self, node: &'ast Attribute); | |
423 | /// # fn visit_expr(&mut self, node: &'ast Expr); | |
424 | /// # fn visit_bin_op(&mut self, node: &'ast BinOp); | |
425 | /// } | |
426 | /// ``` | |
427 | /// | |
428 | /// *This module is available if Syn is built with the `"visit"` feature.* | |
429 | #[cfg(feature = "visit")] | |
430 | pub mod visit; | |
431 | ||
432 | ||
433 | /// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in | |
434 | /// place. | |
435 | /// | |
436 | /// Each method of the [`VisitMut`] trait is a hook that can be overridden | |
437 | /// to customize the behavior when mutating the corresponding type of node. | |
438 | /// By default, every method recursively visits the substructure of the | |
439 | /// input by invoking the right visitor method of each of its fields. | |
440 | /// | |
441 | /// [`VisitMut`]: trait.VisitMut.html | |
442 | /// | |
443 | /// ```rust | |
444 | /// # use syn::{Attribute, BinOp, Expr, ExprBinary}; | |
445 | /// # | |
446 | /// pub trait VisitMut { | |
447 | /// /* ... */ | |
448 | /// | |
449 | /// fn visit_expr_binary_mut(&mut self, node: &mut ExprBinary) { | |
450 | /// for attr in &mut node.attrs { | |
451 | /// self.visit_attribute_mut(attr); | |
452 | /// } | |
453 | /// self.visit_expr_mut(&mut *node.left); | |
454 | /// self.visit_bin_op_mut(&mut node.op); | |
455 | /// self.visit_expr_mut(&mut *node.right); | |
456 | /// } | |
457 | /// | |
458 | /// /* ... */ | |
459 | /// # fn visit_attribute_mut(&mut self, node: &mut Attribute); | |
460 | /// # fn visit_expr_mut(&mut self, node: &mut Expr); | |
461 | /// # fn visit_bin_op_mut(&mut self, node: &mut BinOp); | |
462 | /// } | |
463 | /// ``` | |
464 | /// | |
465 | /// *This module is available if Syn is built with the `"visit-mut"` | |
466 | /// feature.* | |
467 | #[cfg(feature = "visit-mut")] | |
468 | pub mod visit_mut; | |
469 | ||
470 | /// Syntax tree traversal to transform the nodes of an owned syntax tree. | |
471 | /// | |
472 | /// Each method of the [`Fold`] trait is a hook that can be overridden to | |
473 | /// customize the behavior when transforming the corresponding type of node. | |
474 | /// By default, every method recursively visits the substructure of the | |
475 | /// input by invoking the right visitor method of each of its fields. | |
476 | /// | |
477 | /// [`Fold`]: trait.Fold.html | |
478 | /// | |
479 | /// ```rust | |
480 | /// # use syn::{Attribute, BinOp, Expr, ExprBinary}; | |
481 | /// # | |
482 | /// pub trait Fold { | |
483 | /// /* ... */ | |
484 | /// | |
485 | /// fn fold_expr_binary(&mut self, node: ExprBinary) -> ExprBinary { | |
486 | /// ExprBinary { | |
487 | /// attrs: node.attrs | |
488 | /// .into_iter() | |
489 | /// .map(|attr| self.fold_attribute(attr)) | |
490 | /// .collect(), | |
491 | /// left: Box::new(self.fold_expr(*node.left)), | |
492 | /// op: self.fold_bin_op(node.op), | |
493 | /// right: Box::new(self.fold_expr(*node.right)), | |
494 | /// } | |
495 | /// } | |
496 | /// | |
497 | /// /* ... */ | |
498 | /// # fn fold_attribute(&mut self, node: Attribute) -> Attribute; | |
499 | /// # fn fold_expr(&mut self, node: Expr) -> Expr; | |
500 | /// # fn fold_bin_op(&mut self, node: BinOp) -> BinOp; | |
501 | /// } | |
502 | /// ``` | |
503 | /// | |
504 | /// *This module is available if Syn is built with the `"fold"` feature.* | |
505 | #[cfg(feature = "fold")] | |
506 | pub mod fold; | |
507 | ||
508 | #[cfg(any(feature = "full", feature = "derive"))] | |
509 | #[path = "../gen_helper.rs"] | |
510 | mod helper; | |
511 | } | |
512 | pub use gen::*; | |
513 | ||
514 | //////////////////////////////////////////////////////////////////////////////// | |
515 | ||
516 | #[cfg(feature = "parsing")] | |
517 | use synom::{Synom, Parser}; | |
518 | ||
519 | #[cfg(feature = "parsing")] | |
520 | mod error; | |
521 | #[cfg(feature = "parsing")] | |
522 | use error::ParseError; | |
523 | ||
524 | // Not public API. | |
525 | #[cfg(feature = "parsing")] | |
526 | #[doc(hidden)] | |
527 | pub use error::parse_error; | |
528 | ||
529 | /// Parse tokens of source code into the chosen syntax tree node. | |
530 | /// | |
531 | /// This is preferred over parsing a string because tokens are able to preserve | |
532 | /// information about where in the user's code they were originally written (the | |
533 | /// "span" of the token), possibly allowing the compiler to produce better error | |
534 | /// messages. | |
535 | /// | |
536 | /// This function parses a `proc_macro::TokenStream` which is the type used for | |
537 | /// interop with the compiler in a procedural macro. To parse a | |
538 | /// `proc_macro2::TokenStream`, use [`syn::parse2`] instead. | |
539 | /// | |
540 | /// [`syn::parse2`]: fn.parse2.html | |
541 | /// | |
542 | /// *This function is available if Syn is built with the `"parsing"` feature.* | |
543 | /// | |
544 | /// # Examples | |
545 | /// | |
546 | /// ```rust | |
547 | /// extern crate proc_macro; | |
548 | /// use proc_macro::TokenStream; | |
549 | /// | |
550 | /// extern crate syn; | |
551 | /// | |
552 | /// #[macro_use] | |
553 | /// extern crate quote; | |
554 | /// | |
555 | /// use syn::DeriveInput; | |
556 | /// | |
557 | /// # const IGNORE_TOKENS: &str = stringify! { | |
558 | /// #[proc_macro_derive(MyMacro)] | |
559 | /// # }; | |
560 | /// pub fn my_macro(input: TokenStream) -> TokenStream { | |
561 | /// // Parse the tokens into a syntax tree | |
562 | /// let ast: DeriveInput = syn::parse(input).unwrap(); | |
563 | /// | |
564 | /// // Build the output, possibly using quasi-quotation | |
565 | /// let expanded = quote! { | |
566 | /// /* ... */ | |
567 | /// }; | |
568 | /// | |
569 | /// // Convert into a token stream and return it | |
570 | /// expanded.into() | |
571 | /// } | |
572 | /// # | |
573 | /// # fn main() {} | |
574 | /// ``` | |
575 | #[cfg(feature = "parsing")] | |
576 | pub fn parse<T>(tokens: proc_macro::TokenStream) -> Result<T, ParseError> | |
577 | where | |
578 | T: Synom, | |
579 | { | |
580 | parse2(tokens.into()) | |
581 | } | |
582 | ||
583 | /// Parse a proc-macro2 token stream into the chosen syntax tree node. | |
584 | /// | |
585 | /// This function parses a `proc_macro2::TokenStream` which is commonly useful | |
586 | /// when the input comes from a node of the Syn syntax tree, for example the tts | |
587 | /// of a [`Macro`] node. When in a procedural macro parsing the | |
588 | /// `proc_macro::TokenStream` provided by the compiler, use [`syn::parse`] | |
589 | /// instead. | |
590 | /// | |
591 | /// [`Macro`]: struct.Macro.html | |
592 | /// [`syn::parse`]: fn.parse.html | |
593 | /// | |
594 | /// *This function is available if Syn is built with the `"parsing"` feature.* | |
595 | #[cfg(feature = "parsing")] | |
596 | pub fn parse2<T>(tokens: proc_macro2::TokenStream) -> Result<T, ParseError> | |
597 | where | |
598 | T: Synom, | |
599 | { | |
600 | let parser = T::parse; | |
601 | parser.parse2(tokens).map_err(|err| { | |
602 | match T::description() { | |
603 | Some(s) => ParseError::new(format!("failed to parse {}: {}", s, err)), | |
604 | None => err, | |
605 | } | |
606 | }) | |
607 | } | |
608 | ||
609 | /// Parse a string of Rust code into the chosen syntax tree node. | |
610 | /// | |
611 | /// *This function is available if Syn is built with the `"parsing"` feature.* | |
612 | /// | |
613 | /// # Hygiene | |
614 | /// | |
615 | /// Every span in the resulting syntax tree will be set to resolve at the macro | |
616 | /// call site. | |
617 | /// | |
618 | /// # Examples | |
619 | /// | |
620 | /// ```rust | |
621 | /// extern crate syn; | |
622 | /// # | |
623 | /// # | |
624 | /// # type Result<T> = std::result::Result<T, Box<std::error::Error>>; | |
625 | /// | |
626 | /// use syn::Expr; | |
627 | /// | |
628 | /// fn run() -> Result<()> { | |
629 | /// let code = "assert_eq!(u8::max_value(), 255)"; | |
630 | /// let expr = syn::parse_str::<Expr>(code)?; | |
631 | /// println!("{:#?}", expr); | |
632 | /// Ok(()) | |
633 | /// } | |
634 | /// # | |
635 | /// # fn main() { run().unwrap() } | |
636 | /// ``` | |
637 | #[cfg(feature = "parsing")] | |
638 | pub fn parse_str<T: Synom>(s: &str) -> Result<T, ParseError> { | |
639 | match s.parse() { | |
640 | Ok(tts) => parse2(tts), | |
641 | Err(_) => Err(ParseError::new("error while lexing input string")), | |
642 | } | |
643 | } | |
644 | ||
645 | // FIXME the name parse_file makes it sound like you might pass in a path to a | |
646 | // file, rather than the content. | |
647 | /// Parse the content of a file of Rust code. | |
648 | /// | |
649 | /// This is different from `syn::parse_str::<File>(content)` in two ways: | |
650 | /// | |
651 | /// - It discards a leading byte order mark `\u{FEFF}` if the file has one. | |
652 | /// - It preserves the shebang line of the file, such as `#!/usr/bin/env rustx`. | |
653 | /// | |
654 | /// If present, either of these would be an error using `from_str`. | |
655 | /// | |
656 | /// *This function is available if Syn is built with the `"parsing"` and `"full"` features.* | |
657 | /// | |
658 | /// # Examples | |
659 | /// | |
660 | /// ```rust,no_run | |
661 | /// extern crate syn; | |
662 | /// # | |
663 | /// # | |
664 | /// # type Result<T> = std::result::Result<T, Box<std::error::Error>>; | |
665 | /// | |
666 | /// use std::fs::File; | |
667 | /// use std::io::Read; | |
668 | /// | |
669 | /// fn run() -> Result<()> { | |
670 | /// let mut file = File::open("path/to/code.rs")?; | |
671 | /// let mut content = String::new(); | |
672 | /// file.read_to_string(&mut content)?; | |
673 | /// | |
674 | /// let ast = syn::parse_file(&content)?; | |
675 | /// if let Some(shebang) = ast.shebang { | |
676 | /// println!("{}", shebang); | |
677 | /// } | |
678 | /// println!("{} items", ast.items.len()); | |
679 | /// | |
680 | /// Ok(()) | |
681 | /// } | |
682 | /// # | |
683 | /// # fn main() { run().unwrap() } | |
684 | /// ``` | |
685 | #[cfg(all(feature = "parsing", feature = "full"))] | |
686 | pub fn parse_file(mut content: &str) -> Result<File, ParseError> { | |
687 | // Strip the BOM if it is present | |
688 | const BOM: &'static str = "\u{feff}"; | |
689 | if content.starts_with(BOM) { | |
690 | content = &content[BOM.len()..]; | |
691 | } | |
692 | ||
693 | let mut shebang = None; | |
694 | if content.starts_with("#!") && !content.starts_with("#![") { | |
695 | if let Some(idx) = content.find('\n') { | |
696 | shebang = Some(content[..idx].to_string()); | |
697 | content = &content[idx..]; | |
698 | } else { | |
699 | shebang = Some(content.to_string()); | |
700 | content = ""; | |
701 | } | |
702 | } | |
703 | ||
704 | let mut file: File = parse_str(content)?; | |
705 | file.shebang = shebang; | |
706 | Ok(file) | |
707 | } | |
708 | ||
709 | #[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))] | |
710 | struct TokensOrDefault<'a, T: 'a>(&'a Option<T>); | |
711 | ||
712 | #[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))] | |
713 | impl<'a, T> quote::ToTokens for TokensOrDefault<'a, T> | |
714 | where | |
715 | T: quote::ToTokens + Default, | |
716 | { | |
717 | fn to_tokens(&self, tokens: &mut quote::Tokens) { | |
718 | match *self.0 { | |
719 | Some(ref t) => t.to_tokens(tokens), | |
720 | None => T::default().to_tokens(tokens), | |
721 | } | |
722 | } | |
723 | } |