blob: e133f758d8844191bfea62e76970f555582a34e0 [file] [log] [blame]
David Tolnayad2836d2017-04-20 10:11:43 -07001#![doc(html_root_url = "https://dtolnay.github.io/syn")]
2
David Tolnaybb4ca9f2017-12-26 12:28:58 -05003#![cfg_attr(feature = "cargo-clippy", allow(
4 const_static_lifetime,
5 doc_markdown,
6 large_enum_variant,
David Tolnay991fdf72017-12-26 23:20:23 -05007 match_bool,
David Tolnaybb4ca9f2017-12-26 12:28:58 -05008 redundant_closure,
9))]
David Tolnayaed77b02016-09-23 20:50:31 -070010
David Tolnayc7a5d3d2017-06-04 12:11:05 -070011extern crate proc_macro;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070012extern crate proc_macro2;
David Tolnay570695e2017-06-03 16:15:13 -070013extern crate unicode_xid;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070014
Nika Layzell7f5fc682017-10-25 00:47:10 -040015#[cfg(any(feature = "printing", feature = "parsing"))]
David Tolnay87d0b442016-09-04 11:52:12 -070016extern crate quote;
17
David Tolnay1b752fb2017-12-26 21:41:39 -050018#[cfg(feature = "parsing")]
David Tolnayf8db7ba2017-11-11 22:52:16 -080019#[macro_use]
David Tolnayc5ab8c62017-12-26 16:43:39 -050020#[doc(hidden)]
21pub mod parsers;
David Tolnay35161ff2016-09-03 11:33:15 -070022
Alex Crichton62a0a592017-05-22 13:58:53 -070023#[macro_use]
24mod macros;
25
David Tolnayc5ab8c62017-12-26 16:43:39 -050026#[cfg(feature = "parsing")]
27#[doc(hidden)]
28#[macro_use]
29pub mod helper;
30
31#[macro_use]
David Tolnay32954ef2017-12-26 22:43:16 -050032pub mod token;
David Tolnayc5ab8c62017-12-26 16:43:39 -050033
David Tolnayb79ee962016-09-04 09:39:20 -070034mod attr;
Alex Crichton62a0a592017-05-22 13:58:53 -070035pub use attr::{Attribute, AttrStyle, MetaItem, NestedMetaItem, MetaItemList,
36 MetaNameValue};
David Tolnay35161ff2016-09-03 11:33:15 -070037
David Tolnayf38cdf62016-09-23 19:07:09 -070038mod data;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070039pub use data::{Field, Variant, VariantData, Visibility, VisRestricted, VisCrate,
40 VisPublic, VisInherited};
David Tolnayf38cdf62016-09-23 19:07:09 -070041
David Tolnayf4bbbd92016-09-23 14:41:55 -070042mod expr;
Michael Layzell734adb42017-06-07 16:58:31 -040043pub use expr::{Expr, ExprKind, ExprBox, ExprInPlace, ExprArray, ExprCall,
David Tolnay05362582017-12-26 01:33:57 -050044 ExprMethodCall, ExprTuple, ExprBinary, ExprUnary, ExprCast,
Michael Layzell734adb42017-06-07 16:58:31 -040045 ExprType, ExprIf, ExprIfLet, ExprWhile, ExprWhileLet,
Alex Crichton62a0a592017-05-22 13:58:53 -070046 ExprForLoop, ExprLoop, ExprMatch, ExprClosure, ExprBlock,
47 ExprAssign, ExprAssignOp, ExprField, ExprTupField, ExprIndex,
48 ExprRange, ExprPath, ExprAddrOf, ExprBreak, ExprContinue,
Alex Crichtonccbb45d2017-05-23 10:58:24 -070049 ExprRet, ExprStruct, ExprRepeat, ExprParen, ExprTry, ExprCatch,
Nika Layzell640832a2017-12-04 13:37:09 -050050 ExprGroup, ExprYield, ExprUnsafe};
Michael Layzell734adb42017-06-07 16:58:31 -040051
52#[cfg(feature = "full")]
53pub use expr::{Arm, BindingMode, Block, CaptureBy, FieldPat, FieldValue, Local,
54 MacStmtStyle, Pat, RangeLimits, Stmt, PatIdent, PatWild,
55 PatStruct, PatTuple, PatTupleStruct, PatPath, PatBox, PatRef,
56 PatLit, PatRange, PatSlice, InPlaceKind};
David Tolnayf4bbbd92016-09-23 14:41:55 -070057
David Tolnayb79ee962016-09-04 09:39:20 -070058mod generics;
David Tolnayc2f1aba2017-11-12 20:29:22 -080059pub use generics::{Generics, GenericParam, LifetimeDef, TraitBoundModifier, TypeParam, TypeParamBound,
David Tolnayfa23f572017-01-23 00:19:11 -080060 WhereBoundPredicate, WhereClause, WhereEqPredicate, WherePredicate,
Nika Layzellf1fdc0b2017-12-04 19:58:32 -050061 WhereRegionPredicate, BoundLifetimes, ConstParam};
David Tolnaye7678922016-10-13 20:44:03 -070062#[cfg(feature = "printing")]
David Tolnayfd6bf5c2017-11-12 09:41:14 -080063pub use generics::{ImplGenerics, Turbofish, TypeGenerics};
David Tolnay35161ff2016-09-03 11:33:15 -070064
David Tolnay55337722016-09-11 12:58:56 -070065mod ident;
David Tolnaydaaf7742016-10-03 11:11:43 -070066pub use ident::Ident;
David Tolnay55337722016-09-11 12:58:56 -070067
David Tolnayf38cdf62016-09-23 19:07:09 -070068#[cfg(feature = "full")]
David Tolnayb79ee962016-09-04 09:39:20 -070069mod item;
David Tolnayf38cdf62016-09-23 19:07:09 -070070#[cfg(feature = "full")]
David Tolnay8894f602017-11-11 12:11:04 -080071pub use item::{Constness, Defaultness, FnArg, FnDecl, ForeignItem, ItemForeignMod,
David Tolnay5f332a92017-12-26 00:42:45 -050072 ImplItem, ImplPolarity, Item, MethodSig,
73 TraitItem, ItemExternCrate, ItemUse,
David Tolnay500d8322017-12-18 00:32:51 -080074 ItemStatic, ItemConst, ItemFn, ItemMacro, ItemMacro2, ItemMod, ItemType, ItemEnum,
Alex Crichton62a0a592017-05-22 13:58:53 -070075 ItemStruct, ItemUnion, ItemTrait, ItemDefaultImpl, ItemImpl,
David Tolnay5f332a92017-12-26 00:42:45 -050076 UsePath, UseGlob, UseList, ForeignItemFn, ForeignItemStatic, ForeignItemType,
David Tolnaydecf28d2017-11-11 11:56:45 -080077 TraitItemConst, TraitItemMacro, TraitItemMethod, TraitItemType,
David Tolnay857628c2017-11-11 12:25:31 -080078 ImplItemConst, ImplItemMacro, ImplItemMethod, ImplItemType, ArgSelfRef,
David Tolnay5f332a92017-12-26 00:42:45 -050079 ArgSelf, ArgCaptured, UseTree};
David Tolnay35161ff2016-09-03 11:33:15 -070080
David Tolnay631cb8c2016-11-10 17:16:41 -080081#[cfg(feature = "full")]
David Tolnayc7a5d3d2017-06-04 12:11:05 -070082mod file;
David Tolnay631cb8c2016-11-10 17:16:41 -080083#[cfg(feature = "full")]
David Tolnayc7a5d3d2017-06-04 12:11:05 -070084pub use file::File;
David Tolnay631cb8c2016-11-10 17:16:41 -080085
David Tolnay63e3dee2017-06-03 20:13:17 -070086mod lifetime;
87pub use lifetime::Lifetime;
88
David Tolnayf4bbbd92016-09-23 14:41:55 -070089mod lit;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070090pub use lit::{Lit, LitKind};
David Tolnayf4bbbd92016-09-23 14:41:55 -070091
David Tolnayf4bbbd92016-09-23 14:41:55 -070092mod mac;
David Tolnay9c76bcb2017-12-26 23:14:59 -050093pub use mac::Macro;
David Tolnayf4bbbd92016-09-23 14:41:55 -070094
David Tolnay0e837402016-12-22 17:25:55 -050095mod derive;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070096pub use derive::{Body, DeriveInput, BodyEnum, BodyStruct};
David Tolnayf38cdf62016-09-23 19:07:09 -070097
David Tolnay3cb23a92016-10-07 23:02:21 -070098mod op;
99pub use op::{BinOp, UnOp};
100
David Tolnayb79ee962016-09-04 09:39:20 -0700101mod ty;
Nika Layzellc08227a2017-12-04 16:30:17 -0500102pub use ty::{Abi, AbiKind, AngleBracketedGenericArguments, BareFnArg,
103 BareFnArgName, BareFnType, ReturnType, MutType, Mutability,
104 ParenthesizedGenericArguments, Path, PathArguments, PathSegment,
105 PolyTraitRef, QSelf, Type, TypeBinding, Unsafety, TypeSlice,
David Tolnay05362582017-12-26 01:33:57 -0500106 TypeArray, TypePtr, TypeReference, TypeBareFn, TypeNever, TypeTuple,
Nika Layzellc08227a2017-12-04 16:30:17 -0500107 TypePath, TypeTraitObject, TypeImplTrait, TypeParen, TypeInfer,
108 TypeGroup, GenericArgument};
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700109#[cfg(feature = "printing")]
110pub use ty::PathTokens;
111
David Tolnay1b752fb2017-12-26 21:41:39 -0500112#[cfg(feature = "parsing")]
David Tolnayc5ab8c62017-12-26 16:43:39 -0500113mod cursor;
David Tolnay1b752fb2017-12-26 21:41:39 -0500114#[cfg(feature = "parsing")]
David Tolnayc5ab8c62017-12-26 16:43:39 -0500115pub mod synom;
116pub mod delimited;
117
Nika Layzella6f46c42017-10-26 15:26:16 -0400118mod gen {
119 #[cfg(feature = "visit")]
120 pub mod visit;
David Tolnay55337722016-09-11 12:58:56 -0700121
Nika Layzella6f46c42017-10-26 15:26:16 -0400122 #[cfg(feature = "visit_mut")]
123 pub mod visit_mut;
Nika Layzell27726662017-10-24 23:16:35 -0400124
Nika Layzella6f46c42017-10-26 15:26:16 -0400125 #[cfg(feature = "fold")]
126 pub mod fold;
127}
128pub use gen::*;
gnzlbg9ae88d82017-01-26 20:45:17 +0100129
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700130////////////////////////////////////////////////////////////////////////////////
131
David Tolnay55337722016-09-11 12:58:56 -0700132#[cfg(feature = "parsing")]
David Tolnayc5ab8c62017-12-26 16:43:39 -0500133use synom::Synom;
134#[cfg(feature = "parsing")]
135use cursor::SynomBuffer;
Ted Driggs054abbb2017-05-01 12:20:52 -0700136
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700137#[cfg(feature = "parsing")]
David Tolnayc5ab8c62017-12-26 16:43:39 -0500138mod error;
139#[cfg(feature = "parsing")]
140pub use error::{PResult, ParseError};
141
142// Not public API.
David Tolnay1b752fb2017-12-26 21:41:39 -0500143#[cfg(feature = "parsing")]
David Tolnayc5ab8c62017-12-26 16:43:39 -0500144#[doc(hidden)]
145pub use error::parse_error;
Michael Layzell416724e2017-05-24 21:12:34 -0400146
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700147/// Parse tokens of source code into the chosen syn data type.
148///
149/// This is preferred over parsing a string because tokens are able to preserve
150/// information about where in the user's code they were originally written (the
151/// "span" of the token), possibly allowing the compiler to produce better error
152/// messages.
153///
154/// # Examples
155///
David Tolnaybcf26022017-12-25 22:10:52 -0500156/// ```rust
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700157/// extern crate proc_macro;
158/// use proc_macro::TokenStream;
159///
160/// extern crate syn;
161///
162/// #[macro_use]
163/// extern crate quote;
164///
165/// use syn::DeriveInput;
166///
David Tolnaybcf26022017-12-25 22:10:52 -0500167/// # const IGNORE_TOKENS: &str = stringify! {
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700168/// #[proc_macro_derive(MyMacro)]
David Tolnaybcf26022017-12-25 22:10:52 -0500169/// # };
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700170/// pub fn my_macro(input: TokenStream) -> TokenStream {
171/// // Parse the tokens into a syntax tree
172/// let ast: DeriveInput = syn::parse(input).unwrap();
173///
174/// // Build the output, possibly using quasi-quotation
175/// let expanded = quote! {
176/// /* ... */
177/// };
178///
David Tolnaybcf26022017-12-25 22:10:52 -0500179/// // Convert into a token stream and return it
180/// expanded.into()
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700181/// }
David Tolnaybcf26022017-12-25 22:10:52 -0500182/// #
183/// # fn main() {}
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700184/// ```
185#[cfg(feature = "parsing")]
186pub fn parse<T>(tokens: proc_macro::TokenStream) -> Result<T, ParseError>
187 where T: Synom,
188{
189 _parse(tokens.into())
190}
191
192#[cfg(feature = "parsing")]
193fn _parse<T>(tokens: proc_macro2::TokenStream) -> Result<T, ParseError>
194 where T: Synom,
195{
196 let buf = SynomBuffer::new(tokens);
197 let result = T::parse(buf.begin());
198 let err = match result {
199 Ok((rest, t)) => {
200 if rest.eof() {
201 return Ok(t);
202 } else if rest == buf.begin() {
203 // parsed nothing
204 ParseError::new("failed to parse anything")
205 } else {
206 ParseError::new("failed to parse all tokens")
David Tolnay55337722016-09-11 12:58:56 -0700207 }
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700208 }
209 Err(err) => err,
210 };
211 match T::description() {
Alex Crichtonc1b76f52017-07-06 15:04:24 -0700212 Some(s) => Err(ParseError::new(format!("failed to parse {}: {}", s, err))),
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700213 None => Err(err),
214 }
215}
Alex Crichton954046c2017-05-30 21:49:42 -0700216
Nika Layzellcda7ebd2017-10-24 23:10:44 -0400217/// Parse a `quote::Tokens` of Rust code into the chosen syn data type.
218///
219/// # Examples
220///
221/// ```rust
222/// extern crate syn;
223/// #
224/// # #[macro_use]
Nika Layzellcda7ebd2017-10-24 23:10:44 -0400225/// # extern crate quote;
David Tolnay9174b972017-11-09 22:27:50 -0800226/// #
227/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
Nika Layzellcda7ebd2017-10-24 23:10:44 -0400228///
229/// use syn::Expr;
Nika Layzellcda7ebd2017-10-24 23:10:44 -0400230///
231/// fn run() -> Result<()> {
232/// let code = quote!(assert_eq!(u8::max_value(), 255));
David Tolnay3e885132017-12-26 23:15:51 -0500233/// let expr = syn::parse_tokens::<Expr>(code)?;
Nika Layzellcda7ebd2017-10-24 23:10:44 -0400234/// println!("{:#?}", expr);
235/// Ok(())
236/// }
237/// #
238/// # fn main() { run().unwrap() }
239/// ```
240#[cfg(feature = "parsing")]
241pub fn parse_tokens<T: Synom>(tokens: quote::Tokens) -> Result<T, ParseError> {
242 _parse(tokens.into())
243}
244
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700245/// Parse a string of Rust code into the chosen syn data type.
246///
247/// # Examples
248///
249/// ```rust
250/// extern crate syn;
251/// #
David Tolnay9174b972017-11-09 22:27:50 -0800252/// #
253/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700254///
255/// use syn::Expr;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700256///
257/// fn run() -> Result<()> {
258/// let code = "assert_eq!(u8::max_value(), 255)";
259/// let expr = syn::parse_str::<Expr>(code)?;
260/// println!("{:#?}", expr);
261/// Ok(())
262/// }
263/// #
264/// # fn main() { run().unwrap() }
265/// ```
266#[cfg(feature = "parsing")]
267pub fn parse_str<T: Synom>(s: &str) -> Result<T, ParseError> {
268 _parse(s.parse()?)
269}
Alex Crichton954046c2017-05-30 21:49:42 -0700270
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700271// FIXME the name parse_file makes it sound like you might pass in a path to a
272// file, rather than the content.
273/// Parse the content of a file of Rust code.
274///
275/// This is different from `syn::parse_str::<File>(content)` in two ways:
276///
277/// - It discards a leading byte order mark `\u{FEFF}` if the file has one.
278/// - It preserves the shebang line of the file, such as `#!/usr/bin/env rustx`.
279///
280/// If present, either of these would be an error using `from_str`.
281///
282/// # Examples
283///
284/// ```rust,no_run
285/// extern crate syn;
286/// #
David Tolnay9174b972017-11-09 22:27:50 -0800287/// #
288/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700289///
290/// use std::fs::File;
291/// use std::io::Read;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700292///
293/// fn run() -> Result<()> {
294/// let mut file = File::open("path/to/code.rs")?;
295/// let mut content = String::new();
296/// file.read_to_string(&mut content)?;
297///
298/// let ast = syn::parse_file(&content)?;
299/// if let Some(shebang) = ast.shebang {
300/// println!("{}", shebang);
301/// }
302/// println!("{} items", ast.items.len());
303///
304/// Ok(())
305/// }
306/// #
307/// # fn main() { run().unwrap() }
308/// ```
309#[cfg(all(feature = "parsing", feature = "full"))]
310pub fn parse_file(mut content: &str) -> Result<File, ParseError> {
311 // Strip the BOM if it is present
312 const BOM: &'static str = "\u{feff}";
313 if content.starts_with(BOM) {
314 content = &content[BOM.len()..];
David Tolnay35161ff2016-09-03 11:33:15 -0700315 }
Michael Layzell5e107ff2017-01-24 19:58:39 -0500316
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700317 let mut shebang = None;
318 if content.starts_with("#!") && !content.starts_with("#![") {
319 if let Some(idx) = content.find('\n') {
320 shebang = Some(content[..idx].to_string());
321 content = &content[idx..];
322 } else {
323 shebang = Some(content.to_string());
324 content = "";
325 }
Alex Crichton954046c2017-05-30 21:49:42 -0700326 }
David Tolnay0a8972b2017-02-27 02:10:01 -0800327
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700328 let mut file: File = parse_str(content)?;
329 file.shebang = shebang;
330 Ok(file)
Michael Layzell5e107ff2017-01-24 19:58:39 -0500331}
Alex Crichton259ee532017-07-14 06:51:02 -0700332
333#[cfg(feature = "printing")]
334struct TokensOrDefault<'a, T: 'a>(&'a Option<T>);
335
336#[cfg(feature = "printing")]
337impl<'a, T> quote::ToTokens for TokensOrDefault<'a, T>
338 where T: quote::ToTokens + Default,
339{
340 fn to_tokens(&self, tokens: &mut quote::Tokens) {
341 match *self.0 {
342 Some(ref t) => t.to_tokens(tokens),
343 None => T::default().to_tokens(tokens),
344 }
345 }
346}