blob: 3f95a1768d83bbc7061564dfc39e176cbba5975c [file] [log] [blame]
David Tolnay55535012018-01-05 16:39:23 -08001// Copyright 2018 Syn Developers
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
David Tolnayad2836d2017-04-20 10:11:43 -07009#![doc(html_root_url = "https://dtolnay.github.io/syn")]
David Tolnay51382052017-12-27 13:46:21 -050010#![cfg_attr(feature = "cargo-clippy",
11 allow(const_static_lifetime, doc_markdown, large_enum_variant, match_bool,
12 redundant_closure))]
David Tolnayad2836d2017-04-20 10:11:43 -070013
Alex Crichtonccbb45d2017-05-23 10:58:24 -070014extern crate proc_macro2;
David Tolnay51382052017-12-27 13:46:21 -050015extern crate proc_macro;
David Tolnay570695e2017-06-03 16:15:13 -070016extern crate unicode_xid;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070017
David Tolnay1cf80912017-12-31 18:35:12 -050018#[cfg(feature = "printing")]
David Tolnay87d0b442016-09-04 11:52:12 -070019extern crate quote;
20
David Tolnay1b752fb2017-12-26 21:41:39 -050021#[cfg(feature = "parsing")]
David Tolnayf8db7ba2017-11-11 22:52:16 -080022#[macro_use]
David Tolnayc5ab8c62017-12-26 16:43:39 -050023#[doc(hidden)]
24pub mod parsers;
David Tolnay35161ff2016-09-03 11:33:15 -070025
Alex Crichton62a0a592017-05-22 13:58:53 -070026#[macro_use]
27mod macros;
28
David Tolnayc5ab8c62017-12-26 16:43:39 -050029#[macro_use]
David Tolnay32954ef2017-12-26 22:43:16 -050030pub mod token;
David Tolnayc5ab8c62017-12-26 16:43:39 -050031
David Tolnay3cfd1d32018-01-03 00:22:08 -080032#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayb79ee962016-09-04 09:39:20 -070033mod attr;
David Tolnay3cfd1d32018-01-03 00:22:08 -080034#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay51382052017-12-27 13:46:21 -050035pub use attr::{AttrStyle, Attribute, MetaItem, MetaItemList, MetaNameValue, NestedMetaItem};
David Tolnay35161ff2016-09-03 11:33:15 -070036
David Tolnay3cfd1d32018-01-03 00:22:08 -080037#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayf38cdf62016-09-23 19:07:09 -070038mod data;
David Tolnay3cfd1d32018-01-03 00:22:08 -080039#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay61037c62018-01-05 16:21:03 -080040pub use data::{Field, Fields, FieldsNamed, FieldsUnnamed, Variant, VisCrate, VisPublic,
41 VisRestricted, Visibility};
David Tolnayf38cdf62016-09-23 19:07:09 -070042
David Tolnay3cfd1d32018-01-03 00:22:08 -080043#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayf4bbbd92016-09-23 14:41:55 -070044mod expr;
David Tolnay3cfd1d32018-01-03 00:22:08 -080045#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay51382052017-12-27 13:46:21 -050046pub use expr::{Expr, ExprAddrOf, ExprArray, ExprAssign, ExprAssignOp, ExprBinary, ExprBlock,
47 ExprBox, ExprBreak, ExprCall, ExprCast, ExprCatch, ExprClosure, ExprContinue,
48 ExprField, ExprForLoop, ExprGroup, ExprIf, ExprIfLet, ExprInPlace, ExprIndex,
David Tolnay61037c62018-01-05 16:21:03 -080049 ExprLit, ExprLoop, ExprMacro, ExprMatch, ExprMethodCall, ExprParen, ExprPath,
50 ExprRange, ExprRepeat, ExprReturn, ExprStruct, ExprTry, ExprTuple, ExprType,
51 ExprUnary, ExprUnsafe, ExprVerbatim, ExprWhile, ExprWhileLet, ExprYield, Index,
52 Member};
Michael Layzell734adb42017-06-07 16:58:31 -040053
54#[cfg(feature = "full")]
David Tolnaybcd498f2017-12-29 12:02:33 -050055pub use expr::{Arm, Block, FieldPat, FieldValue, GenericMethodArgument, Label, Local,
David Tolnay61037c62018-01-05 16:21:03 -080056 MethodTurbofish, Pat, PatBox, PatIdent, PatLit, PatMacro, PatPath, PatRange,
57 PatRef, PatSlice, PatStruct, PatTuple, PatTupleStruct, PatVerbatim, PatWild,
58 RangeLimits, Stmt};
David Tolnayf4bbbd92016-09-23 14:41:55 -070059
David Tolnay3cfd1d32018-01-03 00:22:08 -080060#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayb79ee962016-09-04 09:39:20 -070061mod generics;
David Tolnay3cfd1d32018-01-03 00:22:08 -080062#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay61037c62018-01-05 16:21:03 -080063pub use generics::{BoundLifetimes, ConstParam, GenericParam, Generics, LifetimeDef, PredicateEq,
64 PredicateLifetime, PredicateType, TraitBound, TraitBoundModifier, TypeParam,
65 TypeParamBound, WhereClause, WherePredicate};
David Tolnay3cfd1d32018-01-03 00:22:08 -080066#[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))]
David Tolnayfd6bf5c2017-11-12 09:41:14 -080067pub use generics::{ImplGenerics, Turbofish, TypeGenerics};
David Tolnay35161ff2016-09-03 11:33:15 -070068
David Tolnay55337722016-09-11 12:58:56 -070069mod ident;
David Tolnaydaaf7742016-10-03 11:11:43 -070070pub use ident::Ident;
David Tolnay55337722016-09-11 12:58:56 -070071
David Tolnayf38cdf62016-09-23 19:07:09 -070072#[cfg(feature = "full")]
David Tolnayb79ee962016-09-04 09:39:20 -070073mod item;
David Tolnayf38cdf62016-09-23 19:07:09 -070074#[cfg(feature = "full")]
David Tolnay61037c62018-01-05 16:21:03 -080075pub use item::{ArgCaptured, ArgSelf, ArgSelfRef, FnArg, FnDecl, ForeignItem, ForeignItemFn,
76 ForeignItemStatic, ForeignItemType, ForeignItemVerbatim, ImplItem, ImplItemConst,
77 ImplItemMacro, ImplItemMethod, ImplItemType, ImplItemVerbatim, Item, ItemConst,
78 ItemEnum, ItemExternCrate, ItemFn, ItemForeignMod, ItemImpl, ItemMacro, ItemMacro2,
79 ItemMod, ItemStatic, ItemStruct, ItemTrait, ItemType, ItemUnion, ItemUse,
80 ItemVerbatim, MethodSig, TraitItem, TraitItemConst, TraitItemMacro,
81 TraitItemMethod, TraitItemType, TraitItemVerbatim, UseGlob, UseList, UsePath,
82 UseTree};
David Tolnay35161ff2016-09-03 11:33:15 -070083
David Tolnay631cb8c2016-11-10 17:16:41 -080084#[cfg(feature = "full")]
David Tolnayc7a5d3d2017-06-04 12:11:05 -070085mod file;
David Tolnay631cb8c2016-11-10 17:16:41 -080086#[cfg(feature = "full")]
David Tolnayc7a5d3d2017-06-04 12:11:05 -070087pub use file::File;
David Tolnay631cb8c2016-11-10 17:16:41 -080088
David Tolnay3cfd1d32018-01-03 00:22:08 -080089#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay63e3dee2017-06-03 20:13:17 -070090mod lifetime;
David Tolnay3cfd1d32018-01-03 00:22:08 -080091#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay63e3dee2017-06-03 20:13:17 -070092pub use lifetime::Lifetime;
93
David Tolnay3cfd1d32018-01-03 00:22:08 -080094#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayf4bbbd92016-09-23 14:41:55 -070095mod lit;
David Tolnay3cfd1d32018-01-03 00:22:08 -080096#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay61037c62018-01-05 16:21:03 -080097pub use lit::{FloatSuffix, IntSuffix, Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat,
98 LitInt, LitStr, LitVerbatim, StrStyle};
David Tolnayf4bbbd92016-09-23 14:41:55 -070099
David Tolnay3cfd1d32018-01-03 00:22:08 -0800100#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayf4bbbd92016-09-23 14:41:55 -0700101mod mac;
David Tolnay3cfd1d32018-01-03 00:22:08 -0800102#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayab919512017-12-30 23:31:51 -0500103pub use mac::{Macro, MacroDelimiter};
David Tolnayf4bbbd92016-09-23 14:41:55 -0700104
David Tolnay3cfd1d32018-01-03 00:22:08 -0800105#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay0e837402016-12-22 17:25:55 -0500106mod derive;
David Tolnay3cfd1d32018-01-03 00:22:08 -0800107#[cfg(feature = "derive")]
David Tolnaye3d41b72017-12-31 15:24:00 -0500108pub use derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput};
David Tolnayf38cdf62016-09-23 19:07:09 -0700109
David Tolnay3cfd1d32018-01-03 00:22:08 -0800110#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay3cb23a92016-10-07 23:02:21 -0700111mod op;
David Tolnay3cfd1d32018-01-03 00:22:08 -0800112#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay3cb23a92016-10-07 23:02:21 -0700113pub use op::{BinOp, UnOp};
114
David Tolnay3cfd1d32018-01-03 00:22:08 -0800115#[cfg(any(feature = "full", feature = "derive"))]
David Tolnayb79ee962016-09-04 09:39:20 -0700116mod ty;
David Tolnay3cfd1d32018-01-03 00:22:08 -0800117#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay61037c62018-01-05 16:21:03 -0800118pub use ty::{Abi, BareFnArg, BareFnArgName, ReturnType, Type, TypeArray, TypeBareFn, TypeGroup,
119 TypeImplTrait, TypeInfer, TypeMacro, TypeNever, TypeParen, TypePath, TypePtr,
120 TypeReference, TypeSlice, TypeTraitObject, TypeTuple, TypeVerbatim};
David Tolnay056de302018-01-05 14:29:05 -0800121
122#[cfg(any(feature = "full", feature = "derive"))]
123mod path;
124#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay61037c62018-01-05 16:21:03 -0800125pub use path::{AngleBracketedGenericArguments, Binding, GenericArgument,
126 ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf};
David Tolnay3cfd1d32018-01-03 00:22:08 -0800127#[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))]
David Tolnay056de302018-01-05 14:29:05 -0800128pub use path::PathTokens;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700129
David Tolnay1b752fb2017-12-26 21:41:39 -0500130#[cfg(feature = "parsing")]
David Tolnayc5ab8c62017-12-26 16:43:39 -0500131mod cursor;
David Tolnay1b752fb2017-12-26 21:41:39 -0500132#[cfg(feature = "parsing")]
David Tolnayc5ab8c62017-12-26 16:43:39 -0500133pub mod synom;
David Tolnayf2cfd722017-12-31 18:02:51 -0500134pub mod punctuated;
David Tolnay3cfd1d32018-01-03 00:22:08 -0800135#[cfg(all(any(feature = "full", feature = "derive"), feature = "parsing"))]
David Tolnaye0824032017-12-27 15:25:56 -0500136mod tt;
David Tolnayc5ab8c62017-12-26 16:43:39 -0500137
David Tolnay4d942b42018-01-02 22:14:04 -0800138#[cfg(all(feature = "parsing", feature = "printing"))]
David Tolnayf790b612017-12-31 18:46:57 -0500139pub mod spanned;
140
Nika Layzella6f46c42017-10-26 15:26:16 -0400141mod gen {
142 #[cfg(feature = "visit")]
143 pub mod visit;
David Tolnay55337722016-09-11 12:58:56 -0700144
Nika Layzella6f46c42017-10-26 15:26:16 -0400145 #[cfg(feature = "visit_mut")]
146 pub mod visit_mut;
Nika Layzell27726662017-10-24 23:16:35 -0400147
Nika Layzella6f46c42017-10-26 15:26:16 -0400148 #[cfg(feature = "fold")]
149 pub mod fold;
David Tolnayf60f4262017-12-28 19:17:58 -0500150
David Tolnay0a0d78c2018-01-05 15:24:01 -0800151 #[cfg(any(feature = "full", feature = "derive"))]
David Tolnayf60f4262017-12-28 19:17:58 -0500152 #[path = "../gen_helper.rs"]
153 mod helper;
Nika Layzella6f46c42017-10-26 15:26:16 -0400154}
155pub use gen::*;
gnzlbg9ae88d82017-01-26 20:45:17 +0100156
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700157////////////////////////////////////////////////////////////////////////////////
158
David Tolnay55337722016-09-11 12:58:56 -0700159#[cfg(feature = "parsing")]
David Tolnayc5ab8c62017-12-26 16:43:39 -0500160use synom::Synom;
161#[cfg(feature = "parsing")]
162use cursor::SynomBuffer;
Ted Driggs054abbb2017-05-01 12:20:52 -0700163
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700164#[cfg(feature = "parsing")]
David Tolnayc5ab8c62017-12-26 16:43:39 -0500165mod error;
166#[cfg(feature = "parsing")]
David Tolnay203557a2017-12-27 23:59:33 -0500167use error::ParseError;
David Tolnayc5ab8c62017-12-26 16:43:39 -0500168
169// Not public API.
David Tolnay1b752fb2017-12-26 21:41:39 -0500170#[cfg(feature = "parsing")]
David Tolnayc5ab8c62017-12-26 16:43:39 -0500171#[doc(hidden)]
172pub use error::parse_error;
Michael Layzell416724e2017-05-24 21:12:34 -0400173
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700174/// Parse tokens of source code into the chosen syn data type.
175///
176/// This is preferred over parsing a string because tokens are able to preserve
177/// information about where in the user's code they were originally written (the
178/// "span" of the token), possibly allowing the compiler to produce better error
179/// messages.
180///
181/// # Examples
182///
David Tolnaybcf26022017-12-25 22:10:52 -0500183/// ```rust
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700184/// extern crate proc_macro;
185/// use proc_macro::TokenStream;
186///
187/// extern crate syn;
188///
189/// #[macro_use]
190/// extern crate quote;
191///
192/// use syn::DeriveInput;
193///
David Tolnaybcf26022017-12-25 22:10:52 -0500194/// # const IGNORE_TOKENS: &str = stringify! {
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700195/// #[proc_macro_derive(MyMacro)]
David Tolnaybcf26022017-12-25 22:10:52 -0500196/// # };
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700197/// pub fn my_macro(input: TokenStream) -> TokenStream {
198/// // Parse the tokens into a syntax tree
199/// let ast: DeriveInput = syn::parse(input).unwrap();
200///
201/// // Build the output, possibly using quasi-quotation
202/// let expanded = quote! {
203/// /* ... */
204/// };
205///
David Tolnaybcf26022017-12-25 22:10:52 -0500206/// // Convert into a token stream and return it
207/// expanded.into()
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700208/// }
David Tolnaybcf26022017-12-25 22:10:52 -0500209/// #
210/// # fn main() {}
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700211/// ```
212#[cfg(feature = "parsing")]
213pub fn parse<T>(tokens: proc_macro::TokenStream) -> Result<T, ParseError>
David Tolnay51382052017-12-27 13:46:21 -0500214where
215 T: Synom,
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700216{
217 _parse(tokens.into())
218}
219
220#[cfg(feature = "parsing")]
221fn _parse<T>(tokens: proc_macro2::TokenStream) -> Result<T, ParseError>
David Tolnay51382052017-12-27 13:46:21 -0500222where
223 T: Synom,
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700224{
225 let buf = SynomBuffer::new(tokens);
226 let result = T::parse(buf.begin());
227 let err = match result {
David Tolnayf4aa6b42017-12-31 16:40:33 -0500228 Ok((t, rest)) => {
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700229 if rest.eof() {
230 return Ok(t);
231 } else if rest == buf.begin() {
232 // parsed nothing
233 ParseError::new("failed to parse anything")
234 } else {
235 ParseError::new("failed to parse all tokens")
David Tolnay55337722016-09-11 12:58:56 -0700236 }
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700237 }
238 Err(err) => err,
239 };
240 match T::description() {
Alex Crichtonc1b76f52017-07-06 15:04:24 -0700241 Some(s) => Err(ParseError::new(format!("failed to parse {}: {}", s, err))),
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700242 None => Err(err),
243 }
244}
Alex Crichton954046c2017-05-30 21:49:42 -0700245
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700246/// Parse a string of Rust code into the chosen syn data type.
247///
248/// # Examples
249///
250/// ```rust
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 syn::Expr;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700257///
258/// fn run() -> Result<()> {
259/// let code = "assert_eq!(u8::max_value(), 255)";
260/// let expr = syn::parse_str::<Expr>(code)?;
261/// println!("{:#?}", expr);
262/// Ok(())
263/// }
264/// #
265/// # fn main() { run().unwrap() }
266/// ```
267#[cfg(feature = "parsing")]
268pub fn parse_str<T: Synom>(s: &str) -> Result<T, ParseError> {
David Tolnayffb1f4d2017-12-28 00:07:59 -0500269 match s.parse() {
270 Ok(tts) => _parse(tts),
271 Err(_) => Err(ParseError::new("error while lexing input string")),
272 }
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700273}
Alex Crichton954046c2017-05-30 21:49:42 -0700274
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700275// FIXME the name parse_file makes it sound like you might pass in a path to a
276// file, rather than the content.
277/// Parse the content of a file of Rust code.
278///
279/// This is different from `syn::parse_str::<File>(content)` in two ways:
280///
281/// - It discards a leading byte order mark `\u{FEFF}` if the file has one.
282/// - It preserves the shebang line of the file, such as `#!/usr/bin/env rustx`.
283///
284/// If present, either of these would be an error using `from_str`.
285///
286/// # Examples
287///
288/// ```rust,no_run
289/// extern crate syn;
290/// #
David Tolnay9174b972017-11-09 22:27:50 -0800291/// #
292/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700293///
294/// use std::fs::File;
295/// use std::io::Read;
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700296///
297/// fn run() -> Result<()> {
298/// let mut file = File::open("path/to/code.rs")?;
299/// let mut content = String::new();
300/// file.read_to_string(&mut content)?;
301///
302/// let ast = syn::parse_file(&content)?;
303/// if let Some(shebang) = ast.shebang {
304/// println!("{}", shebang);
305/// }
306/// println!("{} items", ast.items.len());
307///
308/// Ok(())
309/// }
310/// #
311/// # fn main() { run().unwrap() }
312/// ```
313#[cfg(all(feature = "parsing", feature = "full"))]
314pub fn parse_file(mut content: &str) -> Result<File, ParseError> {
315 // Strip the BOM if it is present
316 const BOM: &'static str = "\u{feff}";
317 if content.starts_with(BOM) {
318 content = &content[BOM.len()..];
David Tolnay35161ff2016-09-03 11:33:15 -0700319 }
Michael Layzell5e107ff2017-01-24 19:58:39 -0500320
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700321 let mut shebang = None;
322 if content.starts_with("#!") && !content.starts_with("#![") {
323 if let Some(idx) = content.find('\n') {
324 shebang = Some(content[..idx].to_string());
325 content = &content[idx..];
326 } else {
327 shebang = Some(content.to_string());
328 content = "";
329 }
Alex Crichton954046c2017-05-30 21:49:42 -0700330 }
David Tolnay0a8972b2017-02-27 02:10:01 -0800331
David Tolnayc7a5d3d2017-06-04 12:11:05 -0700332 let mut file: File = parse_str(content)?;
333 file.shebang = shebang;
334 Ok(file)
Michael Layzell5e107ff2017-01-24 19:58:39 -0500335}
Alex Crichton259ee532017-07-14 06:51:02 -0700336
David Tolnay01cc0202018-01-02 11:13:07 -0800337#[cfg(all(feature = "parsing", feature = "printing"))]
338#[macro_export]
339macro_rules! parse_quote {
340 ($($tt:tt)*) => {
341 ::std::result::Result::unwrap(
342 $crate::parse(
343 ::std::convert::Into::into(
344 quote!($($tt)*))))
345 };
346}
347
David Tolnay3cfd1d32018-01-03 00:22:08 -0800348#[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))]
Alex Crichton259ee532017-07-14 06:51:02 -0700349struct TokensOrDefault<'a, T: 'a>(&'a Option<T>);
350
David Tolnay3cfd1d32018-01-03 00:22:08 -0800351#[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))]
Alex Crichton259ee532017-07-14 06:51:02 -0700352impl<'a, T> quote::ToTokens for TokensOrDefault<'a, T>
David Tolnay51382052017-12-27 13:46:21 -0500353where
354 T: quote::ToTokens + Default,
Alex Crichton259ee532017-07-14 06:51:02 -0700355{
356 fn to_tokens(&self, tokens: &mut quote::Tokens) {
357 match *self.0 {
358 Some(ref t) => t.to_tokens(tokens),
359 None => T::default().to_tokens(tokens),
360 }
361 }
362}