blob: 7d7c0f80bfe11c311dd250df8924855222c865eb [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
David Tolnay1cf80912017-12-31 18:35:12 -050010#[cfg(feature = "printing")]
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#[macro_use]
David Tolnay32954ef2017-12-26 22:43:16 -050022pub mod token;
David Tolnayc5ab8c62017-12-26 16:43:39 -050023
David Tolnayb79ee962016-09-04 09:39:20 -070024mod attr;
David Tolnay51382052017-12-27 13:46:21 -050025pub use attr::{AttrStyle, Attribute, MetaItem, MetaItemList, MetaNameValue, NestedMetaItem};
David Tolnay35161ff2016-09-03 11:33:15 -070026
David Tolnayf38cdf62016-09-23 19:07:09 -070027mod data;
David Tolnaye3d41b72017-12-31 15:24:00 -050028pub use data::{Field, Fields, FieldsNamed, FieldsUnnamed, Variant, VisCrate, VisPublic, VisRestricted, Visibility};
David Tolnayf38cdf62016-09-23 19:07:09 -070029
David Tolnayf4bbbd92016-09-23 14:41:55 -070030mod expr;
David Tolnay51382052017-12-27 13:46:21 -050031pub use expr::{Expr, ExprAddrOf, ExprArray, ExprAssign, ExprAssignOp, ExprBinary, ExprBlock,
32 ExprBox, ExprBreak, ExprCall, ExprCast, ExprCatch, ExprClosure, ExprContinue,
33 ExprField, ExprForLoop, ExprGroup, ExprIf, ExprIfLet, ExprInPlace, ExprIndex,
David Tolnay8c91b882017-12-28 23:04:32 -050034 ExprLit, ExprLoop, ExprMacro, ExprMatch, ExprMethodCall, ExprParen, ExprPath, ExprRange,
David Tolnayc246cd32017-12-28 23:14:32 -050035 ExprRepeat, ExprReturn, ExprStruct, ExprTry, ExprTuple, ExprType,
David Tolnay2ae520a2017-12-29 11:19:50 -050036 ExprUnary, ExprUnsafe, ExprVerbatim, ExprWhile, ExprWhileLet, ExprYield, Index, Member};
Michael Layzell734adb42017-06-07 16:58:31 -040037
38#[cfg(feature = "full")]
David Tolnaybcd498f2017-12-29 12:02:33 -050039pub use expr::{Arm, Block, FieldPat, FieldValue, GenericMethodArgument, Label, Local,
David Tolnay323279a2017-12-29 11:26:32 -050040 MethodTurbofish, Pat, PatBox, PatIdent, PatLit, PatMacro, PatPath, PatRange, PatRef, PatSlice,
David Tolnay2ae520a2017-12-29 11:19:50 -050041 PatStruct, PatTuple, PatTupleStruct, PatVerbatim, PatWild, RangeLimits, Stmt};
David Tolnayf4bbbd92016-09-23 14:41:55 -070042
David Tolnayb79ee962016-09-04 09:39:20 -070043mod generics;
David Tolnay51382052017-12-27 13:46:21 -050044pub use generics::{BoundLifetimes, ConstParam, GenericParam, Generics, LifetimeDef,
David Tolnay40fb8ce2018-01-02 10:53:46 -080045 PredicateEq, PredicateLifetime, PredicateType, TraitBound, TraitBoundModifier,
David Tolnayd4add852018-01-01 20:13:24 -080046 TypeParam, TypeParamBound, WhereClause, WherePredicate};
David Tolnaye7678922016-10-13 20:44:03 -070047#[cfg(feature = "printing")]
David Tolnayfd6bf5c2017-11-12 09:41:14 -080048pub use generics::{ImplGenerics, Turbofish, TypeGenerics};
David Tolnay35161ff2016-09-03 11:33:15 -070049
David Tolnay55337722016-09-11 12:58:56 -070050mod ident;
David Tolnaydaaf7742016-10-03 11:11:43 -070051pub use ident::Ident;
David Tolnay55337722016-09-11 12:58:56 -070052
David Tolnayf38cdf62016-09-23 19:07:09 -070053#[cfg(feature = "full")]
David Tolnayb79ee962016-09-04 09:39:20 -070054mod item;
David Tolnayf38cdf62016-09-23 19:07:09 -070055#[cfg(feature = "full")]
David Tolnay360a6342017-12-29 02:22:11 -050056pub use item::{ArgCaptured, ArgSelf, ArgSelfRef, FnArg, FnDecl,
David Tolnay2ae520a2017-12-29 11:19:50 -050057 ForeignItem, ForeignItemFn, ForeignItemStatic, ForeignItemType, ForeignItemVerbatim, ImplItem,
58 ImplItemConst, ImplItemMacro, ImplItemMethod, ImplItemType, ImplItemVerbatim, Item,
David Tolnay03342952017-12-29 11:52:00 -050059 ItemConst, ItemEnum, ItemExternCrate, ItemFn, ItemForeignMod,
David Tolnay51382052017-12-27 13:46:21 -050060 ItemImpl, ItemMacro, ItemMacro2, ItemMod, ItemStatic, ItemStruct, ItemTrait,
David Tolnay2ae520a2017-12-29 11:19:50 -050061 ItemType, ItemUnion, ItemUse, ItemVerbatim, MethodSig, TraitItem, TraitItemConst, TraitItemMacro,
62 TraitItemMethod, TraitItemType, TraitItemVerbatim, UseGlob, UseList, UsePath, UseTree};
David Tolnay35161ff2016-09-03 11:33:15 -070063
David Tolnay631cb8c2016-11-10 17:16:41 -080064#[cfg(feature = "full")]
David Tolnayc7a5d3d2017-06-04 12:11:05 -070065mod file;
David Tolnay631cb8c2016-11-10 17:16:41 -080066#[cfg(feature = "full")]
David Tolnayc7a5d3d2017-06-04 12:11:05 -070067pub use file::File;
David Tolnay631cb8c2016-11-10 17:16:41 -080068
David Tolnay63e3dee2017-06-03 20:13:17 -070069mod lifetime;
70pub use lifetime::Lifetime;
71
David Tolnayf4bbbd92016-09-23 14:41:55 -070072mod lit;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070073pub use lit::{Lit, LitKind};
David Tolnayf4bbbd92016-09-23 14:41:55 -070074
David Tolnayf4bbbd92016-09-23 14:41:55 -070075mod mac;
David Tolnayab919512017-12-30 23:31:51 -050076pub use mac::{Macro, MacroDelimiter};
David Tolnayf4bbbd92016-09-23 14:41:55 -070077
David Tolnay0e837402016-12-22 17:25:55 -050078mod derive;
David Tolnaye3d41b72017-12-31 15:24:00 -050079pub use derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput};
David Tolnayf38cdf62016-09-23 19:07:09 -070080
David Tolnay3cb23a92016-10-07 23:02:21 -070081mod op;
82pub use op::{BinOp, UnOp};
83
David Tolnayb79ee962016-09-04 09:39:20 -070084mod ty;
David Tolnayd5125762017-12-29 02:42:17 -050085pub use ty::{Abi, AngleBracketedGenericArguments, BareFnArg, BareFnArgName,
David Tolnay506e43a2017-12-29 11:34:36 -050086 Binding, GenericArgument, ParenthesizedGenericArguments, Path,
David Tolnay40fb8ce2018-01-02 10:53:46 -080087 PathArguments, PathSegment, QSelf, ReturnType, Type, TypeArray,
David Tolnay506e43a2017-12-29 11:34:36 -050088 TypeBareFn, TypeGroup, TypeImplTrait, TypeInfer, TypeMacro, TypeNever, TypeParen,
David Tolnay2ae520a2017-12-29 11:19:50 -050089 TypePath, TypePtr, TypeReference, TypeSlice, TypeTraitObject, TypeTuple, TypeVerbatim};
Alex Crichtonccbb45d2017-05-23 10:58:24 -070090#[cfg(feature = "printing")]
91pub use ty::PathTokens;
92
David Tolnay1b752fb2017-12-26 21:41:39 -050093#[cfg(feature = "parsing")]
David Tolnayc5ab8c62017-12-26 16:43:39 -050094mod cursor;
David Tolnay1b752fb2017-12-26 21:41:39 -050095#[cfg(feature = "parsing")]
David Tolnayc5ab8c62017-12-26 16:43:39 -050096pub mod synom;
David Tolnayf2cfd722017-12-31 18:02:51 -050097pub mod punctuated;
David Tolnaye0824032017-12-27 15:25:56 -050098#[cfg(feature = "parsing")]
99mod tt;
David Tolnayc5ab8c62017-12-26 16:43:39 -0500100
David Tolnay4d942b42018-01-02 22:14:04 -0800101#[cfg(all(feature = "parsing", feature = "printing"))]
David Tolnayf790b612017-12-31 18:46:57 -0500102pub mod spanned;
103
Nika Layzella6f46c42017-10-26 15:26:16 -0400104mod gen {
105 #[cfg(feature = "visit")]
106 pub mod visit;
David Tolnay55337722016-09-11 12:58:56 -0700107
Nika Layzella6f46c42017-10-26 15:26:16 -0400108 #[cfg(feature = "visit_mut")]
109 pub mod visit_mut;
Nika Layzell27726662017-10-24 23:16:35 -0400110
Nika Layzella6f46c42017-10-26 15:26:16 -0400111 #[cfg(feature = "fold")]
112 pub mod fold;
David Tolnayf60f4262017-12-28 19:17:58 -0500113
114 #[path = "../gen_helper.rs"]
115 mod helper;
Nika Layzella6f46c42017-10-26 15:26:16 -0400116}
117pub use gen::*;
gnzlbg9ae88d82017-01-26 20:45:17 +0100118
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700119////////////////////////////////////////////////////////////////////////////////
120
David Tolnay55337722016-09-11 12:58:56 -0700121#[cfg(feature = "parsing")]
David Tolnayc5ab8c62017-12-26 16:43:39 -0500122use synom::Synom;
123#[cfg(feature = "parsing")]
124use cursor::SynomBuffer;
Ted Driggs054abbb2017-05-01 12:20:52 -0700125
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700126#[cfg(feature = "parsing")]
David Tolnayc5ab8c62017-12-26 16:43:39 -0500127mod error;
128#[cfg(feature = "parsing")]
David Tolnay203557a2017-12-27 23:59:33 -0500129use error::ParseError;
David Tolnayc5ab8c62017-12-26 16:43:39 -0500130
131// Not public API.
David Tolnay1b752fb2017-12-26 21:41:39 -0500132#[cfg(feature = "parsing")]
David Tolnayc5ab8c62017-12-26 16:43:39 -0500133#[doc(hidden)]
134pub use error::parse_error;
Michael Layzell416724e2017-05-24 21:12:34 -0400135
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700136/// Parse tokens of source code into the chosen syn data type.
137///
138/// This is preferred over parsing a string because tokens are able to preserve
139/// information about where in the user's code they were originally written (the
140/// "span" of the token), possibly allowing the compiler to produce better error
141/// messages.
142///
143/// # Examples
144///
David Tolnaybcf26022017-12-25 22:10:52 -0500145/// ```rust
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700146/// extern crate proc_macro;
147/// use proc_macro::TokenStream;
148///
149/// extern crate syn;
150///
151/// #[macro_use]
152/// extern crate quote;
153///
154/// use syn::DeriveInput;
155///
David Tolnaybcf26022017-12-25 22:10:52 -0500156/// # const IGNORE_TOKENS: &str = stringify! {
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700157/// #[proc_macro_derive(MyMacro)]
David Tolnaybcf26022017-12-25 22:10:52 -0500158/// # };
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700159/// pub fn my_macro(input: TokenStream) -> TokenStream {
160/// // Parse the tokens into a syntax tree
161/// let ast: DeriveInput = syn::parse(input).unwrap();
162///
163/// // Build the output, possibly using quasi-quotation
164/// let expanded = quote! {
165/// /* ... */
166/// };
167///
David Tolnaybcf26022017-12-25 22:10:52 -0500168/// // Convert into a token stream and return it
169/// expanded.into()
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700170/// }
David Tolnaybcf26022017-12-25 22:10:52 -0500171/// #
172/// # fn main() {}
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700173/// ```
174#[cfg(feature = "parsing")]
175pub fn parse<T>(tokens: proc_macro::TokenStream) -> Result<T, ParseError>
David Tolnay51382052017-12-27 13:46:21 -0500176where
177 T: Synom,
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700178{
179 _parse(tokens.into())
180}
181
182#[cfg(feature = "parsing")]
183fn _parse<T>(tokens: proc_macro2::TokenStream) -> Result<T, ParseError>
David Tolnay51382052017-12-27 13:46:21 -0500184where
185 T: Synom,
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700186{
187 let buf = SynomBuffer::new(tokens);
188 let result = T::parse(buf.begin());
189 let err = match result {
David Tolnayf4aa6b42017-12-31 16:40:33 -0500190 Ok((t, rest)) => {
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700191 if rest.eof() {
192 return Ok(t);
193 } else if rest == buf.begin() {
194 // parsed nothing
195 ParseError::new("failed to parse anything")
196 } else {
197 ParseError::new("failed to parse all tokens")
David Tolnay55337722016-09-11 12:58:56 -0700198 }
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700199 }
200 Err(err) => err,
201 };
202 match T::description() {
Alex Crichtonc1b76f52017-07-06 15:04:24 -0700203 Some(s) => Err(ParseError::new(format!("failed to parse {}: {}", s, err))),
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700204 None => Err(err),
205 }
206}
Alex Crichton954046c2017-05-30 21:49:42 -0700207
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700208/// Parse a string of Rust code into the chosen syn data type.
209///
210/// # Examples
211///
212/// ```rust
213/// extern crate syn;
214/// #
David Tolnay9174b972017-11-09 22:27:50 -0800215/// #
216/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700217///
218/// use syn::Expr;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700219///
220/// fn run() -> Result<()> {
221/// let code = "assert_eq!(u8::max_value(), 255)";
222/// let expr = syn::parse_str::<Expr>(code)?;
223/// println!("{:#?}", expr);
224/// Ok(())
225/// }
226/// #
227/// # fn main() { run().unwrap() }
228/// ```
229#[cfg(feature = "parsing")]
230pub fn parse_str<T: Synom>(s: &str) -> Result<T, ParseError> {
David Tolnayffb1f4d2017-12-28 00:07:59 -0500231 match s.parse() {
232 Ok(tts) => _parse(tts),
233 Err(_) => Err(ParseError::new("error while lexing input string")),
234 }
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700235}
Alex Crichton954046c2017-05-30 21:49:42 -0700236
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700237// FIXME the name parse_file makes it sound like you might pass in a path to a
238// file, rather than the content.
239/// Parse the content of a file of Rust code.
240///
241/// This is different from `syn::parse_str::<File>(content)` in two ways:
242///
243/// - It discards a leading byte order mark `\u{FEFF}` if the file has one.
244/// - It preserves the shebang line of the file, such as `#!/usr/bin/env rustx`.
245///
246/// If present, either of these would be an error using `from_str`.
247///
248/// # Examples
249///
250/// ```rust,no_run
251/// extern crate syn;
252/// #
David Tolnay9174b972017-11-09 22:27:50 -0800253/// #
254/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700255///
256/// use std::fs::File;
257/// use std::io::Read;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700258///
259/// fn run() -> Result<()> {
260/// let mut file = File::open("path/to/code.rs")?;
261/// let mut content = String::new();
262/// file.read_to_string(&mut content)?;
263///
264/// let ast = syn::parse_file(&content)?;
265/// if let Some(shebang) = ast.shebang {
266/// println!("{}", shebang);
267/// }
268/// println!("{} items", ast.items.len());
269///
270/// Ok(())
271/// }
272/// #
273/// # fn main() { run().unwrap() }
274/// ```
275#[cfg(all(feature = "parsing", feature = "full"))]
276pub fn parse_file(mut content: &str) -> Result<File, ParseError> {
277 // Strip the BOM if it is present
278 const BOM: &'static str = "\u{feff}";
279 if content.starts_with(BOM) {
280 content = &content[BOM.len()..];
David Tolnay35161ff2016-09-03 11:33:15 -0700281 }
Michael Layzell5e107ff2017-01-24 19:58:39 -0500282
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700283 let mut shebang = None;
284 if content.starts_with("#!") && !content.starts_with("#![") {
285 if let Some(idx) = content.find('\n') {
286 shebang = Some(content[..idx].to_string());
287 content = &content[idx..];
288 } else {
289 shebang = Some(content.to_string());
290 content = "";
291 }
Alex Crichton954046c2017-05-30 21:49:42 -0700292 }
David Tolnay0a8972b2017-02-27 02:10:01 -0800293
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700294 let mut file: File = parse_str(content)?;
295 file.shebang = shebang;
296 Ok(file)
Michael Layzell5e107ff2017-01-24 19:58:39 -0500297}
Alex Crichton259ee532017-07-14 06:51:02 -0700298
David Tolnay01cc0202018-01-02 11:13:07 -0800299#[cfg(all(feature = "parsing", feature = "printing"))]
300#[macro_export]
301macro_rules! parse_quote {
302 ($($tt:tt)*) => {
303 ::std::result::Result::unwrap(
304 $crate::parse(
305 ::std::convert::Into::into(
306 quote!($($tt)*))))
307 };
308}
309
Alex Crichton259ee532017-07-14 06:51:02 -0700310#[cfg(feature = "printing")]
311struct TokensOrDefault<'a, T: 'a>(&'a Option<T>);
312
313#[cfg(feature = "printing")]
314impl<'a, T> quote::ToTokens for TokensOrDefault<'a, T>
David Tolnay51382052017-12-27 13:46:21 -0500315where
316 T: quote::ToTokens + Default,
Alex Crichton259ee532017-07-14 06:51:02 -0700317{
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}