blob: c30515de0bb8f79073cfa2534112a44b682f1bc2 [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
Alex Crichtonccbb45d2017-05-23 10:58:24 -070012#[cfg_attr(feature = "parsing", 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 Layzell42bf7e32017-10-24 23:10:16 -040034 ExprGroup, ExprYield};
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 Tolnay63e3dee2017-06-03 20:13:17 -070043pub use generics::{Generics, LifetimeDef, TraitBoundModifier, TyParam, TyParamBound,
David Tolnayfa23f572017-01-23 00:19:11 -080044 WhereBoundPredicate, WhereClause, WhereEqPredicate, WherePredicate,
Alex Crichtonccbb45d2017-05-23 10:58:24 -070045 WhereRegionPredicate, BoundLifetimes};
David Tolnaye7678922016-10-13 20:44:03 -070046#[cfg(feature = "printing")]
David Tolnayc879a502017-01-25 15:51:32 -080047pub use generics::{ImplGenerics, Turbofish, TyGenerics};
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")]
Alex Crichton62a0a592017-05-22 13:58:53 -070055pub use item::{Constness, Defaultness, FnArg, FnDecl, ForeignItemKind, ForeignItem, ItemForeignMod,
David Tolnayc1fea502016-10-30 17:54:02 -070056 ImplItem, ImplItemKind, ImplPolarity, Item, ItemKind, MethodSig, PathListItem,
Alex Crichton62a0a592017-05-22 13:58:53 -070057 TraitItem, TraitItemKind, ViewPath, ItemExternCrate, ItemUse,
58 ItemStatic, ItemConst, ItemFn, ItemMod, ItemTy, ItemEnum,
59 ItemStruct, ItemUnion, ItemTrait, ItemDefaultImpl, ItemImpl,
60 PathSimple, PathGlob, PathList, ForeignItemFn, ForeignItemStatic,
61 TraitItemConst, TraitItemMethod, TraitItemType,
62 ImplItemConst, ImplItemMethod, ImplItemType, ArgSelfRef,
63 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;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070077pub use mac::{Mac, 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 Layzell42bf7e32017-10-24 23:10:16 -040086pub use ty::{Abi, AbiKind, AngleBracketedParameterData, BareFnArg, BareFnArgName, BareFnTy,
87 FunctionRetTy, MutTy, Mutability, ParenthesizedParameterData, Path,
88 PathParameters, PathSegment, PolyTraitRef, QSelf, Ty, TypeBinding, Unsafety,
89 TySlice, TyArray, TyPtr, TyRptr, TyBareFn, TyNever, TyTup, TyPath,
90 TyTraitObject, TyImplTrait, TyParen, TyInfer, TyGroup};
Alex Crichtonccbb45d2017-05-23 10:58:24 -070091#[cfg(feature = "printing")]
92pub use ty::PathTokens;
93
Alex Crichton954046c2017-05-30 21:49:42 -070094pub use synom::span::Span;
95pub use synom::tokens;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070096pub use synom::delimited;
David Tolnay35161ff2016-09-03 11:33:15 -070097
Nika Layzella6f46c42017-10-26 15:26:16 -040098mod gen {
99 #[cfg(feature = "visit")]
100 pub mod visit;
David Tolnay55337722016-09-11 12:58:56 -0700101
Nika Layzella6f46c42017-10-26 15:26:16 -0400102 #[cfg(feature = "visit_mut")]
103 pub mod visit_mut;
Nika Layzell27726662017-10-24 23:16:35 -0400104
Nika Layzella6f46c42017-10-26 15:26:16 -0400105 #[cfg(feature = "fold")]
106 pub mod fold;
107}
108pub use gen::*;
gnzlbg9ae88d82017-01-26 20:45:17 +0100109
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700110////////////////////////////////////////////////////////////////////////////////
111
David Tolnay55337722016-09-11 12:58:56 -0700112#[cfg(feature = "parsing")]
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700113pub use synom::ParseError;
Ted Driggs054abbb2017-05-01 12:20:52 -0700114
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700115#[cfg(feature = "parsing")]
116use synom::{Synom, SynomBuffer};
Michael Layzell416724e2017-05-24 21:12:34 -0400117
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700118/// Parse tokens of source code into the chosen syn data type.
119///
120/// This is preferred over parsing a string because tokens are able to preserve
121/// information about where in the user's code they were originally written (the
122/// "span" of the token), possibly allowing the compiler to produce better error
123/// messages.
124///
125/// # Examples
126///
127/// ```rust,ignore
128/// extern crate proc_macro;
129/// use proc_macro::TokenStream;
130///
131/// extern crate syn;
132///
133/// #[macro_use]
134/// extern crate quote;
135///
136/// use syn::DeriveInput;
137///
138/// #[proc_macro_derive(MyMacro)]
139/// pub fn my_macro(input: TokenStream) -> TokenStream {
140/// // Parse the tokens into a syntax tree
141/// let ast: DeriveInput = syn::parse(input).unwrap();
142///
143/// // Build the output, possibly using quasi-quotation
144/// let expanded = quote! {
145/// /* ... */
146/// };
147///
148/// // Parse back to a token stream and return it
149/// expanded.parse().unwrap()
150/// }
151/// ```
152#[cfg(feature = "parsing")]
153pub fn parse<T>(tokens: proc_macro::TokenStream) -> Result<T, ParseError>
154 where T: Synom,
155{
156 _parse(tokens.into())
157}
158
159#[cfg(feature = "parsing")]
160fn _parse<T>(tokens: proc_macro2::TokenStream) -> Result<T, ParseError>
161 where T: Synom,
162{
163 let buf = SynomBuffer::new(tokens);
164 let result = T::parse(buf.begin());
165 let err = match result {
166 Ok((rest, t)) => {
167 if rest.eof() {
168 return Ok(t);
169 } else if rest == buf.begin() {
170 // parsed nothing
171 ParseError::new("failed to parse anything")
172 } else {
173 ParseError::new("failed to parse all tokens")
David Tolnay55337722016-09-11 12:58:56 -0700174 }
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700175 }
176 Err(err) => err,
177 };
178 match T::description() {
Alex Crichtonc1b76f52017-07-06 15:04:24 -0700179 Some(s) => Err(ParseError::new(format!("failed to parse {}: {}", s, err))),
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700180 None => Err(err),
181 }
182}
Alex Crichton954046c2017-05-30 21:49:42 -0700183
Nika Layzellcda7ebd2017-10-24 23:10:44 -0400184/// Parse a `quote::Tokens` of Rust code into the chosen syn data type.
185///
186/// # Examples
187///
188/// ```rust
189/// extern crate syn;
190/// #
191/// # #[macro_use]
192/// # extern crate error_chain;
193/// # #[macro_use]
194/// # extern crate quote;
195///
196/// use syn::Expr;
197/// #
198/// # error_chain! {
199/// # foreign_links {
200/// # Syn(syn::ParseError);
201/// # }
202/// # }
203///
204/// fn run() -> Result<()> {
205/// let code = quote!(assert_eq!(u8::max_value(), 255));
206/// let expr = syn::parse_tokens::<Expr>(code)?;
207/// println!("{:#?}", expr);
208/// Ok(())
209/// }
210/// #
211/// # fn main() { run().unwrap() }
212/// ```
213#[cfg(feature = "parsing")]
214pub fn parse_tokens<T: Synom>(tokens: quote::Tokens) -> Result<T, ParseError> {
215 _parse(tokens.into())
216}
217
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700218/// Parse a string of Rust code into the chosen syn data type.
219///
220/// # Examples
221///
222/// ```rust
223/// extern crate syn;
224/// #
225/// # #[macro_use]
226/// # extern crate error_chain;
227///
228/// use syn::Expr;
229/// #
230/// # error_chain! {
231/// # foreign_links {
232/// # Syn(syn::ParseError);
233/// # }
234/// # }
235///
236/// fn run() -> Result<()> {
237/// let code = "assert_eq!(u8::max_value(), 255)";
238/// let expr = syn::parse_str::<Expr>(code)?;
239/// println!("{:#?}", expr);
240/// Ok(())
241/// }
242/// #
243/// # fn main() { run().unwrap() }
244/// ```
245#[cfg(feature = "parsing")]
246pub fn parse_str<T: Synom>(s: &str) -> Result<T, ParseError> {
247 _parse(s.parse()?)
248}
Alex Crichton954046c2017-05-30 21:49:42 -0700249
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700250// FIXME the name parse_file makes it sound like you might pass in a path to a
251// file, rather than the content.
252/// Parse the content of a file of Rust code.
253///
254/// This is different from `syn::parse_str::<File>(content)` in two ways:
255///
256/// - It discards a leading byte order mark `\u{FEFF}` if the file has one.
257/// - It preserves the shebang line of the file, such as `#!/usr/bin/env rustx`.
258///
259/// If present, either of these would be an error using `from_str`.
260///
261/// # Examples
262///
263/// ```rust,no_run
264/// extern crate syn;
265/// #
266/// # #[macro_use]
267/// # extern crate error_chain;
268///
269/// use std::fs::File;
270/// use std::io::Read;
271/// #
272/// # error_chain! {
273/// # foreign_links {
274/// # Io(std::io::Error);
275/// # Syn(syn::ParseError);
276/// # }
277/// # }
278///
279/// fn run() -> Result<()> {
280/// let mut file = File::open("path/to/code.rs")?;
281/// let mut content = String::new();
282/// file.read_to_string(&mut content)?;
283///
284/// let ast = syn::parse_file(&content)?;
285/// if let Some(shebang) = ast.shebang {
286/// println!("{}", shebang);
287/// }
288/// println!("{} items", ast.items.len());
289///
290/// Ok(())
291/// }
292/// #
293/// # fn main() { run().unwrap() }
294/// ```
295#[cfg(all(feature = "parsing", feature = "full"))]
296pub fn parse_file(mut content: &str) -> Result<File, ParseError> {
297 // Strip the BOM if it is present
298 const BOM: &'static str = "\u{feff}";
299 if content.starts_with(BOM) {
300 content = &content[BOM.len()..];
David Tolnay35161ff2016-09-03 11:33:15 -0700301 }
Michael Layzell5e107ff2017-01-24 19:58:39 -0500302
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700303 let mut shebang = None;
304 if content.starts_with("#!") && !content.starts_with("#![") {
305 if let Some(idx) = content.find('\n') {
306 shebang = Some(content[..idx].to_string());
307 content = &content[idx..];
308 } else {
309 shebang = Some(content.to_string());
310 content = "";
311 }
Alex Crichton954046c2017-05-30 21:49:42 -0700312 }
David Tolnay0a8972b2017-02-27 02:10:01 -0800313
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700314 let mut file: File = parse_str(content)?;
315 file.shebang = shebang;
316 Ok(file)
Michael Layzell5e107ff2017-01-24 19:58:39 -0500317}
Alex Crichton259ee532017-07-14 06:51:02 -0700318
319#[cfg(feature = "printing")]
320struct TokensOrDefault<'a, T: 'a>(&'a Option<T>);
321
322#[cfg(feature = "printing")]
323impl<'a, T> quote::ToTokens for TokensOrDefault<'a, T>
324 where T: quote::ToTokens + Default,
325{
326 fn to_tokens(&self, tokens: &mut quote::Tokens) {
327 match *self.0 {
328 Some(ref t) => t.to_tokens(tokens),
329 None => T::default().to_tokens(tokens),
330 }
331 }
332}