Upgrade to syn 1.0

This commit is contained in:
konstin 2019-08-11 14:16:02 +02:00
parent be22d9e5bb
commit 39f151c3bd
12 changed files with 185 additions and 199 deletions

View File

@ -19,25 +19,25 @@ travis-ci = { repository = "PyO3/pyo3", branch = "master" }
appveyor = { repository = "fafhrd91/pyo3" }
[dependencies]
libc = "0.2.54"
spin = "0.5.0"
num-traits = "0.2.6"
libc = "0.2.62"
spin = "0.5.1"
num-traits = "0.2.8"
pyo3cls = { path = "pyo3cls", version = "=0.7.0" }
num-complex = { version = "0.2.1", optional = true }
inventory = "0.1.3"
indoc = "0.3.3"
unindent = "0.1.3"
paste = "0.1.5"
num-complex = { version = "0.2.3", optional = true }
inventory = "0.1.4"
indoc = "0.3.4"
unindent = "0.1.4"
paste = "0.1.6"
[dev-dependencies]
assert_approx_eq = "1.1.0"
trybuild = "1.0"
trybuild = "1.0.11"
[build-dependencies]
regex = "1.1.6"
regex = "1.2.1"
version_check = "0.9.1"
serde = { version = "1.0.91", features = ["derive"] }
serde_json = "1.0.39"
serde = { version = "1.0.99", features = ["derive"] }
serde_json = "1.0.40"
[features]
default = []

View File

@ -11,9 +11,9 @@ license = "Apache-2.0"
edition = "2018"
[dependencies]
quote = "0.6.12"
proc-macro2 = "0.4.30"
syn = { version = "0.15.34", features = ["full", "extra-traits"] }
quote = "1"
proc-macro2 = "1"
syn = { version = "1", features = ["full", "extra-traits"] }
[features]
unsound-subclass = []

View File

