Upgrade to syn 1.0
This commit is contained in:
parent
be22d9e5bb
commit
39f151c3bd
24
Cargo.toml
24
Cargo.toml
|
@ -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 = []
|
||||
|
|
|
@ -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 = []
|
||||
|
|
|
@ -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(),
|
||||
})
|
||||
|
|
|
@ -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()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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! {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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)),
|
||||
));
|
||||
}
|
||||
|
|
|
@ -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(_) => {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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!(
|
||||
|
|
Loading…
Reference in a new issue