Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/rust/syn/lib.rs
38271 views
1
// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3
//! [![github]](https://github.com/dtolnay/syn) [![crates-io]](https://crates.io/crates/syn) [![docs-rs]](crate)
4
//!
5
//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
6
//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
7
//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
8
//!
9
//! <br>
10
//!
11
//! Syn is a parsing library for parsing a stream of Rust tokens into a syntax
12
//! tree of Rust source code.
13
//!
14
//! Currently this library is geared toward use in Rust procedural macros, but
15
//! contains some APIs that may be useful more generally.
16
//!
17
//! - **Data structures** — Syn provides a complete syntax tree that can
18
//! represent any valid Rust source code. The syntax tree is rooted at
19
//! [`syn::File`] which represents a full source file, but there are other
20
//! entry points that may be useful to procedural macros including
21
//! [`syn::Item`], [`syn::Expr`] and [`syn::Type`].
22
//!
23
//! - **Derives** — Of particular interest to derive macros is
24
//! [`syn::DeriveInput`] which is any of the three legal input items to a
25
//! derive macro. An example below shows using this type in a library that can
26
//! derive implementations of a user-defined trait.
27
//!
28
//! - **Parsing** — Parsing in Syn is built around [parser functions] with the
29
//! signature `fn(ParseStream) -> Result<T>`. Every syntax tree node defined
30
//! by Syn is individually parsable and may be used as a building block for
31
//! custom syntaxes, or you may dream up your own brand new syntax without
32
//! involving any of our syntax tree types.
33
//!
34
//! - **Location information** — Every token parsed by Syn is associated with a
35
//! `Span` that tracks line and column information back to the source of that
36
//! token. These spans allow a procedural macro to display detailed error
37
//! messages pointing to all the right places in the user's code. There is an
38
//! example of this below.
39
//!
40
//! - **Feature flags** — Functionality is aggressively feature gated so your
41
//! procedural macros enable only what they need, and do not pay in compile
42
//! time for all the rest.
43
//!
44
//! [`syn::File`]: File
45
//! [`syn::Item`]: Item
46
//! [`syn::Expr`]: Expr
47
//! [`syn::Type`]: Type
48
//! [`syn::DeriveInput`]: DeriveInput
49
//! [parser functions]: mod@parse
50
//!
51
//! <br>
52
//!
53
//! # Example of a derive macro
54
//!
55
//! The canonical derive macro using Syn looks like this. We write an ordinary
56
//! Rust function tagged with a `proc_macro_derive` attribute and the name of
57
//! the trait we are deriving. Any time that derive appears in the user's code,
58
//! the Rust compiler passes their data structure as tokens into our macro. We
59
//! get to execute arbitrary Rust code to figure out what to do with those
60
//! tokens, then hand some tokens back to the compiler to compile into the
61
//! user's crate.
62
//!
63
//! [`TokenStream`]: proc_macro::TokenStream
64
//!
65
//! ```toml
66
//! [dependencies]
67
//! syn = "2.0"
68
//! quote = "1.0"
69
//!
70
//! [lib]
71
//! proc-macro = true
72
//! ```
73
//!
74
//! ```
75
//! # extern crate proc_macro;
76
//! #
77
//! use proc_macro::TokenStream;
78
//! use quote::quote;
79
//! use syn::{parse_macro_input, DeriveInput};
80
//!
81
//! # const IGNORE_TOKENS: &str = stringify! {
82
//! #[proc_macro_derive(MyMacro)]
83
//! # };
84
//! pub fn my_macro(input: TokenStream) -> TokenStream {
85
//! // Parse the input tokens into a syntax tree
86
//! let input = parse_macro_input!(input as DeriveInput);
87
//!
88
//! // Build the output, possibly using quasi-quotation
89
//! let expanded = quote! {
90
//! // ...
91
//! };
92
//!
93
//! // Hand the output tokens back to the compiler
94
//! TokenStream::from(expanded)
95
//! }
96
//! ```
97
//!
98
//! The [`heapsize`] example directory shows a complete working implementation
99
//! of a derive macro. The example derives a `HeapSize` trait which computes an
100
//! estimate of the amount of heap memory owned by a value.
101
//!
102
//! [`heapsize`]: https://github.com/dtolnay/syn/tree/master/examples/heapsize
103
//!
104
//! ```
105
//! pub trait HeapSize {
106
//! /// Total number of bytes of heap memory owned by `self`.
107
//! fn heap_size_of_children(&self) -> usize;
108
//! }
109
//! ```
110
//!
111
//! The derive macro allows users to write `#[derive(HeapSize)]` on data
112
//! structures in their program.
113
//!
114
//! ```
115
//! # const IGNORE_TOKENS: &str = stringify! {
116
//! #[derive(HeapSize)]
117
//! # };
118
//! struct Demo<'a, T: ?Sized> {
119
//! a: Box<T>,
120
//! b: u8,
121
//! c: &'a str,
122
//! d: String,
123
//! }
124
//! ```
125
//!
126
//! <p><br></p>
127
//!
128
//! # Spans and error reporting
129
//!
130
//! The token-based procedural macro API provides great control over where the
131
//! compiler's error messages are displayed in user code. Consider the error the
132
//! user sees if one of their field types does not implement `HeapSize`.
133
//!
134
//! ```
135
//! # const IGNORE_TOKENS: &str = stringify! {
136
//! #[derive(HeapSize)]
137
//! # };
138
//! struct Broken {
139
//! ok: String,
140
//! bad: std::thread::Thread,
141
//! }
142
//! ```
143
//!
144
//! By tracking span information all the way through the expansion of a
145
//! procedural macro as shown in the `heapsize` example, token-based macros in
146
//! Syn are able to trigger errors that directly pinpoint the source of the
147
//! problem.
148
//!
149
//! ```text
150
//! error[E0277]: the trait bound `std::thread::Thread: HeapSize` is not satisfied
151
//! --> src/main.rs:7:5
152
//! |
153
//! 7 | bad: std::thread::Thread,
154
//! | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HeapSize` is not implemented for `Thread`
155
//! ```
156
//!
157
//! <br>
158
//!
159
//! # Parsing a custom syntax
160
//!
161
//! The [`lazy-static`] example directory shows the implementation of a
162
//! `functionlike!(...)` procedural macro in which the input tokens are parsed
163
//! using Syn's parsing API.
164
//!
165
//! [`lazy-static`]: https://github.com/dtolnay/syn/tree/master/examples/lazy-static
166
//!
167
//! The example reimplements the popular `lazy_static` crate from crates.io as a
168
//! procedural macro.
169
//!
170
//! ```
171
//! # macro_rules! lazy_static {
172
//! # ($($tt:tt)*) => {}
173
//! # }
174
//! #
175
//! lazy_static! {
176
//! static ref USERNAME: Regex = Regex::new("^[a-z0-9_-]{3,16}$").unwrap();
177
//! }
178
//! ```
179
//!
180
//! The implementation shows how to trigger custom warnings and error messages
181
//! on the macro input.
182
//!
183
//! ```text
184
//! warning: come on, pick a more creative name
185
//! --> src/main.rs:10:16
186
//! |
187
//! 10 | static ref FOO: String = "lazy_static".to_owned();
188
//! | ^^^
189
//! ```
190
//!
191
//! <br>
192
//!
193
//! # Testing
194
//!
195
//! When testing macros, we often care not just that the macro can be used
196
//! successfully but also that when the macro is provided with invalid input it
197
//! produces maximally helpful error messages. Consider using the [`trybuild`]
198
//! crate to write tests for errors that are emitted by your macro or errors
199
//! detected by the Rust compiler in the expanded code following misuse of the
200
//! macro. Such tests help avoid regressions from later refactors that
201
//! mistakenly make an error no longer trigger or be less helpful than it used
202
//! to be.
203
//!
204
//! [`trybuild`]: https://github.com/dtolnay/trybuild
205
//!
206
//! <br>
207
//!
208
//! # Debugging
209
//!
210
//! When developing a procedural macro it can be helpful to look at what the
211
//! generated code looks like. Use `cargo rustc -- -Zunstable-options
212
//! --pretty=expanded` or the [`cargo expand`] subcommand.
213
//!
214
//! [`cargo expand`]: https://github.com/dtolnay/cargo-expand
215
//!
216
//! To show the expanded code for some crate that uses your procedural macro,
217
//! run `cargo expand` from that crate. To show the expanded code for one of
218
//! your own test cases, run `cargo expand --test the_test_case` where the last
219
//! argument is the name of the test file without the `.rs` extension.
220
//!
221
//! This write-up by Brandon W Maister discusses debugging in more detail:
222
//! [Debugging Rust's new Custom Derive system][debugging].
223
//!
224
//! [debugging]: https://quodlibetor.github.io/posts/debugging-rusts-new-custom-derive-system/
225
//!
226
//! <br>
227
//!
228
//! # Optional features
229
//!
230
//! Syn puts a lot of functionality behind optional features in order to
231
//! optimize compile time for the most common use cases. The following features
232
//! are available.
233
//!
234
//! - **`derive`** *(enabled by default)* — Data structures for representing the
235
//! possible input to a derive macro, including structs and enums and types.
236
//! - **`full`** — Data structures for representing the syntax tree of all valid
237
//! Rust source code, including items and expressions.
238
//! - **`parsing`** *(enabled by default)* — Ability to parse input tokens into
239
//! a syntax tree node of a chosen type.
240
//! - **`printing`** *(enabled by default)* — Ability to print a syntax tree
241
//! node as tokens of Rust source code.
242
//! - **`visit`** — Trait for traversing a syntax tree.
243
//! - **`visit-mut`** — Trait for traversing and mutating in place a syntax
244
//! tree.
245
//! - **`fold`** — Trait for transforming an owned syntax tree.
246
//! - **`clone-impls`** *(enabled by default)* — Clone impls for all syntax tree
247
//! types.
248
//! - **`extra-traits`** — Debug, Eq, PartialEq, Hash impls for all syntax tree
249
//! types.
250
//! - **`proc-macro`** *(enabled by default)* — Runtime dependency on the
251
//! dynamic library libproc_macro from rustc toolchain.
252
253
// Syn types in rustdoc of other crates get linked to here.
254
#![doc(html_root_url = "https://docs.rs/syn/2.0.106")]
255
#![cfg_attr(docsrs, feature(doc_cfg))]
256
#![deny(unsafe_op_in_unsafe_fn)]
257
#![allow(non_camel_case_types)]
258
#![cfg_attr(not(check_cfg), allow(unexpected_cfgs))]
259
#![allow(
260
clippy::bool_to_int_with_if,
261
clippy::cast_lossless,
262
clippy::cast_possible_truncation,
263
clippy::cast_possible_wrap,
264
clippy::cast_ptr_alignment,
265
clippy::default_trait_access,
266
clippy::derivable_impls,
267
clippy::diverging_sub_expression,
268
clippy::doc_markdown,
269
clippy::elidable_lifetime_names,
270
clippy::enum_glob_use,
271
clippy::expl_impl_clone_on_copy,
272
clippy::explicit_auto_deref,
273
clippy::fn_params_excessive_bools,
274
clippy::if_not_else,
275
clippy::inherent_to_string,
276
clippy::into_iter_without_iter,
277
clippy::items_after_statements,
278
clippy::large_enum_variant,
279
clippy::let_underscore_untyped, // https://github.com/rust-lang/rust-clippy/issues/10410
280
clippy::manual_assert,
281
clippy::manual_let_else,
282
clippy::manual_map,
283
clippy::match_like_matches_macro,
284
clippy::match_same_arms,
285
clippy::match_wildcard_for_single_variants, // clippy bug: https://github.com/rust-lang/rust-clippy/issues/6984
286
clippy::missing_errors_doc,
287
clippy::missing_panics_doc,
288
clippy::module_name_repetitions,
289
clippy::must_use_candidate,
290
clippy::needless_doctest_main,
291
clippy::needless_lifetimes,
292
clippy::needless_pass_by_value,
293
clippy::needless_update,
294
clippy::never_loop,
295
clippy::range_plus_one,
296
clippy::redundant_else,
297
clippy::ref_option,
298
clippy::return_self_not_must_use,
299
clippy::similar_names,
300
clippy::single_match_else,
301
clippy::struct_excessive_bools,
302
clippy::too_many_arguments,
303
clippy::too_many_lines,
304
clippy::trivially_copy_pass_by_ref,
305
clippy::unconditional_recursion, // https://github.com/rust-lang/rust-clippy/issues/12133
306
clippy::uninhabited_references,
307
clippy::uninlined_format_args,
308
clippy::unnecessary_box_returns,
309
clippy::unnecessary_unwrap,
310
clippy::used_underscore_binding,
311
clippy::wildcard_imports,
312
)]
313
#![allow(unknown_lints, mismatched_lifetime_syntaxes)]
314
315
extern crate self as syn;
316
317
#[cfg(feature = "proc-macro")]
318
extern crate proc_macro;
319
320
#[macro_use]
321
mod macros;
322
323
#[cfg(feature = "parsing")]
324
#[macro_use]
325
mod group;
326
327
#[macro_use]
328
pub mod token;
329
330
#[cfg(any(feature = "full", feature = "derive"))]
331
mod attr;
332
#[cfg(any(feature = "full", feature = "derive"))]
333
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
334
pub use crate::attr::{AttrStyle, Attribute, Meta, MetaList, MetaNameValue};
335
336
mod bigint;
337
338
#[cfg(feature = "parsing")]
339
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
340
pub mod buffer;
341
342
#[cfg(any(
343
all(feature = "parsing", feature = "full"),
344
all(feature = "printing", any(feature = "full", feature = "derive")),
345
))]
346
mod classify;
347
348
mod custom_keyword;
349
350
mod custom_punctuation;
351
352
#[cfg(any(feature = "full", feature = "derive"))]
353
mod data;
354
#[cfg(any(feature = "full", feature = "derive"))]
355
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
356
pub use crate::data::{Field, Fields, FieldsNamed, FieldsUnnamed, Variant};
357
358
#[cfg(any(feature = "full", feature = "derive"))]
359
mod derive;
360
#[cfg(feature = "derive")]
361
#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
362
pub use crate::derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput};
363
364
mod drops;
365
366
mod error;
367
pub use crate::error::{Error, Result};
368
369
#[cfg(any(feature = "full", feature = "derive"))]
370
mod expr;
371
#[cfg(feature = "full")]
372
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
373
pub use crate::expr::{Arm, Label, PointerMutability, RangeLimits};
374
#[cfg(any(feature = "full", feature = "derive"))]
375
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
376
pub use crate::expr::{
377
Expr, ExprBinary, ExprCall, ExprCast, ExprField, ExprIndex, ExprLit, ExprMacro, ExprMethodCall,
378
ExprParen, ExprPath, ExprReference, ExprStruct, ExprUnary, FieldValue, Index, Member,
379
};
380
#[cfg(any(feature = "full", feature = "derive"))]
381
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
382
pub use crate::expr::{
383
ExprArray, ExprAssign, ExprAsync, ExprAwait, ExprBlock, ExprBreak, ExprClosure, ExprConst,
384
ExprContinue, ExprForLoop, ExprGroup, ExprIf, ExprInfer, ExprLet, ExprLoop, ExprMatch,
385
ExprRange, ExprRawAddr, ExprRepeat, ExprReturn, ExprTry, ExprTryBlock, ExprTuple, ExprUnsafe,
386
ExprWhile, ExprYield,
387
};
388
389
#[cfg(feature = "parsing")]
390
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
391
pub mod ext;
392
393
#[cfg(feature = "full")]
394
mod file;
395
#[cfg(feature = "full")]
396
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
397
pub use crate::file::File;
398
399
#[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))]
400
mod fixup;
401
402
#[cfg(any(feature = "full", feature = "derive"))]
403
mod generics;
404
#[cfg(any(feature = "full", feature = "derive"))]
405
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
406
pub use crate::generics::{
407
BoundLifetimes, ConstParam, GenericParam, Generics, LifetimeParam, PredicateLifetime,
408
PredicateType, TraitBound, TraitBoundModifier, TypeParam, TypeParamBound, WhereClause,
409
WherePredicate,
410
};
411
#[cfg(feature = "full")]
412
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
413
pub use crate::generics::{CapturedParam, PreciseCapture};
414
#[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))]
415
#[cfg_attr(
416
docsrs,
417
doc(cfg(all(any(feature = "full", feature = "derive"), feature = "printing")))
418
)]
419
pub use crate::generics::{ImplGenerics, Turbofish, TypeGenerics};
420
421
mod ident;
422
#[doc(inline)]
423
pub use crate::ident::Ident;
424
425
#[cfg(feature = "full")]
426
mod item;
427
#[cfg(feature = "full")]
428
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
429
pub use crate::item::{
430
FnArg, ForeignItem, ForeignItemFn, ForeignItemMacro, ForeignItemStatic, ForeignItemType,
431
ImplItem, ImplItemConst, ImplItemFn, ImplItemMacro, ImplItemType, ImplRestriction, Item,
432
ItemConst, ItemEnum, ItemExternCrate, ItemFn, ItemForeignMod, ItemImpl, ItemMacro, ItemMod,
433
ItemStatic, ItemStruct, ItemTrait, ItemTraitAlias, ItemType, ItemUnion, ItemUse, Receiver,
434
Signature, StaticMutability, TraitItem, TraitItemConst, TraitItemFn, TraitItemMacro,
435
TraitItemType, UseGlob, UseGroup, UseName, UsePath, UseRename, UseTree, Variadic,
436
};
437
438
mod lifetime;
439
#[doc(inline)]
440
pub use crate::lifetime::Lifetime;
441
442
mod lit;
443
#[doc(hidden)] // https://github.com/dtolnay/syn/issues/1566
444
pub use crate::lit::StrStyle;
445
#[doc(inline)]
446
pub use crate::lit::{
447
Lit, LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitInt, LitStr,
448
};
449
450
#[cfg(feature = "parsing")]
451
mod lookahead;
452
453
#[cfg(any(feature = "full", feature = "derive"))]
454
mod mac;
455
#[cfg(any(feature = "full", feature = "derive"))]
456
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
457
pub use crate::mac::{Macro, MacroDelimiter};
458
459
#[cfg(all(feature = "parsing", any(feature = "full", feature = "derive")))]
460
#[cfg_attr(
461
docsrs,
462
doc(cfg(all(feature = "parsing", any(feature = "full", feature = "derive"))))
463
)]
464
pub mod meta;
465
466
#[cfg(any(feature = "full", feature = "derive"))]
467
mod op;
468
#[cfg(any(feature = "full", feature = "derive"))]
469
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
470
pub use crate::op::{BinOp, UnOp};
471
472
#[cfg(feature = "parsing")]
473
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
474
pub mod parse;
475
476
#[cfg(all(feature = "parsing", feature = "proc-macro"))]
477
mod parse_macro_input;
478
479
#[cfg(all(feature = "parsing", feature = "printing"))]
480
mod parse_quote;
481
482
#[cfg(feature = "full")]
483
mod pat;
484
#[cfg(feature = "full")]
485
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
486
pub use crate::pat::{
487
FieldPat, Pat, PatConst, PatIdent, PatLit, PatMacro, PatOr, PatParen, PatPath, PatRange,
488
PatReference, PatRest, PatSlice, PatStruct, PatTuple, PatTupleStruct, PatType, PatWild,
489
};
490
491
#[cfg(any(feature = "full", feature = "derive"))]
492
mod path;
493
#[cfg(any(feature = "full", feature = "derive"))]
494
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
495
pub use crate::path::{
496
AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, GenericArgument,
497
ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf,
498
};
499
500
#[cfg(all(
501
any(feature = "full", feature = "derive"),
502
any(feature = "parsing", feature = "printing")
503
))]
504
mod precedence;
505
506
#[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))]
507
mod print;
508
509
pub mod punctuated;
510
511
#[cfg(any(feature = "full", feature = "derive"))]
512
mod restriction;
513
#[cfg(any(feature = "full", feature = "derive"))]
514
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
515
pub use crate::restriction::{FieldMutability, VisRestricted, Visibility};
516
517
mod sealed;
518
519
#[cfg(all(feature = "parsing", feature = "derive", not(feature = "full")))]
520
mod scan_expr;
521
522
mod span;
523
524
#[cfg(all(feature = "parsing", feature = "printing"))]
525
#[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))]
526
pub mod spanned;
527
528
#[cfg(feature = "full")]
529
mod stmt;
530
#[cfg(feature = "full")]
531
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
532
pub use crate::stmt::{Block, Local, LocalInit, Stmt, StmtMacro};
533
534
mod thread;
535
536
#[cfg(all(any(feature = "full", feature = "derive"), feature = "extra-traits"))]
537
mod tt;
538
539
#[cfg(any(feature = "full", feature = "derive"))]
540
mod ty;
541
#[cfg(any(feature = "full", feature = "derive"))]
542
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
543
pub use crate::ty::{
544
Abi, BareFnArg, BareVariadic, ReturnType, Type, TypeArray, TypeBareFn, TypeGroup,
545
TypeImplTrait, TypeInfer, TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, TypeReference,
546
TypeSlice, TypeTraitObject, TypeTuple,
547
};
548
549
#[cfg(all(any(feature = "full", feature = "derive"), feature = "parsing"))]
550
mod verbatim;
551
552
#[cfg(all(feature = "parsing", feature = "full"))]
553
mod whitespace;
554
555
#[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/6176
556
mod gen {
557
/// Syntax tree traversal to transform the nodes of an owned syntax tree.
558
///
559
/// Each method of the [`Fold`] trait is a hook that can be overridden to
560
/// customize the behavior when transforming the corresponding type of node.
561
/// By default, every method recursively visits the substructure of the
562
/// input by invoking the right visitor method of each of its fields.
563
///
564
/// [`Fold`]: fold::Fold
565
///
566
/// ```
567
/// # use syn::{Attribute, BinOp, Expr, ExprBinary};
568
/// #
569
/// pub trait Fold {
570
/// /* ... */
571
///
572
/// fn fold_expr_binary(&mut self, node: ExprBinary) -> ExprBinary {
573
/// fold_expr_binary(self, node)
574
/// }
575
///
576
/// /* ... */
577
/// # fn fold_attribute(&mut self, node: Attribute) -> Attribute;
578
/// # fn fold_expr(&mut self, node: Expr) -> Expr;
579
/// # fn fold_bin_op(&mut self, node: BinOp) -> BinOp;
580
/// }
581
///
582
/// pub fn fold_expr_binary<V>(v: &mut V, node: ExprBinary) -> ExprBinary
583
/// where
584
/// V: Fold + ?Sized,
585
/// {
586
/// ExprBinary {
587
/// attrs: node
588
/// .attrs
589
/// .into_iter()
590
/// .map(|attr| v.fold_attribute(attr))
591
/// .collect(),
592
/// left: Box::new(v.fold_expr(*node.left)),
593
/// op: v.fold_bin_op(node.op),
594
/// right: Box::new(v.fold_expr(*node.right)),
595
/// }
596
/// }
597
///
598
/// /* ... */
599
/// ```
600
///
601
/// <br>
602
///
603
/// # Example
604
///
605
/// This fold inserts parentheses to fully parenthesizes any expression.
606
///
607
/// ```
608
/// // [dependencies]
609
/// // quote = "1.0"
610
/// // syn = { version = "2.0", features = ["fold", "full"] }
611
///
612
/// use quote::quote;
613
/// use syn::fold::{fold_expr, Fold};
614
/// use syn::{token, Expr, ExprParen};
615
///
616
/// struct ParenthesizeEveryExpr;
617
///
618
/// impl Fold for ParenthesizeEveryExpr {
619
/// fn fold_expr(&mut self, expr: Expr) -> Expr {
620
/// Expr::Paren(ExprParen {
621
/// attrs: Vec::new(),
622
/// expr: Box::new(fold_expr(self, expr)),
623
/// paren_token: token::Paren::default(),
624
/// })
625
/// }
626
/// }
627
///
628
/// fn main() {
629
/// let code = quote! { a() + b(1) * c.d };
630
/// let expr: Expr = syn::parse2(code).unwrap();
631
/// let parenthesized = ParenthesizeEveryExpr.fold_expr(expr);
632
/// println!("{}", quote!(#parenthesized));
633
///
634
/// // Output: (((a)()) + (((b)((1))) * ((c).d)))
635
/// }
636
/// ```
637
#[cfg(feature = "fold")]
638
#[cfg_attr(docsrs, doc(cfg(feature = "fold")))]
639
#[rustfmt::skip]
640
pub mod fold;
641
642
/// Syntax tree traversal to walk a shared borrow of a syntax tree.
643
///
644
/// Each method of the [`Visit`] trait is a hook that can be overridden to
645
/// customize the behavior when visiting the corresponding type of node. By
646
/// default, every method recursively visits the substructure of the input
647
/// by invoking the right visitor method of each of its fields.
648
///
649
/// [`Visit`]: visit::Visit
650
///
651
/// ```
652
/// # use syn::{Attribute, BinOp, Expr, ExprBinary};
653
/// #
654
/// pub trait Visit<'ast> {
655
/// /* ... */
656
///
657
/// fn visit_expr_binary(&mut self, node: &'ast ExprBinary) {
658
/// visit_expr_binary(self, node);
659
/// }
660
///
661
/// /* ... */
662
/// # fn visit_attribute(&mut self, node: &'ast Attribute);
663
/// # fn visit_expr(&mut self, node: &'ast Expr);
664
/// # fn visit_bin_op(&mut self, node: &'ast BinOp);
665
/// }
666
///
667
/// pub fn visit_expr_binary<'ast, V>(v: &mut V, node: &'ast ExprBinary)
668
/// where
669
/// V: Visit<'ast> + ?Sized,
670
/// {
671
/// for attr in &node.attrs {
672
/// v.visit_attribute(attr);
673
/// }
674
/// v.visit_expr(&*node.left);
675
/// v.visit_bin_op(&node.op);
676
/// v.visit_expr(&*node.right);
677
/// }
678
///
679
/// /* ... */
680
/// ```
681
///
682
/// <br>
683
///
684
/// # Example
685
///
686
/// This visitor will print the name of every freestanding function in the
687
/// syntax tree, including nested functions.
688
///
689
/// ```
690
/// // [dependencies]
691
/// // quote = "1.0"
692
/// // syn = { version = "2.0", features = ["full", "visit"] }
693
///
694
/// use quote::quote;
695
/// use syn::visit::{self, Visit};
696
/// use syn::{File, ItemFn};
697
///
698
/// struct FnVisitor;
699
///
700
/// impl<'ast> Visit<'ast> for FnVisitor {
701
/// fn visit_item_fn(&mut self, node: &'ast ItemFn) {
702
/// println!("Function with name={}", node.sig.ident);
703
///
704
/// // Delegate to the default impl to visit any nested functions.
705
/// visit::visit_item_fn(self, node);
706
/// }
707
/// }
708
///
709
/// fn main() {
710
/// let code = quote! {
711
/// pub fn f() {
712
/// fn g() {}
713
/// }
714
/// };
715
///
716
/// let syntax_tree: File = syn::parse2(code).unwrap();
717
/// FnVisitor.visit_file(&syntax_tree);
718
/// }
719
/// ```
720
///
721
/// The `'ast` lifetime on the input references means that the syntax tree
722
/// outlives the complete recursive visit call, so the visitor is allowed to
723
/// hold on to references into the syntax tree.
724
///
725
/// ```
726
/// use quote::quote;
727
/// use syn::visit::{self, Visit};
728
/// use syn::{File, ItemFn};
729
///
730
/// struct FnVisitor<'ast> {
731
/// functions: Vec<&'ast ItemFn>,
732
/// }
733
///
734
/// impl<'ast> Visit<'ast> for FnVisitor<'ast> {
735
/// fn visit_item_fn(&mut self, node: &'ast ItemFn) {
736
/// self.functions.push(node);
737
/// visit::visit_item_fn(self, node);
738
/// }
739
/// }
740
///
741
/// fn main() {
742
/// let code = quote! {
743
/// pub fn f() {
744
/// fn g() {}
745
/// }
746
/// };
747
///
748
/// let syntax_tree: File = syn::parse2(code).unwrap();
749
/// let mut visitor = FnVisitor { functions: Vec::new() };
750
/// visitor.visit_file(&syntax_tree);
751
/// for f in visitor.functions {
752
/// println!("Function with name={}", f.sig.ident);
753
/// }
754
/// }
755
/// ```
756
#[cfg(feature = "visit")]
757
#[cfg_attr(docsrs, doc(cfg(feature = "visit")))]
758
#[rustfmt::skip]
759
pub mod visit;
760
761
/// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in
762
/// place.
763
///
764
/// Each method of the [`VisitMut`] trait is a hook that can be overridden
765
/// to customize the behavior when mutating the corresponding type of node.
766
/// By default, every method recursively visits the substructure of the
767
/// input by invoking the right visitor method of each of its fields.
768
///
769
/// [`VisitMut`]: visit_mut::VisitMut
770
///
771
/// ```
772
/// # use syn::{Attribute, BinOp, Expr, ExprBinary};
773
/// #
774
/// pub trait VisitMut {
775
/// /* ... */
776
///
777
/// fn visit_expr_binary_mut(&mut self, node: &mut ExprBinary) {
778
/// visit_expr_binary_mut(self, node);
779
/// }
780
///
781
/// /* ... */
782
/// # fn visit_attribute_mut(&mut self, node: &mut Attribute);
783
/// # fn visit_expr_mut(&mut self, node: &mut Expr);
784
/// # fn visit_bin_op_mut(&mut self, node: &mut BinOp);
785
/// }
786
///
787
/// pub fn visit_expr_binary_mut<V>(v: &mut V, node: &mut ExprBinary)
788
/// where
789
/// V: VisitMut + ?Sized,
790
/// {
791
/// for attr in &mut node.attrs {
792
/// v.visit_attribute_mut(attr);
793
/// }
794
/// v.visit_expr_mut(&mut *node.left);
795
/// v.visit_bin_op_mut(&mut node.op);
796
/// v.visit_expr_mut(&mut *node.right);
797
/// }
798
///
799
/// /* ... */
800
/// ```
801
///
802
/// <br>
803
///
804
/// # Example
805
///
806
/// This mut visitor replace occurrences of u256 suffixed integer literals
807
/// like `999u256` with a macro invocation `bigint::u256!(999)`.
808
///
809
/// ```
810
/// // [dependencies]
811
/// // quote = "1.0"
812
/// // syn = { version = "2.0", features = ["full", "visit-mut"] }
813
///
814
/// use quote::quote;
815
/// use syn::visit_mut::{self, VisitMut};
816
/// use syn::{parse_quote, Expr, File, Lit, LitInt};
817
///
818
/// struct BigintReplace;
819
///
820
/// impl VisitMut for BigintReplace {
821
/// fn visit_expr_mut(&mut self, node: &mut Expr) {
822
/// if let Expr::Lit(expr) = &node {
823
/// if let Lit::Int(int) = &expr.lit {
824
/// if int.suffix() == "u256" {
825
/// let digits = int.base10_digits();
826
/// let unsuffixed: LitInt = syn::parse_str(digits).unwrap();
827
/// *node = parse_quote!(bigint::u256!(#unsuffixed));
828
/// return;
829
/// }
830
/// }
831
/// }
832
///
833
/// // Delegate to the default impl to visit nested expressions.
834
/// visit_mut::visit_expr_mut(self, node);
835
/// }
836
/// }
837
///
838
/// fn main() {
839
/// let code = quote! {
840
/// fn main() {
841
/// let _ = 999u256;
842
/// }
843
/// };
844
///
845
/// let mut syntax_tree: File = syn::parse2(code).unwrap();
846
/// BigintReplace.visit_file_mut(&mut syntax_tree);
847
/// println!("{}", quote!(#syntax_tree));
848
/// }
849
/// ```
850
#[cfg(feature = "visit-mut")]
851
#[cfg_attr(docsrs, doc(cfg(feature = "visit-mut")))]
852
#[rustfmt::skip]
853
pub mod visit_mut;
854
855
#[cfg(feature = "clone-impls")]
856
#[rustfmt::skip]
857
mod clone;
858
859
#[cfg(feature = "extra-traits")]
860
#[rustfmt::skip]
861
mod debug;
862
863
#[cfg(feature = "extra-traits")]
864
#[rustfmt::skip]
865
mod eq;
866
867
#[cfg(feature = "extra-traits")]
868
#[rustfmt::skip]
869
mod hash;
870
}
871
872
#[cfg(feature = "fold")]
873
#[cfg_attr(docsrs, doc(cfg(feature = "fold")))]
874
pub use crate::gen::fold;
875
876
#[cfg(feature = "visit")]
877
#[cfg_attr(docsrs, doc(cfg(feature = "visit")))]
878
pub use crate::gen::visit;
879
880
#[cfg(feature = "visit-mut")]
881
#[cfg_attr(docsrs, doc(cfg(feature = "visit-mut")))]
882
pub use crate::gen::visit_mut;
883
884
// Not public API.
885
#[doc(hidden)]
886
#[path = "export.rs"]
887
pub mod __private;
888
889
/// Parse tokens of source code into the chosen syntax tree node.
890
///
891
/// This is preferred over parsing a string because tokens are able to preserve
892
/// information about where in the user's code they were originally written (the
893
/// "span" of the token), possibly allowing the compiler to produce better error
894
/// messages.
895
///
896
/// This function parses a `proc_macro::TokenStream` which is the type used for
897
/// interop with the compiler in a procedural macro. To parse a
898
/// `proc_macro2::TokenStream`, use [`syn::parse2`] instead.
899
///
900
/// [`syn::parse2`]: parse2
901
///
902
/// This function enforces that the input is fully parsed. If there are any
903
/// unparsed tokens at the end of the stream, an error is returned.
904
#[cfg(all(feature = "parsing", feature = "proc-macro"))]
905
#[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "proc-macro"))))]
906
pub fn parse<T: parse::Parse>(tokens: proc_macro::TokenStream) -> Result<T> {
907
parse::Parser::parse(T::parse, tokens)
908
}
909
910
/// Parse a proc-macro2 token stream into the chosen syntax tree node.
911
///
912
/// This function parses a `proc_macro2::TokenStream` which is commonly useful
913
/// when the input comes from a node of the Syn syntax tree, for example the
914
/// body tokens of a [`Macro`] node. When in a procedural macro parsing the
915
/// `proc_macro::TokenStream` provided by the compiler, use [`syn::parse`]
916
/// instead.
917
///
918
/// [`syn::parse`]: parse()
919
///
920
/// This function enforces that the input is fully parsed. If there are any
921
/// unparsed tokens at the end of the stream, an error is returned.
922
#[cfg(feature = "parsing")]
923
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
924
pub fn parse2<T: parse::Parse>(tokens: proc_macro2::TokenStream) -> Result<T> {
925
parse::Parser::parse2(T::parse, tokens)
926
}
927
928
/// Parse a string of Rust code into the chosen syntax tree node.
929
///
930
/// This function enforces that the input is fully parsed. If there are any
931
/// unparsed tokens at the end of the stream, an error is returned.
932
///
933
/// # Hygiene
934
///
935
/// Every span in the resulting syntax tree will be set to resolve at the macro
936
/// call site.
937
///
938
/// # Examples
939
///
940
/// ```
941
/// use syn::{Expr, Result};
942
///
943
/// fn run() -> Result<()> {
944
/// let code = "assert_eq!(u8::max_value(), 255)";
945
/// let expr = syn::parse_str::<Expr>(code)?;
946
/// println!("{:#?}", expr);
947
/// Ok(())
948
/// }
949
/// #
950
/// # run().unwrap();
951
/// ```
952
#[cfg(feature = "parsing")]
953
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
954
pub fn parse_str<T: parse::Parse>(s: &str) -> Result<T> {
955
parse::Parser::parse_str(T::parse, s)
956
}
957
958
/// Parse the content of a file of Rust code.
959
///
960
/// This is different from `syn::parse_str::<File>(content)` in two ways:
961
///
962
/// - It discards a leading byte order mark `\u{FEFF}` if the file has one.
963
/// - It preserves the shebang line of the file, such as `#!/usr/bin/env rustx`.
964
///
965
/// If present, either of these would be an error using `from_str`.
966
///
967
/// # Examples
968
///
969
/// ```no_run
970
/// use std::error::Error;
971
/// use std::fs;
972
/// use std::io::Read;
973
///
974
/// fn run() -> Result<(), Box<dyn Error>> {
975
/// let content = fs::read_to_string("path/to/code.rs")?;
976
/// let ast = syn::parse_file(&content)?;
977
/// if let Some(shebang) = ast.shebang {
978
/// println!("{}", shebang);
979
/// }
980
/// println!("{} items", ast.items.len());
981
///
982
/// Ok(())
983
/// }
984
/// #
985
/// # run().unwrap();
986
/// ```
987
#[cfg(all(feature = "parsing", feature = "full"))]
988
#[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "full"))))]
989
pub fn parse_file(mut content: &str) -> Result<File> {
990
// Strip the BOM if it is present
991
const BOM: &str = "\u{feff}";
992
if content.starts_with(BOM) {
993
content = &content[BOM.len()..];
994
}
995
996
let mut shebang = None;
997
if content.starts_with("#!") {
998
let rest = whitespace::skip(&content[2..]);
999
if !rest.starts_with('[') {
1000
if let Some(idx) = content.find('\n') {
1001
shebang = Some(content[..idx].to_string());
1002
content = &content[idx..];
1003
} else {
1004
shebang = Some(content.to_string());
1005
content = "";
1006
}
1007
}
1008
}
1009
1010
let mut file: File = parse_str(content)?;
1011
file.shebang = shebang;
1012
Ok(file)
1013
}
1014
1015