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