@ -2,6 +2,7 @@
use crate::utils::print_err;
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::Token;
// TODO:
// Add lifetime support for args with Rptr
@ -70,7 +71,7 @@ impl PartialEq<str> for MethodProto {
pub fn impl_method_proto(
cls: &syn::Type,
sig: &mut syn::MethodSig,
sig: &mut syn::Signature,
meth: &MethodProto,
) -> TokenStream {
if let MethodProto::Free { proto, .. } = meth {
@ -80,7 +81,7 @@ pub fn impl_method_proto(
};
}
let ty = &*if let syn::ReturnType::Type(_, ref ty) = sig.decl.output {
let ty = &*if let syn::ReturnType::Type(_, ref ty) = sig.output {
ty.clone()
} else {
panic!("fn return type is not supported")
@ -95,7 +96,7 @@ pub fn impl_method_proto(
let tmp: syn::ItemFn = syn::parse_quote! {
fn test(&self) -> <#cls as #p<'p>>::Result {}
};
sig.decl.output = tmp.decl.output;
sig.output = tmp.sig.output;
modify_self_ty(sig);
if pyres {
@ -119,7 +120,7 @@ pub fn impl_method_proto(
pyres,
proto,
} => {
if sig.decl.inputs.len() <= 1 {
if sig.inputs.len() <= 1 {
println!("Not enough arguments for {}", name);
return TokenStream::new();
}
@ -164,7 +165,7 @@ pub fn impl_method_proto(
pyres,
proto,
} => {
if sig.decl.inputs.len() <= 1 {
if sig.inputs.len() <= 1 {
print_err(format!("Not enough arguments {}", name), quote!(sig));
return TokenStream::new();
}
@ -213,7 +214,7 @@ pub fn impl_method_proto(
pyres,
proto,
} => {
if sig.decl.inputs.len() <= 2 {
if sig.inputs.len() <= 2 {
print_err(format!("Not enough arguments {}", name), quote!(sig));
return TokenStream::new();
}
@ -266,7 +267,7 @@ pub fn impl_method_proto(
pyres,
proto,
} => {
if sig.decl.inputs.len() <= 2 {
if sig.inputs.len() <= 2 {
print_err(format!("Not enough arguments {}", name), quote!(sig));
return TokenStream::new();
}
@ -322,7 +323,7 @@ pub fn impl_method_proto(
arg3,
proto,
} => {
if sig.decl.inputs.len() <= 3 {
if sig.inputs.len() <= 3 {
print_err(format!("Not enough arguments {}", name), quote!(sig));
return TokenStream::new();
}
@ -367,26 +368,26 @@ pub fn impl_method_proto(
}
// TODO: better arg ty detection
fn get_arg_ty(sig: &syn::MethodSig, idx: usize) -> syn::Type {
let mut ty = match sig.decl.inputs[idx] {
syn::FnArg::Captured(ref cap) => {
match cap.ty {
fn get_arg_ty(sig: &syn::Signature, idx: usize) -> syn::Type {
let mut ty = match sig.inputs[idx] {
syn::FnArg::Typed(ref cap) => {
match *cap.ty {
syn::Type::Path(ref ty) => {
// use only last path segment for Option<>
let seg = *ty.path.segments.last().unwrap().value();
let seg = ty.path.segments.last().unwrap().clone();
if seg.ident == "Option" {
if let syn::PathArguments::AngleBracketed(ref data) = seg.arguments {
if let Some(pair) = data.args.last() {
match pair.value() {
match pair {
syn::GenericArgument::Type(ref ty) => return ty.clone(),
_ => panic!("Option only accepted for concrete types"),
}
};
}
}
cap.ty.clone()
*cap.ty.clone()
}
_ => cap.ty.clone(),
_ => *cap.ty.clone(),
}
}
_ => panic!("fn arg type is not supported"),
@ -408,9 +409,9 @@ fn get_res_success(ty: &syn::Type) -> (TokenStream, syn::GenericArgument) {
match ty {
syn::Type::Path(ref typath) => {
if let Some(segment) = typath.path.segments.last() {
match segment.value().ident.to_string().as_str() {
match segment.ident.to_string().as_str() {
// check for PyResult<T>
"PyResult" => match segment.value().arguments {
"PyResult" => match segment.arguments {
syn::PathArguments::AngleBracketed(ref data) => {
result = true;
succ = data.args[0].clone();
@ -420,10 +421,10 @@ fn get_res_success(ty: &syn::Type) -> (TokenStream, syn::GenericArgument) {
data.args[0]
{
if let Some(segment) = typath.path.segments.last() {
if "Option" == segment.value().ident.to_string().as_str() {
if "Option" == segment.ident.to_string().as_str() {
// get T from Option<T>
if let syn::PathArguments::AngleBracketed(ref data) =
segment.value().arguments
segment.arguments
{
result = false;
succ = data.args[0].clone();
@ -436,7 +437,7 @@ fn get_res_success(ty: &syn::Type) -> (TokenStream, syn::GenericArgument) {
},
_ => panic!(
"fn result type has to be PyResult or (), got {:?}",
segment.value().ident
segment.ident
),
}
} else {
@ -456,50 +457,55 @@ fn get_res_success(ty: &syn::Type) -> (TokenStream, syn::GenericArgument) {
(res, succ)
}
fn extract_decl(spec: syn::Item) -> syn::FnDecl {
fn extract_decl(spec: syn::Item) -> syn::Signature {
match spec {
syn::Item::Fn(f) => *f.decl,
syn::Item::Fn(f) => f.sig,
_ => panic!(),
}
}
// modify method signature
fn modify_arg_ty(sig: &mut syn::MethodSig, idx: usize, decl1: &syn::FnDecl, decl2: &syn::FnDecl) {
let arg = sig.decl.inputs[idx].clone();
fn modify_arg_ty(
sig: &mut syn::Signature,
idx: usize,
decl1: &syn::Signature,
decl2: &syn::Signature,
) {
let arg = sig.inputs[idx].clone();
match arg {
syn::FnArg::Captured(ref cap) => match cap.ty {
syn::FnArg::Typed(ref cap) => match *cap.ty {
syn::Type::Path(ref typath) => {
let seg = *typath.path.segments.last().unwrap().value();
let seg = typath.path.segments.last().unwrap().clone();
if seg.ident == "Option" {
sig.decl.inputs[idx] = fix_name(&cap.pat, &decl2.inputs[idx]);
sig.inputs[idx] = fix_name(&cap.pat, &decl2.inputs[idx]);
} else {
sig.decl.inputs[idx] = fix_name(&cap.pat, &decl1.inputs[idx]);
sig.inputs[idx] = fix_name(&cap.pat, &decl1.inputs[idx]);
}
}
_ => {
sig.decl.inputs[idx] = fix_name(&cap.pat, &decl1.inputs[idx]);
sig.inputs[idx] = fix_name(&cap.pat, &decl1.inputs[idx]);
}
},
_ => panic!("not supported"),
}
sig.decl.output = decl1.output.clone();
sig.output = decl1.output.clone();
}
fn modify_self_ty(sig: &mut syn::MethodSig) {
match sig.decl.inputs[0] {
syn::FnArg::SelfRef(ref mut slf) => {
slf.lifetime = Some(syn::parse_quote! {'p});
fn modify_self_ty(sig: &mut syn::Signature) {
match sig.inputs[0] {
syn::FnArg::Receiver(ref mut slf) => {
slf.reference = Some((Token![&](Span::call_site()), syn::parse_quote! {'p}));
}
syn::FnArg::Captured(_) => {}
_ => panic!("not supported"),
syn::FnArg::Typed(_) => {}
}
}
fn fix_name(pat: &syn::Pat, arg: &syn::FnArg) -> syn::FnArg {
if let syn::FnArg::Captured(ref cap) = arg {
syn::FnArg::Captured(syn::ArgCaptured {
pat: pat.clone(),
if let syn::FnArg::Typed(ref cap) = arg {
syn::FnArg::Typed(syn::PatType {
attrs: cap.attrs.clone(),
pat: Box::new(pat.clone()),
colon_token: cap.colon_token,
ty: cap.ty.clone(),
})

View File

@ -49,22 +49,19 @@ impl<'a> FnSpec<'a> {
/// Parser function signature and function attributes
pub fn parse(
name: &'a syn::Ident,
sig: &'a syn::MethodSig,
sig: &'a syn::Signature,
meth_attrs: &'a mut Vec<syn::Attribute>,
) -> syn::Result<FnSpec<'a>> {
let (mut fn_type, fn_attrs) = parse_attributes(meth_attrs)?;
let mut has_self = false;
let mut arguments = Vec::new();
for input in sig.decl.inputs.iter() {
for input in sig.inputs.iter() {
match input {
syn::FnArg::SelfRef(_) => {
syn::FnArg::Receiver(_) => {
has_self = true;
}
syn::FnArg::SelfValue(_) => {
has_self = true;
}
syn::FnArg::Captured(syn::ArgCaptured {
syn::FnArg::Typed(syn::PatType {
ref pat, ref ty, ..
}) => {
// skip first argument (cls)
@ -73,7 +70,7 @@ impl<'a> FnSpec<'a> {
continue;
}
let (ident, by_ref, mutability) = match pat {
let (ident, by_ref, mutability) = match **pat {
syn::Pat::Ident(syn::PatIdent {
ref ident,
ref by_ref,
@ -99,16 +96,10 @@ impl<'a> FnSpec<'a> {
reference: is_ref(name, ty),
});
}
syn::FnArg::Ignored(_) => {
return Err(syn::Error::new_spanned(name, "ignored argument"));
}
syn::FnArg::Inferred(_) => {
return Err(syn::Error::new_spanned(name, "inferred argument"));
}
}
}
let ty = get_return_info(&sig.decl.output);
let ty = get_return_info(&sig.output);
if fn_type == FnType::Fn && !has_self {
if arguments.is_empty() {
@ -131,8 +122,8 @@ impl<'a> FnSpec<'a> {
pub fn is_args(&self, name: &syn::Ident) -> bool {
for s in self.attrs.iter() {
if let Argument::VarArgs(ref ident) = s {
return name == ident;
if let Argument::VarArgs(ref path) = s {
return path.is_ident(name);
}
}
false
@ -151,8 +142,8 @@ impl<'a> FnSpec<'a> {
pub fn is_kwargs(&self, name: &syn::Ident) -> bool {
for s in self.attrs.iter() {
if let Argument::KeywordArgs(ref ident) = s {
return name == ident;
if let Argument::KeywordArgs(ref path) = s {
return path.is_ident(name);
}
}
false
@ -170,16 +161,16 @@ impl<'a> FnSpec<'a> {
pub fn default_value(&self, name: &syn::Ident) -> Option<TokenStream> {
for s in self.attrs.iter() {
match *s {
Argument::Arg(ref ident, ref opt) => {
if ident == name {
Argument::Arg(ref path, ref opt) => {
if path.is_ident(name) {
if let Some(ref val) = opt {
let i: syn::Expr = syn::parse_str(&val).unwrap();
return Some(i.into_token_stream());
}
}
}
Argument::Kwarg(ref ident, ref opt) => {
if ident == name {
Argument::Kwarg(ref path, ref opt) => {
if path.is_ident(name) {
let i: syn::Expr = syn::parse_str(&opt).unwrap();
return Some(quote!(#i));
}
@ -192,8 +183,8 @@ impl<'a> FnSpec<'a> {
pub fn is_kw_only(&self, name: &syn::Ident) -> bool {
for s in self.attrs.iter() {
if let Argument::Kwarg(ref ident, _) = s {
if ident == name {
if let Argument::Kwarg(ref path, _) = s {
if path.is_ident(name) {
return true;
}
}
@ -207,8 +198,8 @@ pub fn is_ref(name: &syn::Ident, ty: &syn::Type) -> bool {
syn::Type::Reference(_) => return true,
syn::Type::Path(syn::TypePath { ref path, .. }) => {
if let Some(segment) = path.segments.last() {
if "Option" == segment.value().ident.to_string().as_str() {
match segment.value().arguments {
if "Option" == segment.ident.to_string().as_str() {
match segment.arguments {
syn::PathArguments::AngleBracketed(ref params) => {
if params.args.len() != 1 {
panic!("argument type is not supported by python method: {:?} ({:?}) {:?}",
@ -248,8 +239,8 @@ pub fn check_arg_ty_and_optional<'a>(
//}
if let Some(segment) = path.segments.last() {
match segment.value().ident.to_string().as_str() {
"Option" => match segment.value().arguments {
match segment.ident.to_string().as_str() {
"Option" => match segment.arguments {
syn::PathArguments::AngleBracketed(ref params) => {
if params.args.len() != 1 {
panic!("argument type is not supported by python method: {:?} ({:?}) {:?}",
@ -294,40 +285,46 @@ fn parse_attributes(attrs: &mut Vec<syn::Attribute>) -> syn::Result<(FnType, Vec
let mut res: Option<FnType> = None;
for attr in attrs.iter() {
match attr.interpret_meta().unwrap() {
syn::Meta::Word(ref name) => match name.to_string().as_ref() {
"new" | "__new__" => res = Some(FnType::FnNew),
"init" | "__init__" => res = Some(FnType::FnInit),
"call" | "__call__" => res = Some(FnType::FnCall),
"classmethod" => res = Some(FnType::FnClass),
"staticmethod" => res = Some(FnType::FnStatic),
"setter" | "getter" => {
match attr.parse_meta().unwrap() {
syn::Meta::Path(ref name) => {
if name.is_ident("new") || name.is_ident("__new__") {
res = Some(FnType::FnNew)
} else if name.is_ident("init") || name.is_ident("__init__") {
res = Some(FnType::FnInit)
} else if name.is_ident("call") || name.is_ident("__call__") {
res = Some(FnType::FnCall)
} else if name.is_ident("classmethod") {
res = Some(FnType::FnClass)
} else if name.is_ident("staticmethod") {
res = Some(FnType::FnStatic)
} else if name.is_ident("setter") || name.is_ident("getter") {
if let syn::AttrStyle::Inner(_) = attr.style {
panic!(
"Inner style attribute is not
supported for setter and getter"
);
panic!("Inner style attribute is not supported for setter and getter");
}
if res != None {
panic!("setter/getter attribute can not be used mutiple times");
}
if name == "setter" {
if name.is_ident("setter") {
res = Some(FnType::Setter(None))
} else {
res = Some(FnType::Getter(None))
}
} else {
new_attrs.push(attr.clone())
}
_ => new_attrs.push(attr.clone()),
},
}
syn::Meta::List(syn::MetaList {
ref ident,
ref path,
ref nested,
..
}) => match ident.to_string().as_str() {
"new" => res = Some(FnType::FnNew),
"init" => res = Some(FnType::FnInit),
"call" => res = Some(FnType::FnCall),
"setter" | "getter" => {
}) => {
if path.is_ident("new") {
res = Some(FnType::FnNew)
} else if path.is_ident("init") {
res = Some(FnType::FnInit)
} else if path.is_ident("call") {
res = Some(FnType::FnCall)
} else if path.is_ident("setter") || path.is_ident("getter") {
if let syn::AttrStyle::Inner(_) = attr.style {
panic!(
"Inner style attribute is not
@ -340,17 +337,17 @@ fn parse_attributes(attrs: &mut Vec<syn::Attribute>) -> syn::Result<(FnType, Vec
if nested.len() != 1 {
panic!("setter/getter requires one value");
}
match nested.first().unwrap().value() {
syn::NestedMeta::Meta(syn::Meta::Word(ref w)) => {
if ident == "setter" {
res = Some(FnType::Setter(Some(w.to_string())))
match nested.first().unwrap() {
syn::NestedMeta::Meta(syn::Meta::Path(ref w)) => {
if path.is_ident("setter") {
res = Some(FnType::Setter(Some(w.segments[0].ident.to_string())))
} else {
res = Some(FnType::Getter(Some(w.to_string())))
res = Some(FnType::Getter(Some(w.segments[0].ident.to_string())))
}
}
syn::NestedMeta::Literal(ref lit) => match *lit {
syn::NestedMeta::Lit(ref lit) => match *lit {
syn::Lit::Str(ref s) => {
if ident == "setter" {
if path.is_ident("setter") {
res = Some(FnType::Setter(Some(s.value())))
} else {
res = Some(FnType::Getter(Some(s.value())))
@ -361,16 +358,16 @@ fn parse_attributes(attrs: &mut Vec<syn::Attribute>) -> syn::Result<(FnType, Vec
}
},
_ => {
println!("cannot parse {:?} attribute: {:?}", ident, nested);
println!("cannot parse {:?} attribute: {:?}", path, nested);
}
}
}
"args" => {
} else if path.is_ident("args") {
let attrs = PyFunctionAttr::from_meta(nested)?;
spec.extend(attrs.arguments)
} else {
new_attrs.push(attr.clone())
}
_ => new_attrs.push(attr.clone()),
},
}
syn::Meta::NameValue(_) => new_attrs.push(attr.clone()),
}
}

View File

@ -8,8 +8,7 @@ use crate::pymethod;
use crate::pymethod::get_arg_names;
use crate::utils;
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::ext::IdentExt;
use quote::{format_ident, quote};
use syn::Ident;
/// Generates the function that is called by the python interpreter to initialize the native
@ -38,7 +37,7 @@ pub fn process_functions_in_module(func: &mut syn::ItemFn) {
extract_pyfn_attrs(&mut func.attrs)
{
let function_to_python = add_fn_to_module(func, &python_name, pyfn_attrs);
let function_wrapper_ident = function_wrapper_ident(&func.ident);
let function_wrapper_ident = function_wrapper_ident(&func.sig.ident);
let item: syn::ItemFn = syn::parse_quote! {
fn block_wrapper() {
#function_to_python
@ -57,9 +56,9 @@ pub fn process_functions_in_module(func: &mut syn::ItemFn) {
/// Transforms a rust fn arg parsed with syn into a method::FnArg
fn wrap_fn_argument<'a>(input: &'a syn::FnArg, name: &'a Ident) -> Option<method::FnArg<'a>> {
match input {
syn::FnArg::SelfRef(_) | &syn::FnArg::SelfValue(_) => None,
syn::FnArg::Captured(ref cap) => {
let (mutability, by_ref, ident) = match cap.pat {
syn::FnArg::Receiver(_) => None,
syn::FnArg::Typed(ref cap) => {
let (mutability, by_ref, ident) = match *cap.pat {
syn::Pat::Ident(ref patid) => (&patid.mutability, &patid.by_ref, &patid.ident),
_ => panic!("unsupported argument: {:?}", cap.pat),
};
@ -76,15 +75,13 @@ fn wrap_fn_argument<'a>(input: &'a syn::FnArg, name: &'a Ident) -> Option<method
reference: method::is_ref(&name, &cap.ty),
})
}
syn::FnArg::Ignored(_) => panic!("ignored argument: {:?}", name),
syn::FnArg::Inferred(_) => panic!("inferred argument: {:?}", name),
}
}
/// Extracts the data from the #[pyfn(...)] attribute of a function
fn extract_pyfn_attrs(
attrs: &mut Vec<syn::Attribute>,
) -> Option<(Ident, Ident, Vec<pyfunction::Argument>)> {
) -> Option<(syn::Path, Ident, Vec<pyfunction::Argument>)> {
let mut new_attrs = Vec::new();
let mut fnname = None;
let mut modname = None;
@ -92,19 +89,19 @@ fn extract_pyfn_attrs(
for attr in attrs.iter() {
match attr.parse_meta() {
Ok(syn::Meta::List(ref list)) if list.ident == "pyfn" => {
Ok(syn::Meta::List(ref list)) if list.path.is_ident("pyfn") => {
let meta: Vec<_> = list.nested.iter().cloned().collect();
if meta.len() >= 2 {
// read module name
match meta[0] {
syn::NestedMeta::Meta(syn::Meta::Word(ref ident)) => {
modname = Some(ident.clone())
syn::NestedMeta::Meta(syn::Meta::Path(ref path)) => {
modname = Some(path.clone())
}
_ => panic!("The first parameter of pyfn must be a MetaItem"),
}
// read Python function name
match meta[1] {
syn::NestedMeta::Literal(syn::Lit::Str(ref lits)) => {
syn::NestedMeta::Lit(syn::Lit::Str(ref lits)) => {
fnname = Some(syn::Ident::new(&lits.value(), lits.span()));
}
_ => panic!("The second parameter of pyfn must be a Literal"),
@ -130,10 +127,7 @@ fn extract_pyfn_attrs(
/// Coordinates the naming of a the add-function-to-python-module function
fn function_wrapper_ident(name: &Ident) -> Ident {
// Make sure this ident matches the one of wrap_pyfunction
Ident::new(
&format!("__pyo3_get_function_{}", name.unraw().to_string()),
Span::call_site(),
)
format_ident!("__pyo3_get_function_{}", name)
}
/// Generates python wrapper over a function that allows adding it to a python module as a python
@ -145,13 +139,13 @@ pub fn add_fn_to_module(
) -> TokenStream {
let mut arguments = Vec::new();
for input in func.decl.inputs.iter() {
if let Some(fn_arg) = wrap_fn_argument(input, &func.ident) {
for input in func.sig.inputs.iter() {
if let Some(fn_arg) = wrap_fn_argument(input, &func.sig.ident) {
arguments.push(fn_arg);
}
}
let ty = method::get_return_info(&func.decl.output);
let ty = method::get_return_info(&func.sig.output);
let spec = method::FnSpec {
tp: method::FnType::Fn,
@ -160,9 +154,9 @@ pub fn add_fn_to_module(
output: ty,
};
let function_wrapper_ident = function_wrapper_ident(&func.ident);
let function_wrapper_ident = function_wrapper_ident(&func.sig.ident);
let wrapper = function_c_wrapper(&func.ident, &spec);
let wrapper = function_c_wrapper(&func.sig.ident, &spec);
let doc = utils::get_doc(&func.attrs, true);
let tokens = quote! {

View File

@ -59,7 +59,7 @@ impl PyClassArgs {
fn add_assign(&mut self, assign: &syn::ExprAssign) -> syn::Result<()> {
let key = match *assign.left {
syn::Expr::Path(ref exp) if exp.path.segments.len() == 1 => {
exp.path.segments.first().unwrap().value().ident.to_string()
exp.path.segments.first().unwrap().ident.to_string()
}
_ => {
return Err(syn::Error::new_spanned(assign, "could not parse argument"));
@ -123,7 +123,7 @@ impl PyClassArgs {
/// Match a key/value flag
fn add_path(&mut self, exp: &syn::ExprPath) -> syn::Result<()> {
let flag = exp.path.segments.first().unwrap().value().ident.to_string();
let flag = exp.path.segments.first().unwrap().ident.to_string();
let path = match flag.as_str() {
"gc" => {
parse_quote! {pyo3::type_object::PY_TYPE_FLAG_GC}
@ -184,28 +184,23 @@ fn parse_descriptors(item: &mut syn::Field) -> syn::Result<Vec<FnType>> {
let mut new_attrs = Vec::new();
for attr in item.attrs.iter() {
if let Ok(syn::Meta::List(ref list)) = attr.parse_meta() {
match list.ident.to_string().as_str() {
"pyo3" => {
for meta in list.nested.iter() {
if let syn::NestedMeta::Meta(ref metaitem) = meta {
match metaitem.name().to_string().as_str() {
"get" => {
descs.push(FnType::Getter(None));
}
"set" => {
descs.push(FnType::Setter(None));
}
_ => {
return Err(syn::Error::new_spanned(
metaitem,
"Only get and set are supported",
));
}
}
if list.path.is_ident("pyo3") {
for meta in list.nested.iter() {
if let syn::NestedMeta::Meta(ref metaitem) = meta {
if metaitem.path().is_ident("get") {
descs.push(FnType::Getter(None));
} else if metaitem.path().is_ident("set") {
descs.push(FnType::Setter(None));
} else {
return Err(syn::Error::new_spanned(
metaitem,
"Only get and set are supported",
));
}
}
}
_ => new_attrs.push(attr.clone()),
} else {
new_attrs.push(attr.clone())
}
} else {
new_attrs.push(attr.clone());

View File

@ -2,15 +2,15 @@
use syn::parse::ParseBuffer;
use syn::punctuated::Punctuated;
use syn::{Ident, NestedMeta};
use syn::{NestedMeta, Path};
#[derive(Debug, Clone, PartialEq)]
pub enum Argument {
VarArgsSeparator,
VarArgs(syn::Ident),
KeywordArgs(syn::Ident),
Arg(syn::Ident, Option<String>),
Kwarg(syn::Ident, String),
VarArgs(syn::Path),
KeywordArgs(syn::Path),
Arg(syn::Path, Option<String>),
Kwarg(syn::Path, String),
}
/// The attributes of the pyfunction macro
@ -41,11 +41,11 @@ impl PyFunctionAttr {
pub fn add_item(&mut self, item: &NestedMeta) -> syn::Result<()> {
match item {
NestedMeta::Meta(syn::Meta::Word(ref ident)) => self.add_work(item, ident)?,
NestedMeta::Meta(syn::Meta::Path(ref ident)) => self.add_work(item, ident)?,
NestedMeta::Meta(syn::Meta::NameValue(ref nv)) => {
self.add_name_value(item, nv)?;
}
NestedMeta::Literal(ref lit) => {
NestedMeta::Lit(ref lit) => {
self.add_literal(item, lit)?;
}
_ => {
@ -89,7 +89,7 @@ impl PyFunctionAttr {
Ok(())
}
fn add_work(&mut self, item: &NestedMeta, ident: &Ident) -> syn::Result<()> {
fn add_work(&mut self, item: &NestedMeta, path: &Path) -> syn::Result<()> {
// self.arguments in form somename
if self.has_kwargs {
return Err(syn::Error::new_spanned(
@ -103,7 +103,7 @@ impl PyFunctionAttr {
"syntax error, argument is not allowed after keyword argument",
));
}
self.arguments.push(Argument::Arg(ident.clone(), None));
self.arguments.push(Argument::Arg(path.clone(), None));
Ok(())
}
@ -122,7 +122,7 @@ impl PyFunctionAttr {
return Err(syn::Error::new_spanned(item, "*(var args) is defined"));
}
self.has_varargs = true;
self.arguments.push(Argument::VarArgs(nv.ident.clone()));
self.arguments.push(Argument::VarArgs(nv.path.clone()));
} else if litstr.value() == "**" {
// kwargs="**"
if self.has_kwargs {
@ -132,10 +132,10 @@ impl PyFunctionAttr {
));
}
self.has_kwargs = true;
self.arguments.push(Argument::KeywordArgs(nv.ident.clone()));
self.arguments.push(Argument::KeywordArgs(nv.path.clone()));
} else if self.has_varargs {
self.arguments
.push(Argument::Kwarg(nv.ident.clone(), litstr.value().clone()))
.push(Argument::Kwarg(nv.path.clone(), litstr.value()))
} else {
if self.has_kwargs {
return Err(syn::Error::new_spanned(
@ -144,18 +144,14 @@ impl PyFunctionAttr {
));
}
self.has_kw = true;
self.arguments.push(Argument::Arg(
nv.ident.clone(),
Some(litstr.value().clone()),
))
self.arguments
.push(Argument::Arg(nv.path.clone(), Some(litstr.value())))
}
}
syn::Lit::Int(ref litint) => {
if self.has_varargs {
self.arguments.push(Argument::Kwarg(
nv.ident.clone(),
format!("{}", litint.value()),
));
self.arguments
.push(Argument::Kwarg(nv.path.clone(), format!("{}", litint)));
} else {
if self.has_kwargs {
return Err(syn::Error::new_spanned(
@ -164,16 +160,14 @@ impl PyFunctionAttr {
));
}
self.has_kw = true;
self.arguments.push(Argument::Arg(
nv.ident.clone(),
Some(format!("{}", litint.value())),
));
self.arguments
.push(Argument::Arg(nv.path.clone(), Some(format!("{}", litint))));
}
}
syn::Lit::Bool(ref litb) => {
if self.has_varargs {
self.arguments
.push(Argument::Kwarg(nv.ident.clone(), format!("{}", litb.value)));
.push(Argument::Kwarg(nv.path.clone(), format!("{}", litb.value)));
} else {
if self.has_kwargs {
return Err(syn::Error::new_spanned(
@ -183,7 +177,7 @@ impl PyFunctionAttr {
}
self.has_kw = true;
self.arguments.push(Argument::Arg(
nv.ident.clone(),
nv.path.clone(),
Some(format!("{}", litb.value)),
));
}

View File

@ -7,7 +7,7 @@ use quote::quote;
pub fn gen_py_method(
cls: &syn::Type,
name: &syn::Ident,
sig: &mut syn::MethodSig,
sig: &mut syn::Signature,
meth_attrs: &mut Vec<syn::Attribute>,
) -> syn::Result<TokenStream> {
check_generic(name, sig)?;
@ -49,14 +49,14 @@ pub fn gen_py_method(
})
}
fn check_generic(name: &syn::Ident, sig: &syn::MethodSig) -> syn::Result<()> {
fn check_generic(name: &syn::Ident, sig: &syn::Signature) -> syn::Result<()> {
let err_msg = |typ| {
format!(
"A Python method can't have a generic {} parameter: {}",
name, typ
)
};
for param in &sig.decl.generics.params {
for param in &sig.generics.params {
match param {
syn::GenericParam::Lifetime(_) => {}
syn::GenericParam::Type(_) => {

View File

@ -12,7 +12,7 @@ use quote::ToTokens;
pub fn build_py_proto(ast: &mut syn::ItemImpl) -> syn::Result<TokenStream> {
if let Some((_, ref mut path, _)) = ast.trait_ {
let proto = if let Some(ref mut segment) = path.segments.last() {
match segment.value().ident.to_string().as_str() {
match segment.ident.to_string().as_str() {
"PyObjectProtocol" => &defs::OBJECT,
"PyAsyncProtocol" => &defs::ASYNC,
"PyMappingProtocol" => &defs::MAPPING,

View File

@ -14,7 +14,7 @@ pub fn if_type_is_python(ty: &syn::Type) -> bool {
.path
.segments
.last()
.map(|seg| seg.value().ident == "Python")
.map(|seg| seg.ident == "Python")
.unwrap_or(false),
_ => false,
}
@ -28,8 +28,8 @@ pub fn get_doc(attrs: &[syn::Attribute], null_terminated: bool) -> syn::Lit {
// let mut span = None;
for attr in attrs.iter() {
if let Some(syn::Meta::NameValue(ref metanv)) = attr.interpret_meta() {
if metanv.ident == "doc" {
if let Ok(syn::Meta::NameValue(ref metanv)) = attr.parse_meta() {
if metanv.path.is_ident("doc") {
// span = Some(metanv.span());
if let syn::Lit::Str(ref litstr) = metanv.lit {
let d = litstr.value();

View File

@ -14,9 +14,9 @@ edition = "2018"
proc-macro = true
[dependencies]
quote= "0.6.12"
proc-macro2 = "0.4.30"
syn = { version = "0.15.34", features = ["full", "extra-traits"] }
quote = "1"
proc-macro2 = "1"
syn = { version = "1", features = ["full", "extra-traits"] }
pyo3-derive-backend = { path = "../pyo3-derive-backend", version = "=0.7.0" }
[features]

View File

@ -20,14 +20,14 @@ pub fn pymodule(attr: TokenStream, input: TokenStream) -> TokenStream {
let mut ast = parse_macro_input!(input as syn::ItemFn);
let modname = if attr.is_empty() {
ast.ident.clone()
ast.sig.ident.clone()
} else {
parse_macro_input!(attr as syn::Ident)
};
process_functions_in_module(&mut ast);
let expanded = py_init(&ast.ident, &modname, get_doc(&ast.attrs, false));
let expanded = py_init(&ast.sig.ident, &modname, get_doc(&ast.attrs, false));
quote!(
#ast
@ -78,7 +78,7 @@ pub fn pyfunction(attr: TokenStream, input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as syn::ItemFn);
let args = parse_macro_input!(attr as PyFunctionAttr);
let python_name = syn::Ident::new(&ast.ident.unraw().to_string(), Span::call_site());
let python_name = syn::Ident::new(&ast.sig.ident.unraw().to_string(), Span::call_site());
let expanded = add_fn_to_module(&ast, &python_name, args.arguments);
quote!(