(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
[dependencies]
syn = "0.11"
quote = "0.3"
syn = { version = "0.13.*", features = ["full", "extra-traits"] }
quote = "0.5.*"
[badges]
travis-ci = { repository = "graphql-rust/juniper" }

View file

@ -1,5 +1,13 @@
use syn;
use syn::*;
use syn::{
DeriveInput,
Meta,
NestedMeta,
Data,
Fields,
Ident,
Variant,
};
use quote::Tokens;
use util::*;
@ -23,16 +31,16 @@ impl EnumAttrs {
// Check attributes for name and description.
if let Some(items) = get_graphl_attr(&input.attrs) {
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);
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);
continue;
}
match item {
&NestedMetaItem::MetaItem(MetaItem::Word(ref ident)) => {
NestedMeta::Meta(Meta::Word(ref ident)) => {
if ident == "_internal" {
res.internal = true;
continue;
@ -64,15 +72,15 @@ impl EnumVariantAttrs {
// Check attributes for name and description.
if let Some(items) = get_graphl_attr(&variant.attrs) {
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);
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);
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);
continue;
}
@ -87,9 +95,9 @@ impl EnumVariantAttrs {
}
pub fn impl_enum(ast: &syn::DeriveInput) -> Tokens {
let variants = match ast.body {
Body::Enum(ref var) => var,
Body::Struct(_) => {
let variants = match ast.data {
Data::Enum(ref enum_data) => enum_data.variants.iter().collect::<Vec<_>>(),
_ => {
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();
for variant in variants {
if variant.data != VariantData::Unit {
panic!(format!(
"Invalid enum variant {}.\nGraphQL enums may only contain unit variants.",
variant.ident
));
}
match variant.fields {
Fields::Unit => {},
_ => {
panic!(format!(
"Invalid enum variant {}.\nGraphQL enums may only contain unit variants.",
variant.ident
));
}
} ;
let var_attrs = EnumVariantAttrs::from_input(variant);
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.
// FIXME: Figure out a better way to do this!

View file

@ -1,6 +1,16 @@
use syn;
use syn::*;
use quote::Tokens;
use std::str::FromStr;
use syn::{
self,
DeriveInput,
NestedMeta,
Meta,
Field,
Fields,
Data,
Ident,
};
use quote::{Tokens, ToTokens};
use util::*;
@ -18,16 +28,16 @@ impl ObjAttrs {
// Check attributes for name and description.
if let Some(items) = get_graphl_attr(&input.attrs) {
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);
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);
continue;
}
match item {
&NestedMetaItem::MetaItem(MetaItem::Word(ref ident)) => {
NestedMeta::Meta(Meta::Word(ref ident)) => {
if ident == "_internal" {
res.internal = true;
continue;
@ -60,20 +70,20 @@ impl ObjFieldAttrs {
// Check attributes for name and description.
if let Some(items) = get_graphl_attr(&variant.attrs) {
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);
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);
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);
continue;
}
match item {
&NestedMetaItem::MetaItem(MetaItem::Word(ref ident)) => {
NestedMeta::Meta(Meta::Word(ref ident)) => {
if ident == "default" {
res.default = true;
continue;
@ -92,16 +102,16 @@ impl ObjFieldAttrs {
}
pub fn impl_input_object(ast: &syn::DeriveInput) -> Tokens {
let fields = match ast.body {
Body::Struct(ref data) => match data {
&VariantData::Struct(ref fields) => fields,
let fields = match ast.data {
Data::Struct(ref data) => match data.fields {
Fields::Named(ref named) => named.named.iter().collect::<Vec<_>>(),
_ => {
panic!(
"#[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");
}
};
@ -146,8 +156,17 @@ pub fn impl_input_object(ast: &syn::DeriveInput) -> Tokens {
Some(quote! { Default::default() })
} else {
match field_attrs.default_expr {
Some(ref def) => match syn::parse_token_trees(def) {
Ok(t) => Some(quote! { #(#t)* }),
Some(ref def) => match ::proc_macro::TokenStream::from_str(def) {
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(_) => {
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.
// FIXME: Figure out a better way to do this!

View file

@ -1,5 +1,10 @@
use syn;
use syn::*;
use syn::{
DeriveInput,
Data,
Fields,
Field,
};
use quote::Tokens;
use util::*;
@ -17,11 +22,11 @@ impl ObjAttrs {
// Check attributes for name and description.
if let Some(items) = get_graphl_attr(&input.attrs) {
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);
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);
continue;
}
@ -49,15 +54,15 @@ impl ObjFieldAttrs {
// Check attributes for name and description.
if let Some(items) = get_graphl_attr(&variant.attrs) {
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);
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);
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);
continue;
}
@ -72,14 +77,14 @@ impl ObjFieldAttrs {
}
pub fn impl_object(ast: &syn::DeriveInput) -> Tokens {
let fields = match ast.body {
Body::Struct(ref data) => match data {
&VariantData::Struct(ref fields) => fields,
let fields = match ast.data {
Data::Struct(ref data) => match data.fields {
Fields::Named(ref fields) => fields.named.iter().collect::<Vec<_>>(),
_ => {
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");
}
};

View file

@ -20,24 +20,21 @@ use proc_macro::TokenStream;
#[proc_macro_derive(GraphQLEnum, attributes(graphql))]
pub fn derive_enum(input: TokenStream) -> TokenStream {
let s = input.to_string();
let ast = syn::parse_derive_input(&s).unwrap();
let ast = syn::parse::<syn::DeriveInput>(input).unwrap();
let gen = derive_enum::impl_enum(&ast);
gen.parse().unwrap()
gen.into()
}
#[proc_macro_derive(GraphQLInputObject, attributes(graphql))]
pub fn derive_input_object(input: TokenStream) -> TokenStream {
let s = input.to_string();
let ast = syn::parse_derive_input(&s).unwrap();
let ast = syn::parse::<syn::DeriveInput>(input).unwrap();
let gen = derive_input_object::impl_input_object(&ast);
gen.parse().unwrap()
gen.into()
}
#[proc_macro_derive(GraphQLObject, attributes(graphql))]
pub fn derive_object(input: TokenStream) -> TokenStream {
let s = input.to_string();
let ast = syn::parse_derive_input(&s).unwrap();
let ast = syn::parse::<syn::DeriveInput>(input).unwrap();
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 {
match attr.value {
MetaItem::List(ref attr_name, ref items) => if attr_name == "graphql" {
return Some(items);
match attr.interpret_meta() {
Some(Meta::List(ref list)) if list.ident == "graphql" => {
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
}
pub fn keyed_item_value(item: &NestedMetaItem, name: &str, must_be_string: bool) -> Option<String> {
let item = match item {
&NestedMetaItem::MetaItem(ref item) => item,
_ => {
return None;
}
};
let lit = match item {
&MetaItem::NameValue(ref ident, ref lit) => if ident == name {
lit
} else {
return 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
pub fn keyed_item_value(item: &NestedMeta, name: &str, must_be_string: bool) -> Option<String> {
match item {
&NestedMeta::Meta(Meta::NameValue(ref nameval)) if nameval.ident == name => {
match &nameval.lit {
&Lit::Str(ref strlit) => {
Some(strlit.value())
},
_ => if must_be_string {
panic!(format!(
"Invalid format for attribute \"{:?}\": expected a string",
item
));
} else {
None
},
}
},
_ => None,
}
}