blob: 40472c5f2eb08164ba8f8448635a24aa8165bf57 [file] [log] [blame]
David Tolnayad2836d2017-04-20 10:11:43 -07001#![doc(html_root_url = "https://dtolnay.github.io/syn")]
2
David Tolnay02a8d472017-02-19 12:59:44 -08003#![cfg_attr(feature = "cargo-clippy", allow(large_enum_variant))]
David Tolnayaed77b02016-09-23 20:50:31 -07004
David Tolnayc7a5d3d2017-06-04 12:11:05 -07005extern crate proc_macro;
Alex Crichtonccbb45d2017-05-23 10:58:24 -07006extern crate proc_macro2;
David Tolnay570695e2017-06-03 16:15:13 -07007extern crate unicode_xid;
Alex Crichtonccbb45d2017-05-23 10:58:24 -07008
Nika Layzell7f5fc682017-10-25 00:47:10 -04009#[cfg(any(feature = "printing", feature = "parsing"))]
David Tolnay87d0b442016-09-04 11:52:12 -070010extern crate quote;
11
David Tolnayf8db7ba2017-11-11 22:52:16 -080012#[macro_use]
David Tolnay5fe14fc2017-01-27 16:22:08 -080013extern crate synom;
David Tolnay35161ff2016-09-03 11:33:15 -070014
Alex Crichton62a0a592017-05-22 13:58:53 -070015#[macro_use]
16mod macros;
17
David Tolnayb79ee962016-09-04 09:39:20 -070018mod attr;
Alex Crichton62a0a592017-05-22 13:58:53 -070019pub use attr::{Attribute, AttrStyle, MetaItem, NestedMetaItem, MetaItemList,
20 MetaNameValue};
David Tolnay35161ff2016-09-03 11:33:15 -070021
David Tolnayf38cdf62016-09-23 19:07:09 -070022mod data;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070023pub use data::{Field, Variant, VariantData, Visibility, VisRestricted, VisCrate,
24 VisPublic, VisInherited};
David Tolnayf38cdf62016-09-23 19:07:09 -070025
David Tolnayf4bbbd92016-09-23 14:41:55 -070026mod expr;
Michael Layzell734adb42017-06-07 16:58:31 -040027pub use expr::{Expr, ExprKind, ExprBox, ExprInPlace, ExprArray, ExprCall,
28 ExprMethodCall, ExprTup, ExprBinary, ExprUnary, ExprCast,
29 ExprType, ExprIf, ExprIfLet, ExprWhile, ExprWhileLet,
Alex Crichton62a0a592017-05-22 13:58:53 -070030 ExprForLoop, ExprLoop, ExprMatch, ExprClosure, ExprBlock,
31 ExprAssign, ExprAssignOp, ExprField, ExprTupField, ExprIndex,
32 ExprRange, ExprPath, ExprAddrOf, ExprBreak, ExprContinue,
Alex Crichtonccbb45d2017-05-23 10:58:24 -070033 ExprRet, ExprStruct, ExprRepeat, ExprParen, ExprTry, ExprCatch,
Nika Layzell640832a2017-12-04 13:37:09 -050034 ExprGroup, ExprYield, ExprUnsafe};
Michael Layzell734adb42017-06-07 16:58:31 -040035
36#[cfg(feature = "full")]
37pub use expr::{Arm, BindingMode, Block, CaptureBy, FieldPat, FieldValue, Local,
38 MacStmtStyle, Pat, RangeLimits, Stmt, PatIdent, PatWild,
39 PatStruct, PatTuple, PatTupleStruct, PatPath, PatBox, PatRef,
40 PatLit, PatRange, PatSlice, InPlaceKind};
David Tolnayf4bbbd92016-09-23 14:41:55 -070041
David Tolnayb79ee962016-09-04 09:39:20 -070042mod generics;
David Tolnayc2f1aba2017-11-12 20:29:22 -080043pub use generics::{Generics, GenericParam, LifetimeDef, TraitBoundModifier, TypeParam, TypeParamBound,
David Tolnayfa23f572017-01-23 00:19:11 -080044 WhereBoundPredicate, WhereClause, WhereEqPredicate, WherePredicate,
Nika Layzellf1fdc0b2017-12-04 19:58:32 -050045 WhereRegionPredicate, BoundLifetimes, ConstParam};
David Tolnaye7678922016-10-13 20:44:03 -070046#[cfg(feature = "printing")]
David Tolnayfd6bf5c2017-11-12 09:41:14 -080047pub use generics::{ImplGenerics, Turbofish, TypeGenerics};
David Tolnay35161ff2016-09-03 11:33:15 -070048
David Tolnay55337722016-09-11 12:58:56 -070049mod ident;
David Tolnaydaaf7742016-10-03 11:11:43 -070050pub use ident::Ident;
David Tolnay55337722016-09-11 12:58:56 -070051
David Tolnayf38cdf62016-09-23 19:07:09 -070052#[cfg(feature = "full")]
David Tolnayb79ee962016-09-04 09:39:20 -070053mod item;
David Tolnayf38cdf62016-09-23 19:07:09 -070054#[cfg(feature = "full")]
David Tolnay8894f602017-11-11 12:11:04 -080055pub use item::{Constness, Defaultness, FnArg, FnDecl, ForeignItem, ItemForeignMod,
David Tolnay857628c2017-11-11 12:25:31 -080056 ImplItem, ImplPolarity, Item, MethodSig, PathListItem,
David Tolnayda705bd2017-11-10 21:58:05 -080057 TraitItem, ViewPath, ItemExternCrate, ItemUse,
David Tolnay500d8322017-12-18 00:32:51 -080058 ItemStatic, ItemConst, ItemFn, ItemMacro, ItemMacro2, ItemMod, ItemType, ItemEnum,
Alex Crichton62a0a592017-05-22 13:58:53 -070059 ItemStruct, ItemUnion, ItemTrait, ItemDefaultImpl, ItemImpl,
David Tolnay199bcbb2017-11-12 10:33:52 -080060 PathSimple, PathGlob, PathList, ForeignItemFn, ForeignItemStatic, ForeignItemType,
David Tolnaydecf28d2017-11-11 11:56:45 -080061 TraitItemConst, TraitItemMacro, TraitItemMethod, TraitItemType,
David Tolnay857628c2017-11-11 12:25:31 -080062 ImplItemConst, ImplItemMacro, ImplItemMethod, ImplItemType, ArgSelfRef,
Alex Crichton62a0a592017-05-22 13:58:53 -070063 ArgSelf, ArgCaptured};
David Tolnay35161ff2016-09-03 11:33:15 -070064
David Tolnay631cb8c2016-11-10 17:16:41 -080065#[cfg(feature = "full")]
David Tolnayc7a5d3d2017-06-04 12:11:05 -070066mod file;
David Tolnay631cb8c2016-11-10 17:16:41 -080067#[cfg(feature = "full")]
David Tolnayc7a5d3d2017-06-04 12:11:05 -070068pub use file::File;
David Tolnay631cb8c2016-11-10 17:16:41 -080069
David Tolnay63e3dee2017-06-03 20:13:17 -070070mod lifetime;
71pub use lifetime::Lifetime;
72
David Tolnayf4bbbd92016-09-23 14:41:55 -070073mod lit;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070074pub use lit::{Lit, LitKind};
David Tolnayf4bbbd92016-09-23 14:41:55 -070075
David Tolnayf4bbbd92016-09-23 14:41:55 -070076mod mac;
David Tolnaydecf28d2017-11-11 11:56:45 -080077pub use mac::{Macro, TokenTree};
David Tolnayf4bbbd92016-09-23 14:41:55 -070078
David Tolnay0e837402016-12-22 17:25:55 -050079mod derive;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070080pub use derive::{Body, DeriveInput, BodyEnum, BodyStruct};
David Tolnayf38cdf62016-09-23 19:07:09 -070081
David Tolnay3cb23a92016-10-07 23:02:21 -070082mod op;
83pub use op::{BinOp, UnOp};
84
David Tolnayb79ee962016-09-04 09:39:20 -070085mod ty;
Nika Layzellc08227a2017-12-04 16:30:17 -050086pub use ty::{Abi, AbiKind, AngleBracketedGenericArguments, BareFnArg,
87 BareFnArgName, BareFnType, ReturnType, MutType, Mutability,
88 ParenthesizedGenericArguments, Path, PathArguments, PathSegment,
89 PolyTraitRef, QSelf, Type, TypeBinding, Unsafety, TypeSlice,
90 TypeArray, TypePtr, TypeReference, TypeBareFn, TypeNever, TypeTup,
91 TypePath, TypeTraitObject, TypeImplTrait, TypeParen, TypeInfer,
92 TypeGroup, GenericArgument};
Alex Crichtonccbb45d2017-05-23 10:58:24 -070093#[cfg(feature = "printing")]
94pub use ty::PathTokens;
95
Alex Crichton954046c2017-05-30 21:49:42 -070096pub use synom::span::Span;
97pub use synom::tokens;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070098pub use synom::delimited;
David Tolnay35161ff2016-09-03 11:33:15 -070099
Nika Layzella6f46c42017-10-26 15:26:16 -0400100mod gen {
101 #[cfg(feature = "visit")]
102 pub mod visit;
David Tolnay55337722016-09-11 12:58:56 -0700103
Nika Layzella6f46c42017-10-26 15:26:16 -0400104 #[cfg(feature = "visit_mut")]
105 pub mod visit_mut;
Nika Layzell27726662017-10-24 23:16:35 -0400106
Nika Layzella6f46c42017-10-26 15:26:16 -0400107 #[cfg(feature = "fold")]
108 pub mod fold;
109}
110pub use gen::*;
gnzlbg9ae88d82017-01-26 20:45:17 +0100111
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700112////////////////////////////////////////////////////////////////////////////////
113
David Tolnay55337722016-09-11 12:58:56 -0700114#[cfg(feature = "parsing")]
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700115pub use synom::ParseError;
Ted Driggs054abbb2017-05-01 12:20:52 -0700116
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700117#[cfg(feature = "parsing")]
118use synom::{Synom, SynomBuffer};
Michael Layzell416724e2017-05-24 21:12:34 -0400119
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700120/// Parse tokens of source code into the chosen syn data type.
121///
122/// This is preferred over parsing a string because tokens are able to preserve
123/// information about where in the user's code they were originally written (the
124/// "span" of the token), possibly allowing the compiler to produce better error
125/// messages.
126///
127/// # Examples
128///
129/// ```rust,ignore
130/// extern crate proc_macro;
131/// use proc_macro::TokenStream;
132///
133/// extern crate syn;
134///
135/// #[macro_use]
136/// extern crate quote;
137///
138/// use syn::DeriveInput;
139///
140/// #[proc_macro_derive(MyMacro)]
141/// pub fn my_macro(input: TokenStream) -> TokenStream {
142/// // Parse the tokens into a syntax tree
143/// let ast: DeriveInput = syn::parse(input).unwrap();
144///
145/// // Build the output, possibly using quasi-quotation
146/// let expanded = quote! {
147/// /* ... */
148/// };
149///
150/// // Parse back to a token stream and return it
151/// expanded.parse().unwrap()
152/// }
153/// ```
154#[cfg(feature = "parsing")]
155pub fn parse<T>(tokens: proc_macro::TokenStream) -> Result<T, ParseError>
156 where T: Synom,
157{
158 _parse(tokens.into())
159}
160
161#[cfg(feature = "parsing")]
162fn _parse<T>(tokens: proc_macro2::TokenStream) -> Result<T, ParseError>
163 where T: Synom,
164{
165 let buf = SynomBuffer::new(tokens);
166 let result = T::parse(buf.begin());
167 let err = match result {
168 Ok((rest, t)) => {
169 if rest.eof() {
170 return Ok(t);
171 } else if rest == buf.begin() {
172 // parsed nothing
173 ParseError::new("failed to parse anything")
174 } else {
175 ParseError::new("failed to parse all tokens")
David Tolnay55337722016-09-11 12:58:56 -0700176 }
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700177 }
178 Err(err) => err,
179 };
180 match T::description() {
Alex Crichtonc1b76f52017-07-06 15:04:24 -0700181 Some(s) => Err(ParseError::new(format!("failed to parse {}: {}", s, err))),
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700182 None => Err(err),
183 }
184}
Alex Crichton954046c2017-05-30 21:49:42 -0700185
Nika Layzellcda7ebd2017-10-24 23:10:44 -0400186/// Parse a `quote::Tokens` of Rust code into the chosen syn data type.
187///
188/// # Examples
189///
190/// ```rust
191/// extern crate syn;
192/// #
193/// # #[macro_use]
Nika Layzellcda7ebd2017-10-24 23:10:44 -0400194/// # extern crate quote;
David Tolnay9174b972017-11-09 22:27:50 -0800195/// #
196/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
Nika Layzellcda7ebd2017-10-24 23:10:44 -0400197///
198/// use syn::Expr;
Nika Layzellcda7ebd2017-10-24 23:10:44 -0400199///
200/// fn run() -> Result<()> {
201/// let code = quote!(assert_eq!(u8::max_value(), 255));
202/// let expr = syn::parse_tokens::<Expr>(code)?;
203/// println!("{:#?}", expr);
204/// Ok(())
205/// }
206/// #
207/// # fn main() { run().unwrap() }
208/// ```
209#[cfg(feature = "parsing")]
210pub fn parse_tokens<T: Synom>(tokens: quote::Tokens) -> Result<T, ParseError> {
211 _parse(tokens.into())
212}
213
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700214/// Parse a string of Rust code into the chosen syn data type.
215///
216/// # Examples
217///
218/// ```rust
219/// extern crate syn;
220/// #
David Tolnay9174b972017-11-09 22:27:50 -0800221/// #
222/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700223///
224/// use syn::Expr;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700225///
226/// fn run() -> Result<()> {
227/// let code = "assert_eq!(u8::max_value(), 255)";
228/// let expr = syn::parse_str::<Expr>(code)?;
229/// println!("{:#?}", expr);
230/// Ok(())
231/// }
232/// #
233/// # fn main() { run().unwrap() }
234/// ```
235#[cfg(feature = "parsing")]
236pub fn parse_str<T: Synom>(s: &str) -> Result<T, ParseError> {
237 _parse(s.parse()?)
238}
Alex Crichton954046c2017-05-30 21:49:42 -0700239
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700240// FIXME the name parse_file makes it sound like you might pass in a path to a
241// file, rather than the content.
242/// Parse the content of a file of Rust code.
243///
244/// This is different from `syn::parse_str::<File>(content)` in two ways:
245///
246/// - It discards a leading byte order mark `\u{FEFF}` if the file has one.
247/// - It preserves the shebang line of the file, such as `#!/usr/bin/env rustx`.
248///
249/// If present, either of these would be an error using `from_str`.
250///
251/// # Examples
252///
253/// ```rust,no_run
254/// extern crate syn;
255/// #
David Tolnay9174b972017-11-09 22:27:50 -0800256/// #
257/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700258///
259/// use std::fs::File;
260/// use std::io::Read;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700261///
262/// fn run() -> Result<()> {
263/// let mut file = File::open("path/to/code.rs")?;
264/// let mut content = String::new();
265/// file.read_to_string(&mut content)?;
266///
267/// let ast = syn::parse_file(&content)?;
268/// if let Some(shebang) = ast.shebang {
269/// println!("{}", shebang);
270/// }
271/// println!("{} items", ast.items.len());
272///
273/// Ok(())
274/// }
275/// #
276/// # fn main() { run().unwrap() }
277/// ```
278#[cfg(all(feature = "parsing", feature = "full"))]
279pub fn parse_file(mut content: &str) -> Result<File, ParseError> {
280 // Strip the BOM if it is present
281 const BOM: &'static str = "\u{feff}";
282 if content.starts_with(BOM) {
283 content = &content[BOM.len()..];
David Tolnay35161ff2016-09-03 11:33:15 -0700284 }
Michael Layzell5e107ff2017-01-24 19:58:39 -0500285
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700286 let mut shebang = None;
287 if content.starts_with("#!") && !content.starts_with("#![") {
288 if let Some(idx) = content.find('\n') {
289 shebang = Some(content[..idx].to_string());
290 content = &content[idx..];
291 } else {
292 shebang = Some(content.to_string());
293 content = "";
294 }
Alex Crichton954046c2017-05-30 21:49:42 -0700295 }
David Tolnay0a8972b2017-02-27 02:10:01 -0800296
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700297 let mut file: File = parse_str(content)?;
298 file.shebang = shebang;
299 Ok(file)
Michael Layzell5e107ff2017-01-24 19:58:39 -0500300}
Alex Crichton259ee532017-07-14 06:51:02 -0700301
302#[cfg(feature = "printing")]
303struct TokensOrDefault<'a, T: 'a>(&'a Option<T>);
304
305#[cfg(feature = "printing")]
306impl<'a, T> quote::ToTokens for TokensOrDefault<'a, T>
307 where T: quote::ToTokens + Default,
308{
309 fn to_tokens(&self, tokens: &mut quote::Tokens) {
310 match *self.0 {
311 Some(ref t) => t.to_tokens(tokens),
312 None => T::default().to_tokens(tokens),
313 }
314 }
315}