(juniper_codegen) Upgrade syn + quote

This commit is contained in:
Christoph Herzog 2018-05-03 01:21:08 +02:00 committed by theduke
parent 3df18f41f8
commit 05c1011d83
6 changed files with 116 additions and 86 deletions

View file

@ -14,8 +14,8 @@ repository = "https://github.com/graphql-rust/juniper"
proc-macro = true proc-macro = true
[dependencies] [dependencies]
syn = "0.11" syn = { version = "0.13.*", features = ["full", "extra-traits"] }
quote = "0.3" quote = "0.5.*"
[badges] [badges]
travis-ci = { repository = "graphql-rust/juniper" } travis-ci = { repository = "graphql-rust/juniper" }

View file

@ -1,5 +1,13 @@
use syn; use syn;
use syn::*; use syn::{
DeriveInput,
Meta,
NestedMeta,
Data,
Fields,
Ident,
Variant,
};
use quote::Tokens; use quote::Tokens;
use util::*; use util::*;
@ -23,16 +31,16 @@ impl EnumAttrs {
// Check attributes for name and description. // Check attributes for name and description.
if let Some(items) = get_graphl_attr(&input.attrs) { if let Some(items) = get_graphl_attr(&input.attrs) {
for item in items { for item in items {
if let Some(val) = keyed_item_value(item, "name", true) { if let Some(val) = keyed_item_value(&item, "name", true) {
res.name = Some(val); res.name = Some(val);
continue; continue;
} }
if let Some(val) = keyed_item_value(item, "description", true) { if let Some(val) = keyed_item_value(&item, "description", true) {
res.description = Some(val); res.description = Some(val);
continue; continue;
} }
match item { match item {
&NestedMetaItem::MetaItem(MetaItem::Word(ref ident)) => { NestedMeta::Meta(Meta::Word(ref ident)) => {
if ident == "_internal" { if ident == "_internal" {
res.internal = true; res.internal = true;
continue; continue;
@ -64,15 +72,15 @@ impl EnumVariantAttrs {
// Check attributes for name and description. // Check attributes for name and description.
if let Some(items) = get_graphl_attr(&variant.attrs) { if let Some(items) = get_graphl_attr(&variant.attrs) {
for item in items { for item in items {
if let Some(val) = keyed_item_value(item, "name", true) { if let Some(val) = keyed_item_value(&item, "name", true) {
res.name = Some(val); res.name = Some(val);
continue; continue;
} }
if let Some(val) = keyed_item_value(item, "description", true) { if let Some(val) = keyed_item_value(&item, "description", true) {
res.description = Some(val); res.description = Some(val);
continue; continue;
} }
if let Some(val) = keyed_item_value(item, "deprecated", true) { if let Some(val) = keyed_item_value(&item, "deprecated", true) {
res.deprecation = Some(val); res.deprecation = Some(val);
continue; continue;
} }
@ -87,9 +95,9 @@ impl EnumVariantAttrs {
} }
pub fn impl_enum(ast: &syn::DeriveInput) -> Tokens { pub fn impl_enum(ast: &syn::DeriveInput) -> Tokens {
let variants = match ast.body { let variants = match ast.data {
Body::Enum(ref var) => var, Data::Enum(ref enum_data) => enum_data.variants.iter().collect::<Vec<_>>(),
Body::Struct(_) => { _ => {
panic!("#[derive(GraphlQLEnum)] may only be applied to enums, not to structs"); panic!("#[derive(GraphlQLEnum)] may only be applied to enums, not to structs");
} }
}; };
@ -110,12 +118,16 @@ pub fn impl_enum(ast: &syn::DeriveInput) -> Tokens {
let mut to_inputs = Vec::<Tokens>::new(); let mut to_inputs = Vec::<Tokens>::new();
for variant in variants { for variant in variants {
if variant.data != VariantData::Unit { match variant.fields {
panic!(format!( Fields::Unit => {},
"Invalid enum variant {}.\nGraphQL enums may only contain unit variants.", _ => {
variant.ident panic!(format!(
)); "Invalid enum variant {}.\nGraphQL enums may only contain unit variants.",
} variant.ident
));
}
} ;
let var_attrs = EnumVariantAttrs::from_input(variant); let var_attrs = EnumVariantAttrs::from_input(variant);
let var_ident = &variant.ident; let var_ident = &variant.ident;
@ -209,7 +221,7 @@ pub fn impl_enum(ast: &syn::DeriveInput) -> Tokens {
} }
}; };
let dummy_const = Ident::new(format!("_IMPL_GRAPHQLENUM_FOR_{}", ident)); let dummy_const = Ident::from(format!("_IMPL_GRAPHQLENUM_FOR_{}", ident).as_str());
// This ugly hack makes it possible to use the derive inside juniper itself. // This ugly hack makes it possible to use the derive inside juniper itself.
// FIXME: Figure out a better way to do this! // FIXME: Figure out a better way to do this!

View file

@ -1,6 +1,16 @@
use syn; use std::str::FromStr;
use syn::*;
use quote::Tokens; use syn::{
self,
DeriveInput,
NestedMeta,
Meta,
Field,
Fields,
Data,
Ident,
};
use quote::{Tokens, ToTokens};
use util::*; use util::*;
@ -18,16 +28,16 @@ impl ObjAttrs {
// Check attributes for name and description. // Check attributes for name and description.
if let Some(items) = get_graphl_attr(&input.attrs) { if let Some(items) = get_graphl_attr(&input.attrs) {
for item in items { for item in items {
if let Some(val) = keyed_item_value(item, "name", true) { if let Some(val) = keyed_item_value(&item, "name", true) {
res.name = Some(val); res.name = Some(val);
continue; continue;
} }
if let Some(val) = keyed_item_value(item, "description", true) { if let Some(val) = keyed_item_value(&item, "description", true) {
res.description = Some(val); res.description = Some(val);
continue; continue;
} }
match item { match item {
&NestedMetaItem::MetaItem(MetaItem::Word(ref ident)) => { NestedMeta::Meta(Meta::Word(ref ident)) => {
if ident == "_internal" { if ident == "_internal" {
res.internal = true; res.internal = true;
continue; continue;
@ -60,20 +70,20 @@ impl ObjFieldAttrs {
// Check attributes for name and description. // Check attributes for name and description.
if let Some(items) = get_graphl_attr(&variant.attrs) { if let Some(items) = get_graphl_attr(&variant.attrs) {
for item in items { for item in items {
if let Some(val) = keyed_item_value(item, "name", true) { if let Some(val) = keyed_item_value(&item, "name", true) {
res.name = Some(val); res.name = Some(val);
continue; continue;
} }
if let Some(val) = keyed_item_value(item, "description", true) { if let Some(val) = keyed_item_value(&item, "description", true) {
res.description = Some(val); res.description = Some(val);
continue; continue;
} }
if let Some(val) = keyed_item_value(item, "default", true) { if let Some(val) = keyed_item_value(&item, "default", true) {
res.default_expr = Some(val); res.default_expr = Some(val);
continue; continue;
} }
match item { match item {
&NestedMetaItem::MetaItem(MetaItem::Word(ref ident)) => { NestedMeta::Meta(Meta::Word(ref ident)) => {
if ident == "default" { if ident == "default" {
res.default = true; res.default = true;
continue; continue;
@ -92,16 +102,16 @@ impl ObjFieldAttrs {
} }
pub fn impl_input_object(ast: &syn::DeriveInput) -> Tokens { pub fn impl_input_object(ast: &syn::DeriveInput) -> Tokens {
let fields = match ast.body { let fields = match ast.data {
Body::Struct(ref data) => match data { Data::Struct(ref data) => match data.fields {
&VariantData::Struct(ref fields) => fields, Fields::Named(ref named) => named.named.iter().collect::<Vec<_>>(),
_ => { _ => {
panic!( panic!(
"#[derive(GraphQLInputObject)] may only be used on regular structs with fields" "#[derive(GraphQLInputObject)] may only be used on regular structs with fields"
); );
} }
}, },
Body::Enum(_) => { _ => {
panic!("#[derive(GraphlQLInputObject)] may only be applied to structs, not to enums"); panic!("#[derive(GraphlQLInputObject)] may only be applied to structs, not to enums");
} }
}; };
@ -146,8 +156,17 @@ pub fn impl_input_object(ast: &syn::DeriveInput) -> Tokens {
Some(quote! { Default::default() }) Some(quote! { Default::default() })
} else { } else {
match field_attrs.default_expr { match field_attrs.default_expr {
Some(ref def) => match syn::parse_token_trees(def) { Some(ref def) => match ::proc_macro::TokenStream::from_str(def) {
Ok(t) => Some(quote! { #(#t)* }), Ok(t) => {
match syn::parse::<syn::Expr>(t) {
Ok(e) => {
Some(e.into_tokens())
},
Err(_) => {
panic!("#graphql(default = ?) must be a valid Rust expression inside a string");
},
}
},
Err(_) => { Err(_) => {
panic!("#graphql(default = ?) must be a valid Rust expression inside a string"); panic!("#graphql(default = ?) must be a valid Rust expression inside a string");
} }
@ -256,7 +275,7 @@ pub fn impl_input_object(ast: &syn::DeriveInput) -> Tokens {
} }
}; };
let dummy_const = Ident::new(format!("_IMPL_GRAPHQLINPUTOBJECT_FOR_{}", ident)); let dummy_const = Ident::from(format!("_IMPL_GRAPHQLINPUTOBJECT_FOR_{}", ident).as_str());
// This ugly hack makes it possible to use the derive inside juniper itself. // This ugly hack makes it possible to use the derive inside juniper itself.
// FIXME: Figure out a better way to do this! // FIXME: Figure out a better way to do this!

View file

@ -1,5 +1,10 @@
use syn; use syn;
use syn::*; use syn::{
DeriveInput,
Data,
Fields,
Field,
};
use quote::Tokens; use quote::Tokens;
use util::*; use util::*;
@ -17,11 +22,11 @@ impl ObjAttrs {
// Check attributes for name and description. // Check attributes for name and description.
if let Some(items) = get_graphl_attr(&input.attrs) { if let Some(items) = get_graphl_attr(&input.attrs) {
for item in items { for item in items {
if let Some(val) = keyed_item_value(item, "name", true) { if let Some(val) = keyed_item_value(&item, "name", true) {
res.name = Some(val); res.name = Some(val);
continue; continue;
} }
if let Some(val) = keyed_item_value(item, "description", true) { if let Some(val) = keyed_item_value(&item, "description", true) {
res.description = Some(val); res.description = Some(val);
continue; continue;
} }
@ -49,15 +54,15 @@ impl ObjFieldAttrs {
// Check attributes for name and description. // Check attributes for name and description.
if let Some(items) = get_graphl_attr(&variant.attrs) { if let Some(items) = get_graphl_attr(&variant.attrs) {
for item in items { for item in items {
if let Some(val) = keyed_item_value(item, "name", true) { if let Some(val) = keyed_item_value(&item, "name", true) {
res.name = Some(val); res.name = Some(val);
continue; continue;
} }
if let Some(val) = keyed_item_value(item, "description", true) { if let Some(val) = keyed_item_value(&item, "description", true) {
res.description = Some(val); res.description = Some(val);
continue; continue;
} }
if let Some(val) = keyed_item_value(item, "deprecation", true) { if let Some(val) = keyed_item_value(&item, "deprecation", true) {
res.deprecation = Some(val); res.deprecation = Some(val);
continue; continue;
} }
@ -72,14 +77,14 @@ impl ObjFieldAttrs {
} }
pub fn impl_object(ast: &syn::DeriveInput) -> Tokens { pub fn impl_object(ast: &syn::DeriveInput) -> Tokens {
let fields = match ast.body { let fields = match ast.data {
Body::Struct(ref data) => match data { Data::Struct(ref data) => match data.fields {
&VariantData::Struct(ref fields) => fields, Fields::Named(ref fields) => fields.named.iter().collect::<Vec<_>>(),
_ => { _ => {
panic!("#[derive(GraphQLObject)] may only be used on regular structs with fields"); panic!("#[derive(GraphQLObject)] may only be used on regular structs with fields");
} }
}, },
Body::Enum(_) => { _ => {
panic!("#[derive(GraphlQLObject)] may only be applied to structs, not to enums"); panic!("#[derive(GraphlQLObject)] may only be applied to structs, not to enums");
} }
}; };

View file

@ -20,24 +20,21 @@ use proc_macro::TokenStream;
#[proc_macro_derive(GraphQLEnum, attributes(graphql))] #[proc_macro_derive(GraphQLEnum, attributes(graphql))]
pub fn derive_enum(input: TokenStream) -> TokenStream { pub fn derive_enum(input: TokenStream) -> TokenStream {
let s = input.to_string(); let ast = syn::parse::<syn::DeriveInput>(input).unwrap();
let ast = syn::parse_derive_input(&s).unwrap();
let gen = derive_enum::impl_enum(&ast); let gen = derive_enum::impl_enum(&ast);
gen.parse().unwrap() gen.into()
} }
#[proc_macro_derive(GraphQLInputObject, attributes(graphql))] #[proc_macro_derive(GraphQLInputObject, attributes(graphql))]
pub fn derive_input_object(input: TokenStream) -> TokenStream { pub fn derive_input_object(input: TokenStream) -> TokenStream {
let s = input.to_string(); let ast = syn::parse::<syn::DeriveInput>(input).unwrap();
let ast = syn::parse_derive_input(&s).unwrap();
let gen = derive_input_object::impl_input_object(&ast); let gen = derive_input_object::impl_input_object(&ast);
gen.parse().unwrap() gen.into()
} }
#[proc_macro_derive(GraphQLObject, attributes(graphql))] #[proc_macro_derive(GraphQLObject, attributes(graphql))]
pub fn derive_object(input: TokenStream) -> TokenStream { pub fn derive_object(input: TokenStream) -> TokenStream {
let s = input.to_string(); let ast = syn::parse::<syn::DeriveInput>(input).unwrap();
let ast = syn::parse_derive_input(&s).unwrap();
let gen = derive_object::impl_object(&ast); let gen = derive_object::impl_object(&ast);
gen.parse().unwrap() gen.into()
} }

View file

@ -1,10 +1,16 @@
use syn::*; use syn::{
Attribute,
Meta,
NestedMeta,
Lit,
};
pub fn get_graphl_attr(attrs: &Vec<Attribute>) -> Option<&Vec<NestedMetaItem>> { // Get the nested items of a a #[graphql(...)] attribute.
pub fn get_graphl_attr(attrs: &Vec<Attribute>) -> Option<Vec<NestedMeta>> {
for attr in attrs { for attr in attrs {
match attr.value { match attr.interpret_meta() {
MetaItem::List(ref attr_name, ref items) => if attr_name == "graphql" { Some(Meta::List(ref list)) if list.ident == "graphql" => {
return Some(items); return Some(list.nested.iter().map(|x| x.clone()).collect());
}, },
_ => {} _ => {}
} }
@ -12,33 +18,24 @@ pub fn get_graphl_attr(attrs: &Vec<Attribute>) -> Option<&Vec<NestedMetaItem>> {
None None
} }
pub fn keyed_item_value(item: &NestedMetaItem, name: &str, must_be_string: bool) -> Option<String> { pub fn keyed_item_value(item: &NestedMeta, name: &str, must_be_string: bool) -> Option<String> {
let item = match item { match item {
&NestedMetaItem::MetaItem(ref item) => item, &NestedMeta::Meta(Meta::NameValue(ref nameval)) if nameval.ident == name => {
_ => { match &nameval.lit {
return None; &Lit::Str(ref strlit) => {
} Some(strlit.value())
}; },
let lit = match item { _ => if must_be_string {
&MetaItem::NameValue(ref ident, ref lit) => if ident == name { panic!(format!(
lit "Invalid format for attribute \"{:?}\": expected a string",
} else { item
return None; ));
}, } else {
_ => { None
return None; },
} }
};
match lit {
&Lit::Str(ref val, _) => Some(val.clone()),
_ => if must_be_string {
panic!(format!(
"Invalid format for attribute \"{:?}\": expected a string",
item
));
} else {
None
}, },
_ => None,
} }
} }