Move parse_macro_input to a different trait
diff --git a/src/lib.rs b/src/lib.rs
index d8031f5..00d5e1d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -446,6 +446,15 @@
#[doc(hidden)]
pub mod parse_quote;
+// Not public API except the `parse_macro_input!` macro.
+#[cfg(all(
+ not(all(target_arch = "wasm32", target_os = "unknown")),
+ feature = "parsing",
+ feature = "proc-macro"
+))]
+#[doc(hidden)]
+pub mod parse_macro_input;
+
#[cfg(all(feature = "parsing", feature = "printing"))]
pub mod spanned;
@@ -763,58 +772,3 @@
file.shebang = shebang;
Ok(file)
}
-
-/// Parse the input TokenStream of a macro, triggering a compile error if the
-/// tokens fail to parse.
-///
-/// Refer to the [`parse` module] documentation for more details about parsing
-/// in Syn.
-///
-/// [`parse` module]: parse/index.html
-///
-/// # Intended usage
-///
-/// ```rust
-/// #[macro_use]
-/// extern crate syn;
-///
-/// extern crate proc_macro;
-///
-/// use proc_macro::TokenStream;
-/// use syn::parse::{Parse, ParseStream, Result};
-///
-/// struct MyMacroInput {
-/// /* ... */
-/// }
-///
-/// impl Parse for MyMacroInput {
-/// fn parse(input: ParseStream) -> Result<Self> {
-/// /* ... */
-/// # Ok(MyMacroInput {})
-/// }
-/// }
-///
-/// # const IGNORE: &str = stringify! {
-/// #[proc_macro]
-/// # };
-/// pub fn my_macro(tokens: TokenStream) -> TokenStream {
-/// let input = parse_macro_input!(tokens as MyMacroInput);
-///
-/// /* ... */
-/// # "".parse().unwrap()
-/// }
-/// #
-/// # fn main() {}
-/// ```
-#[cfg(feature = "proc-macro")]
-#[macro_export]
-macro_rules! parse_macro_input {
- ($tokenstream:ident as $ty:ty) => {
- match $crate::parse::<$ty>($tokenstream) {
- $crate::export::Ok(data) => data,
- $crate::export::Err(err) => {
- return $crate::export::TokenStream::from(err.to_compile_error());
- }
- };
- };
-}
diff --git a/src/parse_macro_input.rs b/src/parse_macro_input.rs
new file mode 100644
index 0000000..e66d1d4
--- /dev/null
+++ b/src/parse_macro_input.rs
@@ -0,0 +1,102 @@
+/// Parse the input TokenStream of a macro, triggering a compile error if the
+/// tokens fail to parse.
+///
+/// Refer to the [`parse` module] documentation for more details about parsing
+/// in Syn.
+///
+/// [`parse` module]: parse/index.html
+///
+/// # Intended usage
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// extern crate proc_macro;
+///
+/// use proc_macro::TokenStream;
+/// use syn::parse::{Parse, ParseStream, Result};
+///
+/// struct MyMacroInput {
+/// /* ... */
+/// }
+///
+/// impl Parse for MyMacroInput {
+/// fn parse(input: ParseStream) -> Result<Self> {
+/// /* ... */
+/// # Ok(MyMacroInput {})
+/// }
+/// }
+///
+/// # const IGNORE: &str = stringify! {
+/// #[proc_macro]
+/// # };
+/// pub fn my_macro(tokens: TokenStream) -> TokenStream {
+/// let input = parse_macro_input!(tokens as MyMacroInput);
+///
+/// /* ... */
+/// # "".parse().unwrap()
+/// }
+/// #
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! parse_macro_input {
+ ($tokenstream:ident as $ty:ty) => {
+ match $crate::parse_macro_input::parse::<$ty>($tokenstream) {
+ $crate::export::Ok(data) => data,
+ $crate::export::Err(err) => {
+ return $crate::export::TokenStream::from(err.to_compile_error());
+ }
+ };
+ };
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Can parse any type that implements Parse.
+
+use parse::{Parse, ParseStream, Parser, Result};
+use proc_macro::TokenStream;
+
+// Not public API.
+#[doc(hidden)]
+pub fn parse<T: ParseMacroInput>(token_stream: TokenStream) -> Result<T> {
+ T::parse.parse(token_stream)
+}
+
+// Not public API.
+#[doc(hidden)]
+pub trait ParseMacroInput: Sized {
+ fn parse(input: ParseStream) -> Result<Self>;
+}
+
+impl<T: Parse> ParseMacroInput for T {
+ fn parse(input: ParseStream) -> Result<Self> {
+ <T as Parse>::parse(input)
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Any other types that we want `parse_macro_input!` to be able to parse.
+
+use NestedMeta;
+
+impl ParseMacroInput for Vec<NestedMeta> {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let mut metas = Vec::new();
+
+ loop {
+ if input.is_empty() {
+ break;
+ }
+ let value = input.parse()?;
+ metas.push(value);
+ if input.is_empty() {
+ break;
+ }
+ input.parse::<Token![,]>()?;
+ }
+
+ Ok(metas)
+ }
+}
diff --git a/src/parse_quote.rs b/src/parse_quote.rs
index 9e0084c..93e2759 100644
--- a/src/parse_quote.rs
+++ b/src/parse_quote.rs
@@ -139,9 +139,7 @@
////////////////////////////////////////////////////////////////////////////////
// Any other types that we want `parse_quote!` to be able to parse.
-use NestedMeta;
use punctuated::Punctuated;
-use token;
#[cfg(any(feature = "full", feature = "derive"))]
use {attr, Attribute};
@@ -161,13 +159,3 @@
Self::parse_terminated(input)
}
}
-
-impl ParseQuote for Vec<NestedMeta> {
- fn parse(input: ParseStream) -> Result<Self> {
- let items = input.parse_terminated::<_, token::Comma>(<NestedMeta as Parse>::parse)?
- .into_iter()
- .collect();
-
- Ok(items)
- }
-}
diff --git a/tests/test_meta_item.rs b/tests/test_meta_item.rs
index 79fe90f..30b06cc 100644
--- a/tests/test_meta_item.rs
+++ b/tests/test_meta_item.rs
@@ -10,7 +10,6 @@
extern crate proc_macro2;
extern crate syn;
-#[macro_use]
extern crate quote;
use proc_macro2::{Ident, Literal, Span};
@@ -304,60 +303,6 @@
assert_eq!(expected, syn::parse_str(raw).unwrap());
}
-#[test]
-fn test_parse_quote_nested_meta() {
- let actual: Vec<NestedMeta> = parse_quote!(5);
-
- let expected = vec![
- NestedMeta::Literal(lit(Literal::i32_unsuffixed(5)))
- ];
-
- assert_eq!(expected, actual);
-
- let actual: Vec<NestedMeta> = parse_quote!(list(name2 = 6));
-
- let expected = vec![
- NestedMeta::Meta(
- MetaList {
- ident: ident("list").into(),
- paren_token: Default::default(),
- nested: punctuated![NestedMeta::Meta(
- MetaNameValue {
- ident: ident("name2").into(),
- eq_token: Default::default(),
- lit: lit(Literal::i32_unsuffixed(6)),
- }
- .into(),
- )],
- }
- .into(),
- )
- ];
-
- assert_eq!(expected, actual);
-
- let actual: Vec<NestedMeta> = parse_quote!(5, list(name2 = 6));
-
- let expected = vec![
- NestedMeta::Literal(lit(Literal::i32_unsuffixed(5))),
- NestedMeta::Meta(
- MetaList {
- ident: ident("list").into(),
- paren_token: Default::default(),
- nested: punctuated![NestedMeta::Meta(
- MetaNameValue {
- ident: ident("name2").into(),
- eq_token: Default::default(),
- lit: lit(Literal::i32_unsuffixed(6)),
- }
- .into(),
- )],
- }
- .into(),
- )
- ];
-}
-
fn run_test<T: Into<Meta>>(input: &str, expected: T) {
let attrs = Attribute::parse_outer.parse_str(input).unwrap();
assert_eq!(attrs.len(), 1);