blob: f465f30ac8ffda93d78ed576cd9d6a2b70c3c45c [file] [log] [blame]
David Tolnayad2836d2017-04-20 10:11:43 -07001#![doc(html_root_url = "https://dtolnay.github.io/syn")]
David Tolnay51382052017-12-27 13:46:21 -05002#![cfg_attr(feature = "cargo-clippy",
3 allow(const_static_lifetime, doc_markdown, large_enum_variant, match_bool,
4 redundant_closure))]
David Tolnayad2836d2017-04-20 10:11:43 -07005
Alex Crichtonccbb45d2017-05-23 10:58:24 -07006extern crate proc_macro2;
David Tolnay51382052017-12-27 13:46:21 -05007extern crate proc_macro;
David Tolnay570695e2017-06-03 16:15:13 -07008extern crate unicode_xid;
Alex Crichtonccbb45d2017-05-23 10:58:24 -07009
Nika Layzell7f5fc682017-10-25 00:47:10 -040010#[cfg(any(feature = "printing", feature = "parsing"))]
David Tolnay87d0b442016-09-04 11:52:12 -070011extern crate quote;
12
David Tolnay1b752fb2017-12-26 21:41:39 -050013#[cfg(feature = "parsing")]
David Tolnayf8db7ba2017-11-11 22:52:16 -080014#[macro_use]
David Tolnayc5ab8c62017-12-26 16:43:39 -050015#[doc(hidden)]
16pub mod parsers;
David Tolnay35161ff2016-09-03 11:33:15 -070017
Alex Crichton62a0a592017-05-22 13:58:53 -070018#[macro_use]
19mod macros;
20
David Tolnayc5ab8c62017-12-26 16:43:39 -050021#[cfg(feature = "parsing")]
22#[doc(hidden)]
23#[macro_use]
24pub mod helper;
25
26#[macro_use]
David Tolnay32954ef2017-12-26 22:43:16 -050027pub mod token;
David Tolnayc5ab8c62017-12-26 16:43:39 -050028
David Tolnayb79ee962016-09-04 09:39:20 -070029mod attr;
David Tolnay51382052017-12-27 13:46:21 -050030pub use attr::{AttrStyle, Attribute, MetaItem, MetaItemList, MetaNameValue, NestedMetaItem};
David Tolnay35161ff2016-09-03 11:33:15 -070031
David Tolnayf38cdf62016-09-23 19:07:09 -070032mod data;
David Tolnayfcfb9002017-12-28 22:04:29 -050033pub use data::{Field, Variant, VariantData, VisCrate, VisPublic, VisRestricted, Visibility};
David Tolnayf38cdf62016-09-23 19:07:09 -070034
David Tolnayf4bbbd92016-09-23 14:41:55 -070035mod expr;
David Tolnay51382052017-12-27 13:46:21 -050036pub use expr::{Expr, ExprAddrOf, ExprArray, ExprAssign, ExprAssignOp, ExprBinary, ExprBlock,
37 ExprBox, ExprBreak, ExprCall, ExprCast, ExprCatch, ExprClosure, ExprContinue,
38 ExprField, ExprForLoop, ExprGroup, ExprIf, ExprIfLet, ExprInPlace, ExprIndex,
David Tolnay8c91b882017-12-28 23:04:32 -050039 ExprLit, ExprLoop, ExprMacro, ExprMatch, ExprMethodCall, ExprParen, ExprPath, ExprRange,
David Tolnayc246cd32017-12-28 23:14:32 -050040 ExprRepeat, ExprReturn, ExprStruct, ExprTry, ExprTuple, ExprType,
David Tolnay2ae520a2017-12-29 11:19:50 -050041 ExprUnary, ExprUnsafe, ExprVerbatim, ExprWhile, ExprWhileLet, ExprYield, Index, Member};
Michael Layzell734adb42017-06-07 16:58:31 -040042
43#[cfg(feature = "full")]
David Tolnayefc96fb2017-12-29 02:03:15 -050044pub use expr::{Arm, Block, FieldPat, FieldValue, GenericMethodArgument, Local,
David Tolnay14982012017-12-29 00:49:51 -050045 MethodTurbofish, Pat, PatBox, PatIdent, PatLit, PatPath, PatRange, PatRef, PatSlice,
David Tolnay2ae520a2017-12-29 11:19:50 -050046 PatStruct, PatTuple, PatTupleStruct, PatVerbatim, PatWild, RangeLimits, Stmt};
David Tolnayf4bbbd92016-09-23 14:41:55 -070047
David Tolnayb79ee962016-09-04 09:39:20 -070048mod generics;
David Tolnay51382052017-12-27 13:46:21 -050049pub use generics::{BoundLifetimes, ConstParam, GenericParam, Generics, LifetimeDef,
50 TraitBoundModifier, TypeParam, TypeParamBound, WhereBoundPredicate,
51 WhereClause, WhereEqPredicate, WherePredicate, WhereRegionPredicate};
David Tolnaye7678922016-10-13 20:44:03 -070052#[cfg(feature = "printing")]
David Tolnayfd6bf5c2017-11-12 09:41:14 -080053pub use generics::{ImplGenerics, Turbofish, TypeGenerics};
David Tolnay35161ff2016-09-03 11:33:15 -070054
David Tolnay55337722016-09-11 12:58:56 -070055mod ident;
David Tolnaydaaf7742016-10-03 11:11:43 -070056pub use ident::Ident;
David Tolnay55337722016-09-11 12:58:56 -070057
David Tolnayf38cdf62016-09-23 19:07:09 -070058#[cfg(feature = "full")]
David Tolnayb79ee962016-09-04 09:39:20 -070059mod item;
David Tolnayf38cdf62016-09-23 19:07:09 -070060#[cfg(feature = "full")]
David Tolnay360a6342017-12-29 02:22:11 -050061pub use item::{ArgCaptured, ArgSelf, ArgSelfRef, FnArg, FnDecl,
David Tolnay2ae520a2017-12-29 11:19:50 -050062 ForeignItem, ForeignItemFn, ForeignItemStatic, ForeignItemType, ForeignItemVerbatim, ImplItem,
63 ImplItemConst, ImplItemMacro, ImplItemMethod, ImplItemType, ImplItemVerbatim, Item,
David Tolnay51382052017-12-27 13:46:21 -050064 ItemConst, ItemDefaultImpl, ItemEnum, ItemExternCrate, ItemFn, ItemForeignMod,
65 ItemImpl, ItemMacro, ItemMacro2, ItemMod, ItemStatic, ItemStruct, ItemTrait,
David Tolnay2ae520a2017-12-29 11:19:50 -050066 ItemType, ItemUnion, ItemUse, ItemVerbatim, MethodSig, TraitItem, TraitItemConst, TraitItemMacro,
67 TraitItemMethod, TraitItemType, TraitItemVerbatim, UseGlob, UseList, UsePath, UseTree};
David Tolnay35161ff2016-09-03 11:33:15 -070068
David Tolnay631cb8c2016-11-10 17:16:41 -080069#[cfg(feature = "full")]
David Tolnayc7a5d3d2017-06-04 12:11:05 -070070mod file;
David Tolnay631cb8c2016-11-10 17:16:41 -080071#[cfg(feature = "full")]
David Tolnayc7a5d3d2017-06-04 12:11:05 -070072pub use file::File;
David Tolnay631cb8c2016-11-10 17:16:41 -080073
David Tolnay63e3dee2017-06-03 20:13:17 -070074mod lifetime;
75pub use lifetime::Lifetime;
76
David Tolnayf4bbbd92016-09-23 14:41:55 -070077mod lit;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070078pub use lit::{Lit, LitKind};
David Tolnayf4bbbd92016-09-23 14:41:55 -070079
David Tolnayf4bbbd92016-09-23 14:41:55 -070080mod mac;
David Tolnay9c76bcb2017-12-26 23:14:59 -050081pub use mac::Macro;
David Tolnayf4bbbd92016-09-23 14:41:55 -070082
David Tolnay0e837402016-12-22 17:25:55 -050083mod derive;
David Tolnay51382052017-12-27 13:46:21 -050084pub use derive::{Body, BodyEnum, BodyStruct, DeriveInput};
David Tolnayf38cdf62016-09-23 19:07:09 -070085
David Tolnay3cb23a92016-10-07 23:02:21 -070086mod op;
87pub use op::{BinOp, UnOp};
88
David Tolnayb79ee962016-09-04 09:39:20 -070089mod ty;
David Tolnayd5125762017-12-29 02:42:17 -050090pub use ty::{Abi, AngleBracketedGenericArguments, BareFnArg, BareFnArgName,
David Tolnay136aaa32017-12-29 02:37:36 -050091 GenericArgument, ParenthesizedGenericArguments, Path,
David Tolnay51382052017-12-27 13:46:21 -050092 PathArguments, PathSegment, PolyTraitRef, QSelf, ReturnType, Type, TypeArray,
93 TypeBareFn, TypeBinding, TypeGroup, TypeImplTrait, TypeInfer, TypeNever, TypeParen,
David Tolnay2ae520a2017-12-29 11:19:50 -050094 TypePath, TypePtr, TypeReference, TypeSlice, TypeTraitObject, TypeTuple, TypeVerbatim};
Alex Crichtonccbb45d2017-05-23 10:58:24 -070095#[cfg(feature = "printing")]
96pub use ty::PathTokens;
97
David Tolnay1b752fb2017-12-26 21:41:39 -050098#[cfg(feature = "parsing")]
David Tolnayc5ab8c62017-12-26 16:43:39 -050099mod cursor;
David Tolnay1b752fb2017-12-26 21:41:39 -0500100#[cfg(feature = "parsing")]
David Tolnayc5ab8c62017-12-26 16:43:39 -0500101pub mod synom;
102pub mod delimited;
David Tolnaye0824032017-12-27 15:25:56 -0500103#[cfg(feature = "parsing")]
104mod tt;
David Tolnayc5ab8c62017-12-26 16:43:39 -0500105
Nika Layzella6f46c42017-10-26 15:26:16 -0400106mod gen {
107 #[cfg(feature = "visit")]
108 pub mod visit;
David Tolnay55337722016-09-11 12:58:56 -0700109
Nika Layzella6f46c42017-10-26 15:26:16 -0400110 #[cfg(feature = "visit_mut")]
111 pub mod visit_mut;
Nika Layzell27726662017-10-24 23:16:35 -0400112
Nika Layzella6f46c42017-10-26 15:26:16 -0400113 #[cfg(feature = "fold")]
114 pub mod fold;
David Tolnayf60f4262017-12-28 19:17:58 -0500115
116 #[path = "../gen_helper.rs"]
117 mod helper;
Nika Layzella6f46c42017-10-26 15:26:16 -0400118}
119pub use gen::*;
gnzlbg9ae88d82017-01-26 20:45:17 +0100120
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700121////////////////////////////////////////////////////////////////////////////////
122
David Tolnay55337722016-09-11 12:58:56 -0700123#[cfg(feature = "parsing")]
David Tolnayc5ab8c62017-12-26 16:43:39 -0500124use synom::Synom;
125#[cfg(feature = "parsing")]
126use cursor::SynomBuffer;
Ted Driggs054abbb2017-05-01 12:20:52 -0700127
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700128#[cfg(feature = "parsing")]
David Tolnayc5ab8c62017-12-26 16:43:39 -0500129mod error;
130#[cfg(feature = "parsing")]
David Tolnay203557a2017-12-27 23:59:33 -0500131use error::ParseError;
David Tolnayc5ab8c62017-12-26 16:43:39 -0500132
133// Not public API.
David Tolnay1b752fb2017-12-26 21:41:39 -0500134#[cfg(feature = "parsing")]
David Tolnayc5ab8c62017-12-26 16:43:39 -0500135#[doc(hidden)]
136pub use error::parse_error;
Michael Layzell416724e2017-05-24 21:12:34 -0400137
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700138/// Parse tokens of source code into the chosen syn data type.
139///
140/// This is preferred over parsing a string because tokens are able to preserve
141/// information about where in the user's code they were originally written (the
142/// "span" of the token), possibly allowing the compiler to produce better error
143/// messages.
144///
145/// # Examples
146///
David Tolnaybcf26022017-12-25 22:10:52 -0500147/// ```rust
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700148/// extern crate proc_macro;
149/// use proc_macro::TokenStream;
150///
151/// extern crate syn;
152///
153/// #[macro_use]
154/// extern crate quote;
155///
156/// use syn::DeriveInput;
157///
David Tolnaybcf26022017-12-25 22:10:52 -0500158/// # const IGNORE_TOKENS: &str = stringify! {
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700159/// #[proc_macro_derive(MyMacro)]
David Tolnaybcf26022017-12-25 22:10:52 -0500160/// # };
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700161/// pub fn my_macro(input: TokenStream) -> TokenStream {
162/// // Parse the tokens into a syntax tree
163/// let ast: DeriveInput = syn::parse(input).unwrap();
164///
165/// // Build the output, possibly using quasi-quotation
166/// let expanded = quote! {
167/// /* ... */
168/// };
169///
David Tolnaybcf26022017-12-25 22:10:52 -0500170/// // Convert into a token stream and return it
171/// expanded.into()
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700172/// }
David Tolnaybcf26022017-12-25 22:10:52 -0500173/// #
174/// # fn main() {}
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700175/// ```
176#[cfg(feature = "parsing")]
177pub fn parse<T>(tokens: proc_macro::TokenStream) -> Result<T, ParseError>
David Tolnay51382052017-12-27 13:46:21 -0500178where
179 T: Synom,
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700180{
181 _parse(tokens.into())
182}
183
184#[cfg(feature = "parsing")]
185fn _parse<T>(tokens: proc_macro2::TokenStream) -> Result<T, ParseError>
David Tolnay51382052017-12-27 13:46:21 -0500186where
187 T: Synom,
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700188{
189 let buf = SynomBuffer::new(tokens);
190 let result = T::parse(buf.begin());
191 let err = match result {
192 Ok((rest, t)) => {
193 if rest.eof() {
194 return Ok(t);
195 } else if rest == buf.begin() {
196 // parsed nothing
197 ParseError::new("failed to parse anything")
198 } else {
199 ParseError::new("failed to parse all tokens")
David Tolnay55337722016-09-11 12:58:56 -0700200 }
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700201 }
202 Err(err) => err,
203 };
204 match T::description() {
Alex Crichtonc1b76f52017-07-06 15:04:24 -0700205 Some(s) => Err(ParseError::new(format!("failed to parse {}: {}", s, err))),
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700206 None => Err(err),
207 }
208}
Alex Crichton954046c2017-05-30 21:49:42 -0700209
Nika Layzellcda7ebd2017-10-24 23:10:44 -0400210/// Parse a `quote::Tokens` of Rust code into the chosen syn data type.
211///
212/// # Examples
213///
214/// ```rust
215/// extern crate syn;
216/// #
217/// # #[macro_use]
Nika Layzellcda7ebd2017-10-24 23:10:44 -0400218/// # extern crate quote;
David Tolnay9174b972017-11-09 22:27:50 -0800219/// #
220/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
Nika Layzellcda7ebd2017-10-24 23:10:44 -0400221///
222/// use syn::Expr;
Nika Layzellcda7ebd2017-10-24 23:10:44 -0400223///
224/// fn run() -> Result<()> {
225/// let code = quote!(assert_eq!(u8::max_value(), 255));
David Tolnay3e885132017-12-26 23:15:51 -0500226/// let expr = syn::parse_tokens::<Expr>(code)?;
Nika Layzellcda7ebd2017-10-24 23:10:44 -0400227/// println!("{:#?}", expr);
228/// Ok(())
229/// }
230/// #
231/// # fn main() { run().unwrap() }
232/// ```
233#[cfg(feature = "parsing")]
234pub fn parse_tokens<T: Synom>(tokens: quote::Tokens) -> Result<T, ParseError> {
235 _parse(tokens.into())
236}
237
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700238/// Parse a string of Rust code into the chosen syn data type.
239///
240/// # Examples
241///
242/// ```rust
243/// extern crate syn;
244/// #
David Tolnay9174b972017-11-09 22:27:50 -0800245/// #
246/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700247///
248/// use syn::Expr;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700249///
250/// fn run() -> Result<()> {
251/// let code = "assert_eq!(u8::max_value(), 255)";
252/// let expr = syn::parse_str::<Expr>(code)?;
253/// println!("{:#?}", expr);
254/// Ok(())
255/// }
256/// #
257/// # fn main() { run().unwrap() }
258/// ```
259#[cfg(feature = "parsing")]
260pub fn parse_str<T: Synom>(s: &str) -> Result<T, ParseError> {
David Tolnayffb1f4d2017-12-28 00:07:59 -0500261 match s.parse() {
262 Ok(tts) => _parse(tts),
263 Err(_) => Err(ParseError::new("error while lexing input string")),
264 }
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700265}
Alex Crichton954046c2017-05-30 21:49:42 -0700266
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700267// FIXME the name parse_file makes it sound like you might pass in a path to a
268// file, rather than the content.
269/// Parse the content of a file of Rust code.
270///
271/// This is different from `syn::parse_str::<File>(content)` in two ways:
272///
273/// - It discards a leading byte order mark `\u{FEFF}` if the file has one.
274/// - It preserves the shebang line of the file, such as `#!/usr/bin/env rustx`.
275///
276/// If present, either of these would be an error using `from_str`.
277///
278/// # Examples
279///
280/// ```rust,no_run
281/// extern crate syn;
282/// #
David Tolnay9174b972017-11-09 22:27:50 -0800283/// #
284/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700285///
286/// use std::fs::File;
287/// use std::io::Read;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700288///
289/// fn run() -> Result<()> {
290/// let mut file = File::open("path/to/code.rs")?;
291/// let mut content = String::new();
292/// file.read_to_string(&mut content)?;
293///
294/// let ast = syn::parse_file(&content)?;
295/// if let Some(shebang) = ast.shebang {
296/// println!("{}", shebang);
297/// }
298/// println!("{} items", ast.items.len());
299///
300/// Ok(())
301/// }
302/// #
303/// # fn main() { run().unwrap() }
304/// ```
305#[cfg(all(feature = "parsing", feature = "full"))]
306pub fn parse_file(mut content: &str) -> Result<File, ParseError> {
307 // Strip the BOM if it is present
308 const BOM: &'static str = "\u{feff}";
309 if content.starts_with(BOM) {
310 content = &content[BOM.len()..];
David Tolnay35161ff2016-09-03 11:33:15 -0700311 }
Michael Layzell5e107ff2017-01-24 19:58:39 -0500312
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700313 let mut shebang = None;
314 if content.starts_with("#!") && !content.starts_with("#![") {
315 if let Some(idx) = content.find('\n') {
316 shebang = Some(content[..idx].to_string());
317 content = &content[idx..];
318 } else {
319 shebang = Some(content.to_string());
320 content = "";
321 }
Alex Crichton954046c2017-05-30 21:49:42 -0700322 }
David Tolnay0a8972b2017-02-27 02:10:01 -0800323
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700324 let mut file: File = parse_str(content)?;
325 file.shebang = shebang;
326 Ok(file)
Michael Layzell5e107ff2017-01-24 19:58:39 -0500327}
Alex Crichton259ee532017-07-14 06:51:02 -0700328
329#[cfg(feature = "printing")]
330struct TokensOrDefault<'a, T: 'a>(&'a Option<T>);
331
332#[cfg(feature = "printing")]
333impl<'a, T> quote::ToTokens for TokensOrDefault<'a, T>
David Tolnay51382052017-12-27 13:46:21 -0500334where
335 T: quote::ToTokens + Default,
Alex Crichton259ee532017-07-14 06:51:02 -0700336{
337 fn to_tokens(&self, tokens: &mut quote::Tokens) {
338 match *self.0 {
339 Some(ref t) => t.to_tokens(tokens),
340 None => T::default().to_tokens(tokens),
341 }
342 }
343}