blob: 92cb9b2957a247aadb622b0b85464ea22bd5ca12 [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
David Tolnay87d0b442016-09-04 11:52:12 -07009#[cfg(feature = "printing")]
10extern 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,
Michael Layzell734adb42017-06-07 16:58:31 -040034 ExprGroup};
35
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;
David Tolnayb8d8ef52016-10-29 14:30:08 -070086pub use ty::{Abi, AngleBracketedParameterData, BareFnArg, BareFnTy, FunctionRetTy, MutTy,
87 Mutability, ParenthesizedParameterData, Path, PathParameters, PathSegment,
Alex Crichton62a0a592017-05-22 13:58:53 -070088 PolyTraitRef, QSelf, Ty, TypeBinding, Unsafety, TySlice, TyArray,
89 TyPtr, TyRptr, TyBareFn, TyNever, TyTup, TyPath, TyTraitObject,
Michael Layzell93c36282017-06-04 20:43:14 -040090 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
David Tolnay55337722016-09-11 12:58:56 -070098#[cfg(feature = "visit")]
99pub mod visit;
100
gnzlbg9ae88d82017-01-26 20:45:17 +0100101#[cfg(feature = "fold")]
102pub mod fold;
103
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700104////////////////////////////////////////////////////////////////////////////////
105
David Tolnay55337722016-09-11 12:58:56 -0700106#[cfg(feature = "parsing")]
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700107pub use synom::ParseError;
Ted Driggs054abbb2017-05-01 12:20:52 -0700108
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700109#[cfg(feature = "parsing")]
110use synom::{Synom, SynomBuffer};
Michael Layzell416724e2017-05-24 21:12:34 -0400111
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700112/// Parse tokens of source code into the chosen syn data type.
113///
114/// This is preferred over parsing a string because tokens are able to preserve
115/// information about where in the user's code they were originally written (the
116/// "span" of the token), possibly allowing the compiler to produce better error
117/// messages.
118///
119/// # Examples
120///
121/// ```rust,ignore
122/// extern crate proc_macro;
123/// use proc_macro::TokenStream;
124///
125/// extern crate syn;
126///
127/// #[macro_use]
128/// extern crate quote;
129///
130/// use syn::DeriveInput;
131///
132/// #[proc_macro_derive(MyMacro)]
133/// pub fn my_macro(input: TokenStream) -> TokenStream {
134/// // Parse the tokens into a syntax tree
135/// let ast: DeriveInput = syn::parse(input).unwrap();
136///
137/// // Build the output, possibly using quasi-quotation
138/// let expanded = quote! {
139/// /* ... */
140/// };
141///
142/// // Parse back to a token stream and return it
143/// expanded.parse().unwrap()
144/// }
145/// ```
146#[cfg(feature = "parsing")]
147pub fn parse<T>(tokens: proc_macro::TokenStream) -> Result<T, ParseError>
148 where T: Synom,
149{
150 _parse(tokens.into())
151}
152
153#[cfg(feature = "parsing")]
154fn _parse<T>(tokens: proc_macro2::TokenStream) -> Result<T, ParseError>
155 where T: Synom,
156{
157 let buf = SynomBuffer::new(tokens);
158 let result = T::parse(buf.begin());
159 let err = match result {
160 Ok((rest, t)) => {
161 if rest.eof() {
162 return Ok(t);
163 } else if rest == buf.begin() {
164 // parsed nothing
165 ParseError::new("failed to parse anything")
166 } else {
167 ParseError::new("failed to parse all tokens")
David Tolnay55337722016-09-11 12:58:56 -0700168 }
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700169 }
170 Err(err) => err,
171 };
172 match T::description() {
173 Some(s) => Err(ParseError::new(format!("parsing {}: {}", s, err))),
174 None => Err(err),
175 }
176}
Alex Crichton954046c2017-05-30 21:49:42 -0700177
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700178/// Parse a string of Rust code into the chosen syn data type.
179///
180/// # Examples
181///
182/// ```rust
183/// extern crate syn;
184/// #
185/// # #[macro_use]
186/// # extern crate error_chain;
187///
188/// use syn::Expr;
189/// #
190/// # error_chain! {
191/// # foreign_links {
192/// # Syn(syn::ParseError);
193/// # }
194/// # }
195///
196/// fn run() -> Result<()> {
197/// let code = "assert_eq!(u8::max_value(), 255)";
198/// let expr = syn::parse_str::<Expr>(code)?;
199/// println!("{:#?}", expr);
200/// Ok(())
201/// }
202/// #
203/// # fn main() { run().unwrap() }
204/// ```
205#[cfg(feature = "parsing")]
206pub fn parse_str<T: Synom>(s: &str) -> Result<T, ParseError> {
207 _parse(s.parse()?)
208}
Alex Crichton954046c2017-05-30 21:49:42 -0700209
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700210// FIXME the name parse_file makes it sound like you might pass in a path to a
211// file, rather than the content.
212/// Parse the content of a file of Rust code.
213///
214/// This is different from `syn::parse_str::<File>(content)` in two ways:
215///
216/// - It discards a leading byte order mark `\u{FEFF}` if the file has one.
217/// - It preserves the shebang line of the file, such as `#!/usr/bin/env rustx`.
218///
219/// If present, either of these would be an error using `from_str`.
220///
221/// # Examples
222///
223/// ```rust,no_run
224/// extern crate syn;
225/// #
226/// # #[macro_use]
227/// # extern crate error_chain;
228///
229/// use std::fs::File;
230/// use std::io::Read;
231/// #
232/// # error_chain! {
233/// # foreign_links {
234/// # Io(std::io::Error);
235/// # Syn(syn::ParseError);
236/// # }
237/// # }
238///
239/// fn run() -> Result<()> {
240/// let mut file = File::open("path/to/code.rs")?;
241/// let mut content = String::new();
242/// file.read_to_string(&mut content)?;
243///
244/// let ast = syn::parse_file(&content)?;
245/// if let Some(shebang) = ast.shebang {
246/// println!("{}", shebang);
247/// }
248/// println!("{} items", ast.items.len());
249///
250/// Ok(())
251/// }
252/// #
253/// # fn main() { run().unwrap() }
254/// ```
255#[cfg(all(feature = "parsing", feature = "full"))]
256pub fn parse_file(mut content: &str) -> Result<File, ParseError> {
257 // Strip the BOM if it is present
258 const BOM: &'static str = "\u{feff}";
259 if content.starts_with(BOM) {
260 content = &content[BOM.len()..];
David Tolnay35161ff2016-09-03 11:33:15 -0700261 }
Michael Layzell5e107ff2017-01-24 19:58:39 -0500262
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700263 let mut shebang = None;
264 if content.starts_with("#!") && !content.starts_with("#![") {
265 if let Some(idx) = content.find('\n') {
266 shebang = Some(content[..idx].to_string());
267 content = &content[idx..];
268 } else {
269 shebang = Some(content.to_string());
270 content = "";
271 }
Alex Crichton954046c2017-05-30 21:49:42 -0700272 }
David Tolnay0a8972b2017-02-27 02:10:01 -0800273
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700274 let mut file: File = parse_str(content)?;
275 file.shebang = shebang;
276 Ok(file)
Michael Layzell5e107ff2017-01-24 19:58:39 -0500277}