blob: 820c4fdadbd30833a8b82672a4346534234cfd92 [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,
7 redundant_closure,
8))]
David Tolnayaed77b02016-09-23 20:50:31 -07009
David Tolnayc7a5d3d2017-06-04 12:11:05 -070010extern crate proc_macro;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070011extern crate proc_macro2;
David Tolnay570695e2017-06-03 16:15:13 -070012extern crate unicode_xid;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070013
Nika Layzell7f5fc682017-10-25 00:47:10 -040014#[cfg(any(feature = "printing", feature = "parsing"))]
David Tolnay87d0b442016-09-04 11:52:12 -070015extern crate quote;
16
David Tolnayf8db7ba2017-11-11 22:52:16 -080017#[macro_use]
David Tolnay5fe14fc2017-01-27 16:22:08 -080018extern crate synom;
David Tolnay35161ff2016-09-03 11:33:15 -070019
Alex Crichton62a0a592017-05-22 13:58:53 -070020#[macro_use]
21mod macros;
22
David Tolnayb79ee962016-09-04 09:39:20 -070023mod attr;
Alex Crichton62a0a592017-05-22 13:58:53 -070024pub use attr::{Attribute, AttrStyle, MetaItem, NestedMetaItem, MetaItemList,
25 MetaNameValue};
David Tolnay35161ff2016-09-03 11:33:15 -070026
David Tolnayf38cdf62016-09-23 19:07:09 -070027mod data;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070028pub use data::{Field, Variant, VariantData, Visibility, VisRestricted, VisCrate,
29 VisPublic, VisInherited};
David Tolnayf38cdf62016-09-23 19:07:09 -070030
David Tolnayf4bbbd92016-09-23 14:41:55 -070031mod expr;
Michael Layzell734adb42017-06-07 16:58:31 -040032pub use expr::{Expr, ExprKind, ExprBox, ExprInPlace, ExprArray, ExprCall,
David Tolnay05362582017-12-26 01:33:57 -050033 ExprMethodCall, ExprTuple, ExprBinary, ExprUnary, ExprCast,
Michael Layzell734adb42017-06-07 16:58:31 -040034 ExprType, ExprIf, ExprIfLet, ExprWhile, ExprWhileLet,
Alex Crichton62a0a592017-05-22 13:58:53 -070035 ExprForLoop, ExprLoop, ExprMatch, ExprClosure, ExprBlock,
36 ExprAssign, ExprAssignOp, ExprField, ExprTupField, ExprIndex,
37 ExprRange, ExprPath, ExprAddrOf, ExprBreak, ExprContinue,
Alex Crichtonccbb45d2017-05-23 10:58:24 -070038 ExprRet, ExprStruct, ExprRepeat, ExprParen, ExprTry, ExprCatch,
Nika Layzell640832a2017-12-04 13:37:09 -050039 ExprGroup, ExprYield, ExprUnsafe};
Michael Layzell734adb42017-06-07 16:58:31 -040040
41#[cfg(feature = "full")]
42pub use expr::{Arm, BindingMode, Block, CaptureBy, FieldPat, FieldValue, Local,
43 MacStmtStyle, Pat, RangeLimits, Stmt, PatIdent, PatWild,
44 PatStruct, PatTuple, PatTupleStruct, PatPath, PatBox, PatRef,
45 PatLit, PatRange, PatSlice, InPlaceKind};
David Tolnayf4bbbd92016-09-23 14:41:55 -070046
David Tolnayb79ee962016-09-04 09:39:20 -070047mod generics;
David Tolnayc2f1aba2017-11-12 20:29:22 -080048pub use generics::{Generics, GenericParam, LifetimeDef, TraitBoundModifier, TypeParam, TypeParamBound,
David Tolnayfa23f572017-01-23 00:19:11 -080049 WhereBoundPredicate, WhereClause, WhereEqPredicate, WherePredicate,
Nika Layzellf1fdc0b2017-12-04 19:58:32 -050050 WhereRegionPredicate, BoundLifetimes, ConstParam};
David Tolnaye7678922016-10-13 20:44:03 -070051#[cfg(feature = "printing")]
David Tolnayfd6bf5c2017-11-12 09:41:14 -080052pub use generics::{ImplGenerics, Turbofish, TypeGenerics};
David Tolnay35161ff2016-09-03 11:33:15 -070053
David Tolnay55337722016-09-11 12:58:56 -070054mod ident;
David Tolnaydaaf7742016-10-03 11:11:43 -070055pub use ident::Ident;
David Tolnay55337722016-09-11 12:58:56 -070056
David Tolnayf38cdf62016-09-23 19:07:09 -070057#[cfg(feature = "full")]
David Tolnayb79ee962016-09-04 09:39:20 -070058mod item;
David Tolnayf38cdf62016-09-23 19:07:09 -070059#[cfg(feature = "full")]
David Tolnay8894f602017-11-11 12:11:04 -080060pub use item::{Constness, Defaultness, FnArg, FnDecl, ForeignItem, ItemForeignMod,
David Tolnay5f332a92017-12-26 00:42:45 -050061 ImplItem, ImplPolarity, Item, MethodSig,
62 TraitItem, ItemExternCrate, ItemUse,
David Tolnay500d8322017-12-18 00:32:51 -080063 ItemStatic, ItemConst, ItemFn, ItemMacro, ItemMacro2, ItemMod, ItemType, ItemEnum,
Alex Crichton62a0a592017-05-22 13:58:53 -070064 ItemStruct, ItemUnion, ItemTrait, ItemDefaultImpl, ItemImpl,
David Tolnay5f332a92017-12-26 00:42:45 -050065 UsePath, UseGlob, UseList, ForeignItemFn, ForeignItemStatic, ForeignItemType,
David Tolnaydecf28d2017-11-11 11:56:45 -080066 TraitItemConst, TraitItemMacro, TraitItemMethod, TraitItemType,
David Tolnay857628c2017-11-11 12:25:31 -080067 ImplItemConst, ImplItemMacro, ImplItemMethod, ImplItemType, ArgSelfRef,
David Tolnay5f332a92017-12-26 00:42:45 -050068 ArgSelf, ArgCaptured, 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 Tolnaydecf28d2017-11-11 11:56:45 -080082pub use mac::{Macro, TokenTree};
David Tolnayf4bbbd92016-09-23 14:41:55 -070083
David Tolnay0e837402016-12-22 17:25:55 -050084mod derive;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070085pub use derive::{Body, DeriveInput, BodyEnum, BodyStruct};
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;
Nika Layzellc08227a2017-12-04 16:30:17 -050091pub use ty::{Abi, AbiKind, AngleBracketedGenericArguments, BareFnArg,
92 BareFnArgName, BareFnType, ReturnType, MutType, Mutability,
93 ParenthesizedGenericArguments, Path, PathArguments, PathSegment,
94 PolyTraitRef, QSelf, Type, TypeBinding, Unsafety, TypeSlice,
David Tolnay05362582017-12-26 01:33:57 -050095 TypeArray, TypePtr, TypeReference, TypeBareFn, TypeNever, TypeTuple,
Nika Layzellc08227a2017-12-04 16:30:17 -050096 TypePath, TypeTraitObject, TypeImplTrait, TypeParen, TypeInfer,
97 TypeGroup, GenericArgument};
Alex Crichtonccbb45d2017-05-23 10:58:24 -070098#[cfg(feature = "printing")]
99pub use ty::PathTokens;
100
Alex Crichton954046c2017-05-30 21:49:42 -0700101pub use synom::span::Span;
102pub use synom::tokens;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700103pub use synom::delimited;
David Tolnay35161ff2016-09-03 11:33:15 -0700104
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 Tolnayc7a5d3d2017-06-04 12:11:05 -0700120pub use synom::ParseError;
Ted Driggs054abbb2017-05-01 12:20:52 -0700121
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700122#[cfg(feature = "parsing")]
123use synom::{Synom, SynomBuffer};
Michael Layzell416724e2017-05-24 21:12:34 -0400124
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700125/// Parse tokens of source code into the chosen syn data type.
126///
127/// This is preferred over parsing a string because tokens are able to preserve
128/// information about where in the user's code they were originally written (the
129/// "span" of the token), possibly allowing the compiler to produce better error
130/// messages.
131///
132/// # Examples
133///
David Tolnaybcf26022017-12-25 22:10:52 -0500134/// ```rust
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700135/// extern crate proc_macro;
136/// use proc_macro::TokenStream;
137///
138/// extern crate syn;
139///
140/// #[macro_use]
141/// extern crate quote;
142///
143/// use syn::DeriveInput;
144///
David Tolnaybcf26022017-12-25 22:10:52 -0500145/// # const IGNORE_TOKENS: &str = stringify! {
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700146/// #[proc_macro_derive(MyMacro)]
David Tolnaybcf26022017-12-25 22:10:52 -0500147/// # };
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700148/// pub fn my_macro(input: TokenStream) -> TokenStream {
149/// // Parse the tokens into a syntax tree
150/// let ast: DeriveInput = syn::parse(input).unwrap();
151///
152/// // Build the output, possibly using quasi-quotation
153/// let expanded = quote! {
154/// /* ... */
155/// };
156///
David Tolnaybcf26022017-12-25 22:10:52 -0500157/// // Convert into a token stream and return it
158/// expanded.into()
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700159/// }
David Tolnaybcf26022017-12-25 22:10:52 -0500160/// #
161/// # fn main() {}
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700162/// ```
163#[cfg(feature = "parsing")]
164pub fn parse<T>(tokens: proc_macro::TokenStream) -> Result<T, ParseError>
165 where T: Synom,
166{
167 _parse(tokens.into())
168}
169
170#[cfg(feature = "parsing")]
171fn _parse<T>(tokens: proc_macro2::TokenStream) -> Result<T, ParseError>
172 where T: Synom,
173{
174 let buf = SynomBuffer::new(tokens);
175 let result = T::parse(buf.begin());
176 let err = match result {
177 Ok((rest, t)) => {
178 if rest.eof() {
179 return Ok(t);
180 } else if rest == buf.begin() {
181 // parsed nothing
182 ParseError::new("failed to parse anything")
183 } else {
184 ParseError::new("failed to parse all tokens")
David Tolnay55337722016-09-11 12:58:56 -0700185 }
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700186 }
187 Err(err) => err,
188 };
189 match T::description() {
Alex Crichtonc1b76f52017-07-06 15:04:24 -0700190 Some(s) => Err(ParseError::new(format!("failed to parse {}: {}", s, err))),
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700191 None => Err(err),
192 }
193}
Alex Crichton954046c2017-05-30 21:49:42 -0700194
Nika Layzellcda7ebd2017-10-24 23:10:44 -0400195/// Parse a `quote::Tokens` of Rust code into the chosen syn data type.
196///
197/// # Examples
198///
199/// ```rust
200/// extern crate syn;
201/// #
202/// # #[macro_use]
Nika Layzellcda7ebd2017-10-24 23:10:44 -0400203/// # extern crate quote;
David Tolnay9174b972017-11-09 22:27:50 -0800204/// #
205/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
Nika Layzellcda7ebd2017-10-24 23:10:44 -0400206///
207/// use syn::Expr;
Nika Layzellcda7ebd2017-10-24 23:10:44 -0400208///
209/// fn run() -> Result<()> {
210/// let code = quote!(assert_eq!(u8::max_value(), 255));
211/// let expr = syn::parse_tokens::<Expr>(code)?;
212/// println!("{:#?}", expr);
213/// Ok(())
214/// }
215/// #
216/// # fn main() { run().unwrap() }
217/// ```
218#[cfg(feature = "parsing")]
219pub fn parse_tokens<T: Synom>(tokens: quote::Tokens) -> Result<T, ParseError> {
220 _parse(tokens.into())
221}
222
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700223/// Parse a string of Rust code into the chosen syn data type.
224///
225/// # Examples
226///
227/// ```rust
228/// extern crate syn;
229/// #
David Tolnay9174b972017-11-09 22:27:50 -0800230/// #
231/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700232///
233/// use syn::Expr;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700234///
235/// fn run() -> Result<()> {
236/// let code = "assert_eq!(u8::max_value(), 255)";
237/// let expr = syn::parse_str::<Expr>(code)?;
238/// println!("{:#?}", expr);
239/// Ok(())
240/// }
241/// #
242/// # fn main() { run().unwrap() }
243/// ```
244#[cfg(feature = "parsing")]
245pub fn parse_str<T: Synom>(s: &str) -> Result<T, ParseError> {
246 _parse(s.parse()?)
247}
Alex Crichton954046c2017-05-30 21:49:42 -0700248
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700249// FIXME the name parse_file makes it sound like you might pass in a path to a
250// file, rather than the content.
251/// Parse the content of a file of Rust code.
252///
253/// This is different from `syn::parse_str::<File>(content)` in two ways:
254///
255/// - It discards a leading byte order mark `\u{FEFF}` if the file has one.
256/// - It preserves the shebang line of the file, such as `#!/usr/bin/env rustx`.
257///
258/// If present, either of these would be an error using `from_str`.
259///
260/// # Examples
261///
262/// ```rust,no_run
263/// extern crate syn;
264/// #
David Tolnay9174b972017-11-09 22:27:50 -0800265/// #
266/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700267///
268/// use std::fs::File;
269/// use std::io::Read;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700270///
271/// fn run() -> Result<()> {
272/// let mut file = File::open("path/to/code.rs")?;
273/// let mut content = String::new();
274/// file.read_to_string(&mut content)?;
275///
276/// let ast = syn::parse_file(&content)?;
277/// if let Some(shebang) = ast.shebang {
278/// println!("{}", shebang);
279/// }
280/// println!("{} items", ast.items.len());
281///
282/// Ok(())
283/// }
284/// #
285/// # fn main() { run().unwrap() }
286/// ```
287#[cfg(all(feature = "parsing", feature = "full"))]
288pub fn parse_file(mut content: &str) -> Result<File, ParseError> {
289 // Strip the BOM if it is present
290 const BOM: &'static str = "\u{feff}";
291 if content.starts_with(BOM) {
292 content = &content[BOM.len()..];
David Tolnay35161ff2016-09-03 11:33:15 -0700293 }
Michael Layzell5e107ff2017-01-24 19:58:39 -0500294
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700295 let mut shebang = None;
296 if content.starts_with("#!") && !content.starts_with("#![") {
297 if let Some(idx) = content.find('\n') {
298 shebang = Some(content[..idx].to_string());
299 content = &content[idx..];
300 } else {
301 shebang = Some(content.to_string());
302 content = "";
303 }
Alex Crichton954046c2017-05-30 21:49:42 -0700304 }
David Tolnay0a8972b2017-02-27 02:10:01 -0800305
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700306 let mut file: File = parse_str(content)?;
307 file.shebang = shebang;
308 Ok(file)
Michael Layzell5e107ff2017-01-24 19:58:39 -0500309}
Alex Crichton259ee532017-07-14 06:51:02 -0700310
311#[cfg(feature = "printing")]
312struct TokensOrDefault<'a, T: 'a>(&'a Option<T>);
313
314#[cfg(feature = "printing")]
315impl<'a, T> quote::ToTokens for TokensOrDefault<'a, T>
316 where T: quote::ToTokens + Default,
317{
318 fn to_tokens(&self, tokens: &mut quote::Tokens) {
319 match *self.0 {
320 Some(ref t) => t.to_tokens(tokens),
321 None => T::default().to_tokens(tokens),
322 }
323 }
324}