blob: 106a045a298fd8b58d0904d972414538e6e531e8 [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 Tolnay51382052017-12-27 13:46:21 -050033pub use data::{Field, Variant, VariantData, VisCrate, VisInherited, VisPublic, VisRestricted,
34 Visibility};
David Tolnayf38cdf62016-09-23 19:07:09 -070035
David Tolnayf4bbbd92016-09-23 14:41:55 -070036mod expr;
David Tolnay51382052017-12-27 13:46:21 -050037pub use expr::{Expr, ExprAddrOf, ExprArray, ExprAssign, ExprAssignOp, ExprBinary, ExprBlock,
38 ExprBox, ExprBreak, ExprCall, ExprCast, ExprCatch, ExprClosure, ExprContinue,
39 ExprField, ExprForLoop, ExprGroup, ExprIf, ExprIfLet, ExprInPlace, ExprIndex,
40 ExprKind, ExprLoop, ExprMatch, ExprMethodCall, ExprParen, ExprPath, ExprRange,
41 ExprRepeat, ExprRet, ExprStruct, ExprTry, ExprTupField, ExprTuple, ExprType,
42 ExprUnary, ExprUnsafe, ExprWhile, ExprWhileLet, ExprYield};
Michael Layzell734adb42017-06-07 16:58:31 -040043
44#[cfg(feature = "full")]
David Tolnay51382052017-12-27 13:46:21 -050045pub use expr::{Arm, BindingMode, Block, CaptureBy, FieldPat, FieldValue, InPlaceKind, Local,
46 MacStmtStyle, Pat, PatBox, PatIdent, PatLit, PatPath, PatRange, PatRef, PatSlice,
47 PatStruct, PatTuple, PatTupleStruct, PatWild, RangeLimits, Stmt};
David Tolnayf4bbbd92016-09-23 14:41:55 -070048
David Tolnayb79ee962016-09-04 09:39:20 -070049mod generics;
David Tolnay51382052017-12-27 13:46:21 -050050pub use generics::{BoundLifetimes, ConstParam, GenericParam, Generics, LifetimeDef,
51 TraitBoundModifier, TypeParam, TypeParamBound, WhereBoundPredicate,
52 WhereClause, WhereEqPredicate, WherePredicate, WhereRegionPredicate};
David Tolnaye7678922016-10-13 20:44:03 -070053#[cfg(feature = "printing")]
David Tolnayfd6bf5c2017-11-12 09:41:14 -080054pub use generics::{ImplGenerics, Turbofish, TypeGenerics};
David Tolnay35161ff2016-09-03 11:33:15 -070055
David Tolnay55337722016-09-11 12:58:56 -070056mod ident;
David Tolnaydaaf7742016-10-03 11:11:43 -070057pub use ident::Ident;
David Tolnay55337722016-09-11 12:58:56 -070058
David Tolnayf38cdf62016-09-23 19:07:09 -070059#[cfg(feature = "full")]
David Tolnayb79ee962016-09-04 09:39:20 -070060mod item;
David Tolnayf38cdf62016-09-23 19:07:09 -070061#[cfg(feature = "full")]
David Tolnay51382052017-12-27 13:46:21 -050062pub use item::{ArgCaptured, ArgSelf, ArgSelfRef, Constness, Defaultness, FnArg, FnDecl,
63 ForeignItem, ForeignItemFn, ForeignItemStatic, ForeignItemType, ImplItem,
64 ImplItemConst, ImplItemMacro, ImplItemMethod, ImplItemType, ImplPolarity, Item,
65 ItemConst, ItemDefaultImpl, ItemEnum, ItemExternCrate, ItemFn, ItemForeignMod,
66 ItemImpl, ItemMacro, ItemMacro2, ItemMod, ItemStatic, ItemStruct, ItemTrait,
67 ItemType, ItemUnion, ItemUse, MethodSig, TraitItem, TraitItemConst, TraitItemMacro,
68 TraitItemMethod, TraitItemType, UseGlob, UseList, UsePath, UseTree};
David Tolnay35161ff2016-09-03 11:33:15 -070069
David Tolnay631cb8c2016-11-10 17:16:41 -080070#[cfg(feature = "full")]
David Tolnayc7a5d3d2017-06-04 12:11:05 -070071mod file;
David Tolnay631cb8c2016-11-10 17:16:41 -080072#[cfg(feature = "full")]
David Tolnayc7a5d3d2017-06-04 12:11:05 -070073pub use file::File;
David Tolnay631cb8c2016-11-10 17:16:41 -080074
David Tolnay63e3dee2017-06-03 20:13:17 -070075mod lifetime;
76pub use lifetime::Lifetime;
77
David Tolnayf4bbbd92016-09-23 14:41:55 -070078mod lit;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070079pub use lit::{Lit, LitKind};
David Tolnayf4bbbd92016-09-23 14:41:55 -070080
David Tolnayf4bbbd92016-09-23 14:41:55 -070081mod mac;
David Tolnay9c76bcb2017-12-26 23:14:59 -050082pub use mac::Macro;
David Tolnayf4bbbd92016-09-23 14:41:55 -070083
David Tolnay0e837402016-12-22 17:25:55 -050084mod derive;
David Tolnay51382052017-12-27 13:46:21 -050085pub use derive::{Body, BodyEnum, BodyStruct, DeriveInput};
David Tolnayf38cdf62016-09-23 19:07:09 -070086
David Tolnay3cb23a92016-10-07 23:02:21 -070087mod op;
88pub use op::{BinOp, UnOp};
89
David Tolnayb79ee962016-09-04 09:39:20 -070090mod ty;
David Tolnay51382052017-12-27 13:46:21 -050091pub use ty::{Abi, AbiKind, AngleBracketedGenericArguments, BareFnArg, BareFnArgName, BareFnType,
92 GenericArgument, MutType, Mutability, ParenthesizedGenericArguments, Path,
93 PathArguments, PathSegment, PolyTraitRef, QSelf, ReturnType, Type, TypeArray,
94 TypeBareFn, TypeBinding, TypeGroup, TypeImplTrait, TypeInfer, TypeNever, TypeParen,
95 TypePath, TypePtr, TypeReference, TypeSlice, TypeTraitObject, TypeTuple, Unsafety};
Alex Crichtonccbb45d2017-05-23 10:58:24 -070096#[cfg(feature = "printing")]
97pub use ty::PathTokens;
98
David Tolnay1b752fb2017-12-26 21:41:39 -050099#[cfg(feature = "parsing")]
David Tolnayc5ab8c62017-12-26 16:43:39 -0500100mod cursor;
David Tolnay1b752fb2017-12-26 21:41:39 -0500101#[cfg(feature = "parsing")]
David Tolnayc5ab8c62017-12-26 16:43:39 -0500102pub mod synom;
103pub mod delimited;
104
Nika Layzella6f46c42017-10-26 15:26:16 -0400105mod gen {
106 #[cfg(feature = "visit")]
107 pub mod visit;
David Tolnay55337722016-09-11 12:58:56 -0700108
Nika Layzella6f46c42017-10-26 15:26:16 -0400109 #[cfg(feature = "visit_mut")]
110 pub mod visit_mut;
Nika Layzell27726662017-10-24 23:16:35 -0400111
Nika Layzella6f46c42017-10-26 15:26:16 -0400112 #[cfg(feature = "fold")]
113 pub mod fold;
114}
115pub use gen::*;
gnzlbg9ae88d82017-01-26 20:45:17 +0100116
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700117////////////////////////////////////////////////////////////////////////////////
118
David Tolnay55337722016-09-11 12:58:56 -0700119#[cfg(feature = "parsing")]
David Tolnayc5ab8c62017-12-26 16:43:39 -0500120use synom::Synom;
121#[cfg(feature = "parsing")]
122use cursor::SynomBuffer;
Ted Driggs054abbb2017-05-01 12:20:52 -0700123
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700124#[cfg(feature = "parsing")]
David Tolnayc5ab8c62017-12-26 16:43:39 -0500125mod error;
126#[cfg(feature = "parsing")]
127pub use error::{PResult, ParseError};
128
129// Not public API.
David Tolnay1b752fb2017-12-26 21:41:39 -0500130#[cfg(feature = "parsing")]
David Tolnayc5ab8c62017-12-26 16:43:39 -0500131#[doc(hidden)]
132pub use error::parse_error;
Michael Layzell416724e2017-05-24 21:12:34 -0400133
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700134/// Parse tokens of source code into the chosen syn data type.
135///
136/// This is preferred over parsing a string because tokens are able to preserve
137/// information about where in the user's code they were originally written (the
138/// "span" of the token), possibly allowing the compiler to produce better error
139/// messages.
140///
141/// # Examples
142///
David Tolnaybcf26022017-12-25 22:10:52 -0500143/// ```rust
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700144/// extern crate proc_macro;
145/// use proc_macro::TokenStream;
146///
147/// extern crate syn;
148///
149/// #[macro_use]
150/// extern crate quote;
151///
152/// use syn::DeriveInput;
153///
David Tolnaybcf26022017-12-25 22:10:52 -0500154/// # const IGNORE_TOKENS: &str = stringify! {
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700155/// #[proc_macro_derive(MyMacro)]
David Tolnaybcf26022017-12-25 22:10:52 -0500156/// # };
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700157/// pub fn my_macro(input: TokenStream) -> TokenStream {
158/// // Parse the tokens into a syntax tree
159/// let ast: DeriveInput = syn::parse(input).unwrap();
160///
161/// // Build the output, possibly using quasi-quotation
162/// let expanded = quote! {
163/// /* ... */
164/// };
165///
David Tolnaybcf26022017-12-25 22:10:52 -0500166/// // Convert into a token stream and return it
167/// expanded.into()
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700168/// }
David Tolnaybcf26022017-12-25 22:10:52 -0500169/// #
170/// # fn main() {}
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700171/// ```
172#[cfg(feature = "parsing")]
173pub fn parse<T>(tokens: proc_macro::TokenStream) -> Result<T, ParseError>
David Tolnay51382052017-12-27 13:46:21 -0500174where
175 T: Synom,
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700176{
177 _parse(tokens.into())
178}
179
180#[cfg(feature = "parsing")]
181fn _parse<T>(tokens: proc_macro2::TokenStream) -> Result<T, ParseError>
David Tolnay51382052017-12-27 13:46:21 -0500182where
183 T: Synom,
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700184{
185 let buf = SynomBuffer::new(tokens);
186 let result = T::parse(buf.begin());
187 let err = match result {
188 Ok((rest, t)) => {
189 if rest.eof() {
190 return Ok(t);
191 } else if rest == buf.begin() {
192 // parsed nothing
193 ParseError::new("failed to parse anything")
194 } else {
195 ParseError::new("failed to parse all tokens")
David Tolnay55337722016-09-11 12:58:56 -0700196 }
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700197 }
198 Err(err) => err,
199 };
200 match T::description() {
Alex Crichtonc1b76f52017-07-06 15:04:24 -0700201 Some(s) => Err(ParseError::new(format!("failed to parse {}: {}", s, err))),
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700202 None => Err(err),
203 }
204}
Alex Crichton954046c2017-05-30 21:49:42 -0700205
Nika Layzellcda7ebd2017-10-24 23:10:44 -0400206/// Parse a `quote::Tokens` of Rust code into the chosen syn data type.
207///
208/// # Examples
209///
210/// ```rust
211/// extern crate syn;
212/// #
213/// # #[macro_use]
Nika Layzellcda7ebd2017-10-24 23:10:44 -0400214/// # extern crate quote;
David Tolnay9174b972017-11-09 22:27:50 -0800215/// #
216/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
Nika Layzellcda7ebd2017-10-24 23:10:44 -0400217///
218/// use syn::Expr;
Nika Layzellcda7ebd2017-10-24 23:10:44 -0400219///
220/// fn run() -> Result<()> {
221/// let code = quote!(assert_eq!(u8::max_value(), 255));
David Tolnay3e885132017-12-26 23:15:51 -0500222/// let expr = syn::parse_tokens::<Expr>(code)?;
Nika Layzellcda7ebd2017-10-24 23:10:44 -0400223/// println!("{:#?}", expr);
224/// Ok(())
225/// }
226/// #
227/// # fn main() { run().unwrap() }
228/// ```
229#[cfg(feature = "parsing")]
230pub fn parse_tokens<T: Synom>(tokens: quote::Tokens) -> Result<T, ParseError> {
231 _parse(tokens.into())
232}
233
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700234/// Parse a string of Rust code into the chosen syn data type.
235///
236/// # Examples
237///
238/// ```rust
239/// extern crate syn;
240/// #
David Tolnay9174b972017-11-09 22:27:50 -0800241/// #
242/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700243///
244/// use syn::Expr;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700245///
246/// fn run() -> Result<()> {
247/// let code = "assert_eq!(u8::max_value(), 255)";
248/// let expr = syn::parse_str::<Expr>(code)?;
249/// println!("{:#?}", expr);
250/// Ok(())
251/// }
252/// #
253/// # fn main() { run().unwrap() }
254/// ```
255#[cfg(feature = "parsing")]
256pub fn parse_str<T: Synom>(s: &str) -> Result<T, ParseError> {
257 _parse(s.parse()?)
258}
Alex Crichton954046c2017-05-30 21:49:42 -0700259
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700260// FIXME the name parse_file makes it sound like you might pass in a path to a
261// file, rather than the content.
262/// Parse the content of a file of Rust code.
263///
264/// This is different from `syn::parse_str::<File>(content)` in two ways:
265///
266/// - It discards a leading byte order mark `\u{FEFF}` if the file has one.
267/// - It preserves the shebang line of the file, such as `#!/usr/bin/env rustx`.
268///
269/// If present, either of these would be an error using `from_str`.
270///
271/// # Examples
272///
273/// ```rust,no_run
274/// extern crate syn;
275/// #
David Tolnay9174b972017-11-09 22:27:50 -0800276/// #
277/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700278///
279/// use std::fs::File;
280/// use std::io::Read;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700281///
282/// fn run() -> Result<()> {
283/// let mut file = File::open("path/to/code.rs")?;
284/// let mut content = String::new();
285/// file.read_to_string(&mut content)?;
286///
287/// let ast = syn::parse_file(&content)?;
288/// if let Some(shebang) = ast.shebang {
289/// println!("{}", shebang);
290/// }
291/// println!("{} items", ast.items.len());
292///
293/// Ok(())
294/// }
295/// #
296/// # fn main() { run().unwrap() }
297/// ```
298#[cfg(all(feature = "parsing", feature = "full"))]
299pub fn parse_file(mut content: &str) -> Result<File, ParseError> {
300 // Strip the BOM if it is present
301 const BOM: &'static str = "\u{feff}";
302 if content.starts_with(BOM) {
303 content = &content[BOM.len()..];
David Tolnay35161ff2016-09-03 11:33:15 -0700304 }
Michael Layzell5e107ff2017-01-24 19:58:39 -0500305
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700306 let mut shebang = None;
307 if content.starts_with("#!") && !content.starts_with("#![") {
308 if let Some(idx) = content.find('\n') {
309 shebang = Some(content[..idx].to_string());
310 content = &content[idx..];
311 } else {
312 shebang = Some(content.to_string());
313 content = "";
314 }
Alex Crichton954046c2017-05-30 21:49:42 -0700315 }
David Tolnay0a8972b2017-02-27 02:10:01 -0800316
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700317 let mut file: File = parse_str(content)?;
318 file.shebang = shebang;
319 Ok(file)
Michael Layzell5e107ff2017-01-24 19:58:39 -0500320}
Alex Crichton259ee532017-07-14 06:51:02 -0700321
322#[cfg(feature = "printing")]
323struct TokensOrDefault<'a, T: 'a>(&'a Option<T>);
324
325#[cfg(feature = "printing")]
326impl<'a, T> quote::ToTokens for TokensOrDefault<'a, T>
David Tolnay51382052017-12-27 13:46:21 -0500327where
328 T: quote::ToTokens + Default,
Alex Crichton259ee532017-07-14 06:51:02 -0700329{
330 fn to_tokens(&self, tokens: &mut quote::Tokens) {
331 match *self.0 {
332 Some(ref t) => t.to_tokens(tokens),
333 None => T::default().to_tokens(tokens),
334 }
335 }
336}