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